Merge the other docs into TADM, it's all the same content anyway
This commit is contained in:
parent
415c6bc392
commit
e3094b7fb0
@ -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
|
|
@ -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
|
|
||||||
|
|
@ -126,6 +126,52 @@ Apparently you can do arithmetic on the Big Oh functions
|
|||||||
** 2.5 Efficiency
|
** 2.5 Efficiency
|
||||||
|
|
||||||
*** Selection Sort
|
*** 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
|
**** C
|
||||||
|
|
||||||
#+begin_src C :includes stdio.h
|
#+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);
|
selection_sort(nums, 9);
|
||||||
#+end_src
|
#+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
|
*** Insertion Sort
|
||||||
**** C
|
**** C
|
||||||
@ -253,6 +288,71 @@ However, pointers require extra space for storing pointer fields
|
|||||||
*** Stacks
|
*** Stacks
|
||||||
/(PUSH, /POP/) LIFO, useful in executing recursive algorithms.
|
/(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
|
*** Queues
|
||||||
(/ENQUEUE/, /DEQUEUE/) FIFO, useful for breadth-first searches in graphs.
|
(/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
|
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.
|
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
|
** 4.7 Distribution Sort: Bucketing
|
||||||
|
|
||||||
Two other sorting algorithms function similarly by subdividing the sorting
|
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
|
A[8], A[16], and so forth. You can also use these sorts of bisections on square
|
||||||
root problems, whatever those are.
|
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
|
** 4.10 Divide-and-Conquer
|
||||||
|
|
||||||
Algorithms that use this technique, Mergesort being the classic example, have
|
Algorithms that use this technique, Mergesort being the classic example, have
|
||||||
|
Loading…
x
Reference in New Issue
Block a user