Merge the other docs into TADM, it's all the same content anyway

This commit is contained in:
Joseph Ferano 2023-01-23 22:19:48 +07:00
parent 415c6bc392
commit e3094b7fb0
3 changed files with 149 additions and 220 deletions

View File

@ -1,71 +0,0 @@
#+TITLE: Random Data Structures
#+AUTHOR: Joseph Ferano
#+OPTIONS: ^:{}
** Stack
*** C
#+begin_src C :includes stdlib.h stdio.h stdbool.h
typedef struct Node {
struct Node* next;
/* void *data; */
int data;
} Node;
typedef struct Stack {
Node* top;
int length;
} Stack;
/* void stack_create(void* data) { */
Stack *stack_create(int data) {
Stack *stack = malloc(sizeof(Stack));
Node *node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
stack->top = node;
stack->length = 1;
return stack;
}
int stack_pop(Stack *stack) {
Node *top = stack->top;
Node *next = top->next;
if (stack->length > 0 && next != NULL) {
stack->top = next;
stack->length--;
int value = top->data;
free(top);
return value;
} else {
// A better API design would be to return a bool and the int as a pointer
// Although once we switch away from int and use void pointers, might not be needed
return -1;
}
}
/* void stack_push(Stack *stack, void *data) { */
void stack_push(Stack *stack, int data) {
Node *node = malloc(sizeof(Node));
Node *top = stack->top;
node->data = data;
node->next = top;
stack->top = node;
stack->length++;
}
/* void* stack_peak(Stack *stack) { */
int stack_peak(Stack *stack) {
return stack->top->data;
}
void stack_print(Stack *stack) {
Node *current = stack->top;
int i = 0;
while (current != NULL) {
printf("Stack at %d: %d\n", ++i, current->data);
current = current->next;
}
printf("------------------\n");
}
#+end_src

View File

@ -1,138 +0,0 @@
#+TITLE: Notes & Exercises: Grokking Algorithms
#+AUTHOR: Joseph Ferano
#+OPTIONS: ^:{}
* Algorithms from the book
** Recursive sum
*** OCaml
#+begin_src ocaml
let rec sum_rec = function
| [] -> 0
| n::ns -> n + sum_rec ns;;
sum_rec [2;3;4;2;1];;
#+end_src
#+RESULTS:
: 12
#+begin_src ocaml
let sum_rec_tail list =
let rec f acc = function
| [] -> 0
| n::ns -> sum_rec (acc + n) ns
in f 0 list;;
sum_rec [2;3;4;2;1];;
#+end_src
#+RESULTS:
: 12
*** Python
#+begin_src python :results output
def sum_rec(arr):
if not arr:
return 0
else:
return arr[0] + sum_rec(arr[1:])
print(sum_rec([1,2,3]))
#+end_src
#+RESULTS:
: 6
** Binary Search
*** OCaml
#+begin_src ocaml
let binary_search items target =
let rec f low high =
match (high - low) / 2 + low with
| mid when target = items.(mid) -> Some items.(mid)
| mid when target < items.(mid) -> f low mid
| mid when target > items.(mid) -> f mid high
| _ -> None
in f 0 (Array.length items);;
binary_search [|1;2;3;4;5|] 3;;
#+end_src
** Selection Sort
Runtime O(n^{2})
*** Python
#+begin_src python
def selection_sort(arr):
sorted_list = []
for i in range(len(arr)):
max = arr[0]
for count, value in enumerate(arr):
if value > max:
max = value
sorted_list.append(max)
arr.remove(max)
return sorted_list
selection_sort([2,1,5,3,4])
#+end_src
*** OCaml
Really reinventing the wheel on this one...
#+begin_src ocaml
let max_element = function
| [] -> invalid_arg "empty list"
| x::xs ->
let rec f acc = function
| [] -> acc
| x::xs -> f (if x > acc then x else acc) xs
in f x xs
let remove item list =
let rec f acc item = function
| [] -> List.rev acc
| x::xs -> if item = x then (List.rev acc) @ xs else f (x::acc) item xs
in f [] item list
let selection_sort list =
let rec f acc = function
| [] -> acc
| xs ->
let m = max xs
in f (m::acc) (remove m xs)
in f [] list
#+end_src
** Quicksort
*** Python
#+begin_src python
import random
def quicksort(arr):
if len(arr) < 2:
return arr
elif len(arr) == 2:
if arr[0] > arr[1]:
temp = arr[1]
arr[1] = arr[0]
arr[0] = temp
return arr
else:
# Pick a random pivot
index = random.randrange(0, len(arr))
pivot = arr.pop(index)
left = [x for x in arr if x <= pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + [pivot] + quicksort(right)
#+end_src

View File

@ -126,6 +126,52 @@ Apparently you can do arithmetic on the Big Oh functions
** 2.5 Efficiency
*** Selection Sort
**** OCaml
Really reinventing the wheel on this one...
#+begin_src ocaml
let max_element = function
| [] -> invalid_arg "empty list"
| x::xs ->
let rec f acc = function
| [] -> acc
| x::xs -> f (if x > acc then x else acc) xs
in f x xs
let remove item list =
let rec f acc item = function
| [] -> List.rev acc
| x::xs -> if item = x then (List.rev acc) @ xs else f (x::acc) item xs
in f [] item list
let selection_sort list =
let rec f acc = function
| [] -> acc
| xs ->
let m = max xs
in f (m::acc) (remove m xs)
in f [] list
#+end_src
**** Python
#+begin_src python
def selection_sort(arr):
sorted_list = []
for i in range(len(arr)):
max = arr[0]
for count, value in enumerate(arr):
if value > max:
max = value
sorted_list.append(max)
arr.remove(max)
return sorted_list
selection_sort([2,1,5,3,4])
#+end_src
**** C
#+begin_src C :includes stdio.h
@ -157,17 +203,6 @@ int nums[9] = { 2, 4, 9, 1, 3, 8, 5, 7, 6 };
selection_sort(nums, 9);
#+end_src
#+RESULTS:
| 2 | 4 | 9 | 1 | 3 | 8 | 5 | 7 | 6 | |
| 1 | 4 | 9 | 2 | 3 | 8 | 5 | 7 | 6 | |
| 1 | 2 | 9 | 4 | 3 | 8 | 5 | 7 | 6 | |
| 1 | 2 | 3 | 4 | 9 | 8 | 5 | 7 | 6 | |
| 1 | 2 | 3 | 4 | 9 | 8 | 5 | 7 | 6 | |
| 1 | 2 | 3 | 4 | 5 | 8 | 9 | 7 | 6 | |
| 1 | 2 | 3 | 4 | 5 | 6 | 9 | 7 | 8 | |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 8 | |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
*** Insertion Sort
**** C
@ -253,6 +288,71 @@ However, pointers require extra space for storing pointer fields
*** Stacks
/(PUSH, /POP/) LIFO, useful in executing recursive algorithms.
#+begin_src C :includes stdlib.h stdio.h stdbool.h
typedef struct Node {
struct Node* next;
/* void *data; */
int data;
} Node;
typedef struct Stack {
Node* top;
int length;
} Stack;
/* void stack_create(void* data) { */
Stack *stack_create(int data) {
Stack *stack = malloc(sizeof(Stack));
Node *node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
stack->top = node;
stack->length = 1;
return stack;
}
int stack_pop(Stack *stack) {
Node *top = stack->top;
Node *next = top->next;
if (stack->length > 0 && next != NULL) {
stack->top = next;
stack->length--;
int value = top->data;
free(top);
return value;
} else {
// A better API design would be to return a bool and the int as a pointer
// Although once we switch away from int and use void pointers, might not be needed
return -1;
}
}
/* void stack_push(Stack *stack, void *data) { */
void stack_push(Stack *stack, int data) {
Node *node = malloc(sizeof(Node));
Node *top = stack->top;
node->data = data;
node->next = top;
stack->top = node;
stack->length++;
}
/* void* stack_peak(Stack *stack) { */
int stack_peak(Stack *stack) {
return stack->top->data;
}
void stack_print(Stack *stack) {
Node *current = stack->top;
int i = 0;
while (current != NULL) {
printf("Stack at %d: %d\n", ++i, current->data);
current = current->next;
}
printf("------------------\n");
}
#+end_src
*** Queues
(/ENQUEUE/, /DEQUEUE/) FIFO, useful for breadth-first searches in graphs.
@ -786,6 +886,29 @@ new arrays to hold the new sorted elements. However, it becomes more challenging
when doing it in place. This algorithm requires 3 pointers to keep track of the
mid point, the iterator, and the high, then finish once mid passes h.
*** Python
#+begin_src python
import random
def quicksort(arr):
if len(arr) < 2:
return arr
elif len(arr) == 2:
if arr[0] > arr[1]:
temp = arr[1]
arr[1] = arr[0]
arr[0] = temp
return arr
else:
# Pick a random pivot
index = random.randrange(0, len(arr))
pivot = arr.pop(index)
left = [x for x in arr if x <= pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + [pivot] + quicksort(right)
#+end_src
** 4.7 Distribution Sort: Bucketing
Two other sorting algorithms function similarly by subdividing the sorting
@ -809,6 +932,21 @@ dealing with lazy sequences, where you search first by A[1], then A[2], A[4],
A[8], A[16], and so forth. You can also use these sorts of bisections on square
root problems, whatever those are.
Here's a simple binary search guessing game;
#+begin_src ocaml
let binary_search items target =
let rec f low high =
match (high - low) / 2 + low with
| mid when target = items.(mid) -> Some items.(mid)
| mid when target < items.(mid) -> f low mid
| mid when target > items.(mid) -> f mid high
| _ -> None
in f 0 (Array.length items);;
binary_search [|1;2;3;4;5|] 3;;
#+end_src
** 4.10 Divide-and-Conquer
Algorithms that use this technique, Mergesort being the classic example, have