Chapter 4.1-4.4 with a slightly modified heapsort
This commit is contained in:
parent
3e61af6cac
commit
f9361490d1
@ -1,5 +1,6 @@
|
|||||||
#+TITLE: Notes & Exercises: The Algorith Design Manual
|
#+TITLE: Notes & Exercises: The Algorith Design Manual
|
||||||
#+AUTHOR: Joseph Ferano
|
#+AUTHOR: Joseph Ferano
|
||||||
|
#+STARTUP: overview
|
||||||
#+OPTIONS: ^:{}
|
#+OPTIONS: ^:{}
|
||||||
|
|
||||||
* Chapter 1
|
* Chapter 1
|
||||||
@ -357,3 +358,224 @@ printf("Final: %s\n", str);
|
|||||||
| Before: | My | name | is | Chris |
|
| Before: | My | name | is | Chris |
|
||||||
| After: | sirhC | si | eman | yM |
|
| After: | sirhC | si | eman | yM |
|
||||||
| Final: | Chris | is | name | My |
|
| Final: | Chris | is | name | My |
|
||||||
|
|
||||||
|
* Chapter 4
|
||||||
|
|
||||||
|
** 4.1 Applications of Sorting
|
||||||
|
|
||||||
|
Apparently sorting is a big deal. There are a lot of problems that can be solved by using a sorted
|
||||||
|
list, for example; closest pair, searching, frequency distribution, convex hulls, etc;
|
||||||
|
|
||||||
|
The fastest sorting algorithms are ~n log n~, here is how it scales compared to an algorithm with
|
||||||
|
quadratic growth. Even crazier is that this table divides it by 4 so it's not that ridiculous.
|
||||||
|
|
||||||
|
| n | n^{2}/4 | n lg n |
|
||||||
|
|---------+---------------+-----------|
|
||||||
|
| 10 | 25 | 33 |
|
||||||
|
| 100 | 2,500 | 664 |
|
||||||
|
| 1,000 | 250,000 | 9,965 |
|
||||||
|
| 10,000 | 25,000,000 | 132,877 |
|
||||||
|
| 100,000 | 2,500,000,000 | 1,660,960 |
|
||||||
|
|
||||||
|
Whenever you have an algorithmic problem, don't be afraid to use sorting, because if it results in
|
||||||
|
the ability to then do a linear scan, at worst is becomes ~2n log n~, which in the end is just ~n log n~
|
||||||
|
|
||||||
|
** 4.2 Pragmatics of Sorting
|
||||||
|
|
||||||
|
There are some important things to consider when sorting; the order, keys and their data, equality,
|
||||||
|
and non-numerical data. For resolving these, we would use /comparison functions/. Here is the
|
||||||
|
signature of the C function for quicksort
|
||||||
|
|
||||||
|
#+begin_src C :include stdlib.h
|
||||||
|
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
It takes a comparison function that might look like this;
|
||||||
|
|
||||||
|
#+begin_src C :include stdlib.h
|
||||||
|
int compare(int *i, int *j) {
|
||||||
|
if (*i > *j) return 1;
|
||||||
|
if (*i < *j) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
** 4.3 Heapsort
|
||||||
|
|
||||||
|
An O(n^{2}) sorting algorithm like Selection Sort can be made faster by using the right data structure,
|
||||||
|
in this case either a heap or a balanced binary tree. The first initial construction will take
|
||||||
|
one O(n), but subsequent operations within the loop will now take O(log n) rather than O(n), giving
|
||||||
|
a final complexity of O(n log n).
|
||||||
|
|
||||||
|
*** Heaps
|
||||||
|
|
||||||
|
They can either be min or max heaps and the root node will dominate its children in min-ness or
|
||||||
|
max-ness. It's also different in that it can be implemented in an array and still be reasonably
|
||||||
|
conservative with it's space complexity. However it should be noted that searching isn't efficient
|
||||||
|
because the nodes aren't guaranteed to be ordered, only the relationship between the parent/child.
|
||||||
|
|
||||||
|
Here's the full heap implementation;
|
||||||
|
|
||||||
|
#+begin_src C :includes stdio.h stdlib.h
|
||||||
|
#define PQ_SIZE 256
|
||||||
|
#define item_type int
|
||||||
|
|
||||||
|
struct priority_queue {
|
||||||
|
item_type *q;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct priority_queue *pq_create() {
|
||||||
|
item_type *q = calloc(PQ_SIZE, sizeof(item_type));
|
||||||
|
struct priority_queue *pq = malloc(sizeof(struct priority_queue));
|
||||||
|
pq->q = q;
|
||||||
|
pq->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pq_parent(int n) {
|
||||||
|
if (n == 1) return -1;
|
||||||
|
else return ((int) n/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pq_young_child(int n) {
|
||||||
|
return 2 * n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I mean technically we shouldn't need to provide the parent, since we can
|
||||||
|
// just call that ourselves
|
||||||
|
void pq_swap(struct priority_queue *pq, int n, int parent) {
|
||||||
|
item_type item = pq->q[n];
|
||||||
|
pq->q[n] = pq->q[parent];
|
||||||
|
pq->q[parent] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pq_bubble_up(struct priority_queue *pq, int n) {
|
||||||
|
int pidx = pq_parent(n);
|
||||||
|
if (pidx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item_type parent = pq->q[pidx];
|
||||||
|
item_type node = pq->q[n];
|
||||||
|
|
||||||
|
if (parent > node) {
|
||||||
|
pq_swap(pq, n, pidx);
|
||||||
|
pq_bubble_up(pq, pidx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pq_bubble_down(struct priority_queue *pq, int n) {
|
||||||
|
int cidx = pq_young_child(n);
|
||||||
|
if (cidx > pq->len) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item_type child = pq->q[cidx];
|
||||||
|
item_type node = pq->q[n];
|
||||||
|
int min_idx = n;
|
||||||
|
|
||||||
|
if (cidx <= pq->len && node > child) {
|
||||||
|
min_idx = cidx;
|
||||||
|
}
|
||||||
|
if (cidx + 1 <= pq->len && pq->q[min_idx] > pq->q[cidx + 1]) {
|
||||||
|
min_idx = cidx + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node > child) {
|
||||||
|
pq_swap(pq, n, min_idx);
|
||||||
|
pq_bubble_down(pq, min_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pq_insert(struct priority_queue *pq, item_type x) {
|
||||||
|
if (pq->len >= PQ_SIZE) {
|
||||||
|
printf("Error: Priority Queue Overflow");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pq->q[++pq->len] = x;
|
||||||
|
pq_bubble_up(pq, pq->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
item_type pq_pop_top(struct priority_queue *pq) {
|
||||||
|
if (pq->len == 0) {
|
||||||
|
printf("Error: No elements in Priority Qeueu");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
item_type top = pq->q[1];
|
||||||
|
pq->q[1] = pq->q[pq->len--];
|
||||||
|
pq_bubble_down(pq, 1);
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct priority_queue* pq = pq_create();
|
||||||
|
|
||||||
|
#define ELEMENTS 8
|
||||||
|
item_type arr[ELEMENTS];
|
||||||
|
|
||||||
|
for (int i = 0; i < ELEMENTS; i++) {
|
||||||
|
arr[i] = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverse(item_type *arr) {
|
||||||
|
for (int i = 0; i < ELEMENTS / 2; i++) {
|
||||||
|
item_type temp = arr[i];
|
||||||
|
arr[i] = arr[ELEMENTS - i - 1];
|
||||||
|
arr[ELEMENTS - i - 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shuffle(item_type *arr) {
|
||||||
|
for (int i = 0; i < ELEMENTS - 1; i++) {
|
||||||
|
float r = (float)rand() / RAND_MAX;
|
||||||
|
int idx = (int)(ELEMENTS * r);
|
||||||
|
item_type temp = arr[idx];
|
||||||
|
arr[idx] = arr[i];
|
||||||
|
arr[i] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_elems(item_type *arr) {
|
||||||
|
for (int i = 0; i < ELEMENTS; i++) {
|
||||||
|
printf("%d,", arr[i]);
|
||||||
|
if (i == ELEMENTS - 1) {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_pq(struct priority_queue *pq) {
|
||||||
|
for (int i = 1; i <= pq->len; i++) {
|
||||||
|
printf("%d,", pq->q[i]);
|
||||||
|
if (i == pq->len) {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse(arr);
|
||||||
|
for (int i = 0; i < ELEMENTS; i++) {
|
||||||
|
pq_insert(pq, arr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_pq(pq);
|
||||||
|
|
||||||
|
pq_pop_top(pq);
|
||||||
|
|
||||||
|
print_pq(pq);
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
** 4.4 War Story
|
||||||
|
|
||||||
|
Apparently calculating airline tickets is hard
|
||||||
|
|
||||||
|
** 4.5 Mergesort
|
||||||
|
|
||||||
|
** 4.6 Quicksort
|
||||||
|
|
||||||
|
** 4.7 Distribution Sort: Bucketing
|
||||||
|
|
||||||
|
** 4.8 War Story
|
||||||
|
|
||||||
|
** 4.9 Binary Search and Related Algorithms
|
||||||
|
|
||||||
|
** 4.10 Divide-and-Conquer
|
||||||
|
Loading…
x
Reference in New Issue
Block a user