diff --git a/chapters/FFT/code/c/fft.c b/chapters/FFT/code/c/fft.c index ff3aac530..839507df6 100644 --- a/chapters/FFT/code/c/fft.c +++ b/chapters/FFT/code/c/fft.c @@ -1,10 +1,21 @@ #include #include +#include #include +#include #include -#include -#define PI 3.1415926535897932384626 +void dft(double complex *X, const size_t N) { + double complex tmp[N]; + for (size_t i = 0; i < N; ++i) { + tmp[i] = 0; + for (size_t j = 0; j < N; ++j) { + tmp[i] += X[j] * cexp(-2.0 * M_PI * I * j * i / N); + } + } + + memcpy(X, tmp, N * sizeof(*X)); +} void cooley_tukey(double complex *X, const size_t N) { if (N >= 2) { @@ -21,30 +32,32 @@ void cooley_tukey(double complex *X, const size_t N) { cooley_tukey(X + N / 2, N / 2); for (size_t i = 0; i < N / 2; ++i) { - X[i + N / 2] = X[i] - cexp(-2.0 * I * PI * i / N) * X[i + N / 2]; + X[i + N / 2] = X[i] - cexp(-2.0 * I * M_PI * i / N) * X[i + N / 2]; X[i] -= (X[i + N / 2]-X[i]); } } } void bit_reverse(double complex *X, size_t N) { - double complex temp; - unsigned int b; + for (int i = 0; i < N; ++i) { + int n = i; + int a = i; + int count = (int)log2((double)N) - 1; - for (unsigned int i = 0; i < N; ++i) { - b = i; - b = (((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1)); - b = (((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2)); - b = (((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4)); - b = (((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8)); - b = ((b >> 16) | (b << 16)) >> - (32 - (unsigned int) log2((double)N)); - if (b > i) { - temp = X[b]; - X[b] = X[i]; - X[i] = temp; - } + n >>= 1; + while (n > 0) { + a = (a << 1) | (n & 1); + count--; + n >>= 1; } + n = (a << count) & ((1 << (int)log2((double)N)) - 1); + + if (n > i) { + double complex tmp = X[i]; + X[i] = X[n]; + X[n] = tmp; + } + } } void iterative_cooley_tukey(double complex *X, size_t N) { @@ -52,7 +65,7 @@ void iterative_cooley_tukey(double complex *X, size_t N) { for (int i = 1; i <= log2((double)N); ++i) { int stride = pow(2, i); - double complex w = cexp(-2.0 * I * PI / stride); + double complex w = cexp(-2.0 * I * M_PI / stride); for (size_t j = 0; j < N; j += stride) { double complex v = 1.0; for (size_t k = 0; k < stride / 2; ++k) { diff --git a/chapters/FFT/cooley_tukey.md b/chapters/FFT/cooley_tukey.md index 3c9a33428..041f61610 100644 --- a/chapters/FFT/cooley_tukey.md +++ b/chapters/FFT/cooley_tukey.md @@ -72,7 +72,7 @@ For some reason, though, putting code to this transformation really helped me fi {% sample lang="jl" %} [import:2-11, lang:"julia"](code/julia/fft.jl) {% sample lang="c" %} -[import:2-11, lang:"julia"](code/julia/fft.jl) +[import:7-19, lang:"c_cpp"](code/c/fft.c) {% sample lang="cpp" %} [import:2-11, lang:"julia"](code/julia/fft.jl) {% sample lang="hs" %} @@ -117,7 +117,7 @@ In the end, the code looks like: {% sample lang="jl" %} [import:14-31, lang:"julia"](code/julia/fft.jl) {% sample lang="c" %} -[import:9-28, lang:"c_cpp"](code/c/fft.c) +[import:21-40, lang:"c_cpp"](code/c/fft.c) {% sample lang="cpp" %} [import:27-57, lang:"c_cpp"](code/c++/fft.cpp) {% sample lang="hs" %} diff --git a/chapters/tree_traversal/code/c/tree_traversal.c b/chapters/tree_traversal/code/c/tree_traversal.c index 22239b5f5..7fed9a16c 100644 --- a/chapters/tree_traversal/code/c/tree_traversal.c +++ b/chapters/tree_traversal/code/c/tree_traversal.c @@ -1,150 +1,121 @@ -#include +#include "utility.h" + +#include #include -#include +#include -typedef struct node { +struct node { struct node *children; - int children_num; - int ID; -} node; - -typedef struct node_list { - node n; - struct node_list *last_list, *next_list; -} node_list; - -typedef struct node_points { - node_list *start_point, *end_point; -} node_points; - -void push(node_points *np, node n) { - node_list *temp = (node_list*)malloc(sizeof(node_list)); - temp->n = n; - temp->last_list = temp->next_list = NULL; - - if (!np->end_point) { - np->start_point = temp; - } else { - np->end_point->next_list = temp; - temp->last_list = np->end_point; + size_t children_size; + int id; +}; + +struct node create_tree(int rows, size_t num_children) { + struct node n = {NULL, 0, rows}; + + if (rows > 0) { + n.children = (struct node*)malloc(num_children * sizeof(struct node)); + n.children_size = num_children; + for (size_t i = 0; i < num_children; ++i) { + n.children[i] = create_tree(rows - 1, num_children); + } } - np->end_point = temp; + return n; } -void stack_pop(node_points *np) { - node_list *temp; - temp = np->end_point; - - if (temp) { - np->end_point = temp->last_list; - if (!np->end_point) { - np->start_point = NULL; +void destroy_tree(struct node n) { + if (n.id > 0) { + for (size_t i = 0; i < n.children_size; ++i) { + destroy_tree(n.children[i]); } - free(temp); + free(n.children); } } -void queue_pop(node_points *np) { - node_list *temp; - temp = np->start_point; - if (temp) { - np->start_point = temp->next_list; - if (!np->start_point) { - np->end_point = NULL; - } +void dfs_recursive(struct node n) { + printf("%d\n", n.id); - free(temp); + if (n.children) { + for (size_t i = 0; i < n.children_size; ++i) { + dfs_recursive(n.children[i]); + } } } -void create_tree(node *n, int num_row, int num_child) { - n->ID = num_row; - if (num_row == 0) { - return; +void dfs_recursive_postorder(struct node n) { + for (size_t i = 0; i < n.children_size; ++i) { + dfs_recursive_postorder(n.children[i]); } - n->children = (node *)malloc(num_child * sizeof(*n->children)); - n->children_num = num_child; - for (int i = 0; i < num_child; ++i) { - node child; - create_tree(&child, num_row - 1, num_child); - *(n->children + i) = child; - } + printf("%d\n", n.id); } -void DFS_recursive(node n) { - printf("%d\n", n.ID); - if (!n.children) { - return; - } - - for (int i = 0; i < n.children_num; ++i) { - DFS_recursive(n.children[i]); +void dfs_recursive_inorder_btree(struct node n) { + switch (n.children_size) { + case 2: + dfs_recursive_inorder_btree(n.children[0]); + printf("%d\n", n.id); + dfs_recursive_inorder_btree(n.children[1]); + break; + case 1: + dfs_recursive_inorder_btree(n.children[0]); + printf("%d\n", n.id); + break; + case 0: + printf("%d\n", n.id); + break; + default: + printf("This is not a binary tree.\n"); + break; } } -void DFS_stack(node n) { - node_points stack; - memset(&stack, 0, sizeof(node_points)); - push(&stack, n); - node temp; - - while (stack.start_point != NULL) { - temp = stack.end_point->n; - printf("%d\n", temp.ID); - stack_pop(&stack); - for (int i = 0; i < temp.children_num; ++i) { - if (!temp.children) { - break; - } - - push(&stack, temp.children[i]); +void dfs_stack(struct node n) { + struct stack stk = get_stack(sizeof(struct node*)); + stack_push(&stk, &n); + struct node *tmp; + + while (!stack_empty(&stk)) { + tmp = (struct node*)stack_pop(&stk); + if (!tmp) { + break; } - } -} -void BFS_queue(node n) { - node_points queue; - memset(&queue, 0, sizeof(node_points)); - push(&queue, n); - node temp; - - while (queue.start_point != NULL) { - temp = queue.start_point->n; - printf("%d\n", temp.ID); - queue_pop(&queue); - for (int i = 0; i < temp.children_num; ++i) { - if (!temp.children) { - break; - } - - push(&queue, temp.children[i]); + printf("%d\n", tmp->id); + for (size_t i = 0; i < tmp->children_size; ++i) { + stack_push(&stk, &tmp->children[i]); } } + + free_stack(stk); } -void destroy_tree(node *n) { - if (n->ID == 0) { - return; - } +void bfs_queue(struct node n) { + struct queue q = get_queue(sizeof(struct node*)); + enqueue(&q, &n); + struct node *tmp; - for (int i = 0; i < n->children_num; ++i) { - destroy_tree(n->children + i); + while (!queue_empty(&q)) { + tmp = (struct node*)dequeue(&q); + if (!tmp) { + break; + } + + printf("%d\n", tmp->id); + for (size_t i = 0; i < tmp->children_size; ++i) { + enqueue(&q, &tmp->children[i]); + } } - free(n->children); + free_queue(q); } int main() { - node root; - create_tree(&root, 3, 3); - DFS_recursive(root); - //DFS_stack(root); - //BFS_queue(root); - destroy_tree(&root); + struct node root = create_tree(3, 3); + bfs_queue(root); + destroy_tree(root); return 0; } - diff --git a/chapters/tree_traversal/code/c/utility.h b/chapters/tree_traversal/code/c/utility.h new file mode 100644 index 000000000..04e33342e --- /dev/null +++ b/chapters/tree_traversal/code/c/utility.h @@ -0,0 +1,105 @@ +#ifndef UTILITY_H +#define UTILITY_H + +#include +#include +#include +#include + +struct stack { + void **data; + size_t top, capacity, size; +}; + +struct queue { + void **data; + size_t front, back, capacity; +}; + +struct stack get_stack(size_t size) { + struct stack stk; + + stk.data = malloc(4 * size); + stk.capacity = 4; + stk.top = 0; + + return stk; +} + +bool stack_empty(struct stack *stk) { + return stk->top == 0; +} + +void stack_push(struct stack *stk, void *element) { + if (stk->top == stk->capacity) { + stk->capacity *= 2; + stk->data = realloc(stk->data, stk->capacity * sizeof(stk->data[0])); + } + + stk->data[stk->top++] = element; +} + +void *stack_pop(struct stack *stk) { + if (stack_empty(stk)) { + return NULL; + } + + return stk->data[--stk->top]; +} + +void free_stack(struct stack stk) { + free(stk.data); +} + +struct queue get_queue(size_t size) { + struct queue q; + + q.data = calloc(4, size); + q.front = 0; + q.back = 0; + q.capacity = 4; + + return q; +} + +bool queue_empty(struct queue *q) { + return q->front == q->back; +} + +void queue_resize(struct queue *q) { + size_t size = sizeof(q->data[0]); + void **tmp = calloc((q->capacity * 2), size); + memcpy(tmp, q->data + q->front, (q->capacity - q->front) * size); + memcpy(tmp + q->capacity - q->front, q->data, (q->front - 1) * size); + + q->data = tmp; + q->back = q->capacity - 1; + q->front = 0; + q->capacity *= 2; +} + +void enqueue(struct queue *q, void *element) { + if (q->front == (q->back % q->capacity) + 1) { + queue_resize(q); + } + + q->data[q->back] = element; + q->back = (q->back + 1) % q->capacity; +} + +void *dequeue(struct queue *q) { + if (queue_empty(q)) { + return NULL; + } + + void *ret = q->data[q->front]; + q->front = (q->front + 1) % q->capacity; + + return ret; +} + +void free_queue(struct queue q) { + free(q.data); +} + +#endif //UTILITY_H diff --git a/chapters/tree_traversal/tree_traversal.md b/chapters/tree_traversal/tree_traversal.md index 343ce5fd1..06c2ae438 100644 --- a/chapters/tree_traversal/tree_traversal.md +++ b/chapters/tree_traversal/tree_traversal.md @@ -1,4 +1,4 @@ -# Tree Traversal +# Tree Traversal Trees are naturally recursive data structures, and because of this, we cannot access their elements like we might access the elements of a vector or array. Instead, we need to use more interesting methods to work through each element. This is often called *Tree Traversal*, and there are many different ways to do this. For now, we will restrict the discussion to two common and related methods of tree traversal: *Depth-First* and *Breadth-First Search*. Note that trees vary greatly in shape and size depending on how they are used; however, they are composed primarily of nodes that house other, children nodes, like so: @@ -10,7 +10,7 @@ Trees are naturally recursive data structures, and because of this, we cannot ac {% sample lang="cs" %} [import:11-15, lang:"csharp"](code/cs/TreeMdAdditional/TreeMdAdditional.cs) {% sample lang="c" %} -[import:5-10, lang:"c_cpp"](code/c/tree_traversal.c) +[import:7-11, lang:"c_cpp"](code/c/tree_traversal.c) {% sample lang="js" %} This has not been implemented in your chosen language, so here is the Julia code [import:3-7, lang:"julia"](code/julia/Tree.jl) @@ -35,7 +35,7 @@ Because of this, the most straightforward way to traverse the tree might be recu {% sample lang="cs" %} [import:48-57, lang:"csharp"](code/cs/TreeMdAdditional/TreeMdAdditional.cs) {% sample lang="c" %} -[import:77-86, lang:"c_cpp"](code/c/tree_traversal.c) +[import:37-45, lang:"c_cpp"](code/c/tree_traversal.c) {% sample lang="js" %} [import:15-23, lang:"javascript"](code/javascript/Tree_example.js) {% sample lang="py2" %} @@ -70,8 +70,7 @@ This has not been implemented in your chosen language, so here is the Julia code {% sample lang="cs" %} [import:75-84, lang:"csharp"](code/cs/TreeMdAdditional/TreeMdAdditional.cs) {% sample lang="c" %} -This has not been implemented in your chosen language, so here is the Julia code -[import:18-26, lang:"julia"](code/julia/Tree.jl) +[import:47-53, lang:"c_cpp"](code/c/tree_traversal.c) {% sample lang="js" %} This has not been implemented in your chosen language, so here is the Julia code [import:18-26, lang:"julia"](code/julia/Tree.jl) @@ -104,8 +103,7 @@ This has not been implemented in your chosen language, so here is the Julia code {% sample lang="cs" %} [import:86-104, lang:"csharp"](code/cs/TreeMdAdditional/TreeMdAdditional.cs) {% sample lang="c" %} -This has not been implemented in your chosen language, so here is the Julia code -[import:28-43, lang:"julia"](code/julia/Tree.jl) +[import:55-73, lang:"c_cpp"](code/c/tree_traversal.c) {% sample lang="js" %} This has not been implemented in your chosen language, so here is the Julia code [import:28-43, lang:"julia"](code/julia/Tree.jl) @@ -147,9 +145,7 @@ In code, it looks like this: {% sample lang="cs" %} [import:36-52, lang:"csharp"](code/cs/Tree/Tree.cs) {% sample lang="c" %} -[import:20-33, lang:"c_cpp"](code/c/tree_traversal.c) -[import:35-47, lang:"c_cpp"](code/c/tree_traversal.c) -[import:88-106, lang:"c_cpp"](code/c/tree_traversal.c) +[import:75-93, lang:"c_cpp"](code/c/tree_traversal.c) {% sample lang="js" %} [import:25-40, lang:"javascript"](code/javascript/Tree_example.js) {% sample lang="py2" %} @@ -179,7 +175,7 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can {% sample lang="cs" %} [import:54-70, lang:"csharp"](code/cs/Tree/Tree.cs) {% sample lang="c" %} -[import:108-126, lang:"c_cpp"](code/c/tree_traversal.c) +[import:95-113, lang:"c_cpp"](code/c/tree_traversal.c) {% sample lang="js" %} [import:42-57, lang:"javascript"](code/javascript/Tree_example.js) {% sample lang="py2" %} @@ -209,6 +205,9 @@ Program.cs [import, lang:"csharp"](code/cs/Tree/Program.cs) {% sample lang="c" %} ### C +utility.h +[import, lang:"c_cpp"](code/c/utility.h) +tree_traversal.c [import, lang:"c_cpp"](code/c/tree_traversal.c) {% sample lang="js" %} ### JavaScript