diff --git a/week10/BST.c b/week10/BST.c new file mode 100644 index 0000000..63a78d2 --- /dev/null +++ b/week10/BST.c @@ -0,0 +1,103 @@ +/* + * Author: Walter + * Student ID: 1930006025 + * week_10_BST + */ + +#include "BST.h" +#include +#include + +Node *insertNode(Node **proot, int x) { + /* create if empty */ + if ((*proot) == NULL) { + *proot = (Node *)malloc(sizeof(Node)); + if (*proot == NULL) { + fprintf(stderr, "Can not allocate new space for node\n"); + exit(1); + } + (*proot)->key = x; + (*proot)->left = (*proot)->right = NULL; + return *proot; + } + + if (x < (*proot)->key) { + return insertNode(&((*proot)->left), x); + } else if (x > (*proot)->key) { + return insertNode(&((*proot)->right), x); + } + + /* equal, do nothing and return NULL, + * because insertion is not successful */ + return NULL; +} + +Node *findNode(Node *root, int x) { + /* empty tree */ + if (root == NULL) { + return NULL; + } + + if (x < root->key) { + return findNode(root->left, x); + } else if (x > root->key) { + return findNode(root->right, x); + } + + /* equal */ + return root; +} + +Node *deleteNode(Node **proot, int x) { + Node *tmpNode; + + /* not found */ + if (*proot == NULL) { + return NULL; + } + + /* find the node needs to be delete */ + if (x < (*proot)->key) { + return deleteNode(&((*proot)->left), x); + } else if (x > (*proot)->key) { + return deleteNode(&((*proot)->right), x); + } + + if ((*proot)->left && (*proot)->right) { + /* two child, find the min on right to replace */ + tmpNode = (*proot)->right; + while (tmpNode->left) { + tmpNode = tmpNode->left; + } + /* simply replace key value */ + (*proot)->key = tmpNode->key; + /* delete tmpNode, which has one or zero child */ + return deleteNode(&(*proot)->right, tmpNode->key); + } else if ((*proot)->left || (*proot)->right) { + /* one child */ + tmpNode = *proot; + if ((*proot)->left) { + *proot = (*proot)->left; + } + if ((*proot)->right) { + *proot = (*proot)->right; + } + } else { + /* no child */ + tmpNode = *proot; + *proot = NULL; + } + + return tmpNode; +} + +void destroyTree(Node *root) { + /* end situation */ + if (root == NULL) { + return; + } + destroyTree(root->left); + destroyTree(root->right); + free(root); + return; +} diff --git a/week10/BST.h b/week10/BST.h new file mode 100644 index 0000000..c0a167d --- /dev/null +++ b/week10/BST.h @@ -0,0 +1,42 @@ +typedef struct Node { + int key; + struct Node *left, *right; +} Node; + +/* function: inserts a new node to the tree +input: proot: pointer to the pointer to the tree root +x: the key of the new node +output: returns a pointer to the newly inserted node +returns NULL if insertion is not successful +*/ +Node *insertNode(Node **proot, int x); + +/* function: searches for a node in the tree +input: root: pointer to the tree root +x: the key of of the node to be searched +output: returns a pointer to the found node +returns NULL if no such node exists +*/ +Node *findNode(Node *root, int x); + +/* function: removes a node from the tree without freeing it +input: proot: pointer to the pointer to the tree root +x: the key of of the node to be deleted +output: returns a pointer to the deleted node +returns NULL if no such node exists +*/ +Node *deleteNode(Node **proot, int x); + +/* function: deletes all the nodes in the tree and frees the memory + occupied by them +input: root: pointer to the tree node +output: none +*/ +void destroyTree(Node *root); + +/* function: prints the tree in ASCII + (this function is already implemented in printTree.c) +input: root: pointer to the tree node +output: none +*/ +void printTree(Node *root); diff --git a/week10/main.c b/week10/main.c new file mode 100644 index 0000000..9ae7485 --- /dev/null +++ b/week10/main.c @@ -0,0 +1,66 @@ +#include "BST.h" +#include +#include + +int main(void) { + Node *root = NULL; + + printTree(root); + + printf("After inserting 10:\n"); + insertNode(&root, 10); + printTree(root); + + printf("\nAfter inserting 5:\n"); + insertNode(&root, 5); + printTree(root); + + printf("\nAfter inserting 15:\n"); + insertNode(&root, 15); + printTree(root); + + printf("\nAfter inserting 9, 13:\n"); + insertNode(&root, 9); + insertNode(&root, 13); + printTree(root); + + printf("\nAfter inserting 2, 6, 12, 14:\n"); + insertNode(&root, 2); + insertNode(&root, 6); + insertNode(&root, 12); + insertNode(&root, 14); + printTree(root); + + printf("\nSearching for 10, 6, 13, 14, 1, 3, 11, 16:\n"); + printf(findNode(root, 10)->key == 10 ? "true\n" : "false\n"); + printf(findNode(root, 6)->key == 6 ? "true\n" : "false\n"); + printf(findNode(root, 13)->key == 13 ? "true\n" : "false\n"); + printf(findNode(root, 14)->key == 14 ? "true\n" : "false\n"); + printf(findNode(root, 1) == NULL ? "true\n" : "false\n"); + printf(findNode(root, 3) == NULL ? "true\n" : "false\n"); + printf(findNode(root, 11) == NULL ? "true\n" : "false\n"); + printf(findNode(root, 16) == NULL ? "true\n" : "false\n"); + + printf("\nAfter deleting 12 (which has no children):\n"); + free(deleteNode(&root, 12)); + printTree(root); + + printf("\nAfter deleting 13 (which has a right child):\n"); + free(deleteNode(&root, 13)); + printTree(root); + + printf("\nAfter deleting 9 (which has a left child):\n"); + free(deleteNode(&root, 9)); + printTree(root); + + printf("\nAfter deleting 5 (which has two children):\n"); + free(deleteNode(&root, 5)); + printTree(root); + + printf("\nAfter deleting 10 (which has two children):\n"); + free(deleteNode(&root, 10)); + printTree(root); + + destroyTree(root); + return 0; +} diff --git a/week10/printTree.c b/week10/printTree.c new file mode 100644 index 0000000..6626685 --- /dev/null +++ b/week10/printTree.c @@ -0,0 +1,248 @@ +#include "BST.h" +#include +#include +#include + +// printing tree in ascii + +typedef struct asciinode_struct asciinode; + +struct asciinode_struct { + asciinode *left, *right; + + // length of the edge from this node to its children + int edge_length; + + int height; + + int lablen; + + //-1=I am left, 0=I am root, 1=right + int parent_dir; + + // max supported unit32 in dec, 10 digits max + char label[11]; +}; + +#define MAX_HEIGHT 1000 +int lprofile[MAX_HEIGHT]; +int rprofile[MAX_HEIGHT]; +#define INFINITY (1 << 20) + +// adjust gap between left and right nodes +int gap = 3; + +// used for printing next node in the same level, +// this is the x coordinate of the next char printed +int print_next; + +int MIN(int X, int Y) { return ((X) < (Y)) ? (X) : (Y); } + +int MAX(int X, int Y) { return ((X) > (Y)) ? (X) : (Y); } + +asciinode *build_ascii_tree_recursive(Node *t) { + asciinode *node; + + if (t == NULL) + return NULL; + + node = (asciinode *)malloc(sizeof(asciinode)); + node->left = build_ascii_tree_recursive(t->left); + node->right = build_ascii_tree_recursive(t->right); + + if (node->left != NULL) { + node->left->parent_dir = -1; + } + + if (node->right != NULL) { + node->right->parent_dir = 1; + } + + sprintf(node->label, "%d", t->key); + + node->lablen = strlen(node->label); + + return node; +} + +// Copy the tree into the ascii node structre +asciinode *build_ascii_tree(Node *t) { + asciinode *node; + if (t == NULL) + return NULL; + node = build_ascii_tree_recursive(t); + node->parent_dir = 0; + return node; +} + +// Free all the nodes of the given tree +void free_ascii_tree(asciinode *node) { + if (node == NULL) + return; + free_ascii_tree(node->left); + free_ascii_tree(node->right); + free(node); +} + +// The following function fills in the lprofile array for the given tree. +// It assumes that the center of the label of the root of this tree +// is located at a position (x,y). It assumes that the edge_length +// fields have been computed for this tree. +void compute_lprofile(asciinode *node, int x, int y) { + int i, isleft; + if (node == NULL) + return; + isleft = (node->parent_dir == -1); + lprofile[y] = MIN(lprofile[y], x - ((node->lablen - isleft) / 2)); + if (node->left != NULL) { + for (i = 1; i <= node->edge_length && y + i < MAX_HEIGHT; i++) { + lprofile[y + i] = MIN(lprofile[y + i], x - i); + } + } + compute_lprofile(node->left, x - node->edge_length - 1, + y + node->edge_length + 1); + compute_lprofile(node->right, x + node->edge_length + 1, + y + node->edge_length + 1); +} + +void compute_rprofile(asciinode *node, int x, int y) { + int i, notleft; + if (node == NULL) + return; + notleft = (node->parent_dir != -1); + rprofile[y] = MAX(rprofile[y], x + ((node->lablen - notleft) / 2)); + if (node->right != NULL) { + for (i = 1; i <= node->edge_length && y + i < MAX_HEIGHT; i++) { + rprofile[y + i] = MAX(rprofile[y + i], x + i); + } + } + compute_rprofile(node->left, x - node->edge_length - 1, + y + node->edge_length + 1); + compute_rprofile(node->right, x + node->edge_length + 1, + y + node->edge_length + 1); +} + +// This function fills in the edge_length and +// height fields of the specified tree +void compute_edge_lengths(asciinode *node) { + int h, hmin, i, delta; + if (node == NULL) + return; + compute_edge_lengths(node->left); + compute_edge_lengths(node->right); + + /* first fill in the edge_length of node */ + if (node->right == NULL && node->left == NULL) { + node->edge_length = 0; + } else { + if (node->left != NULL) { + for (i = 0; i < node->left->height && i < MAX_HEIGHT; i++) { + rprofile[i] = -INFINITY; + } + compute_rprofile(node->left, 0, 0); + hmin = node->left->height; + } else { + hmin = 0; + } + if (node->right != NULL) { + for (i = 0; i < node->right->height && i < MAX_HEIGHT; i++) { + lprofile[i] = INFINITY; + } + compute_lprofile(node->right, 0, 0); + hmin = MIN(node->right->height, hmin); + } else { + hmin = 0; + } + delta = 4; + for (i = 0; i < hmin; i++) { + delta = MAX(delta, gap + 1 + rprofile[i] - lprofile[i]); + } + + // If the node has two children of height 1, then we allow the + // two leaves to be within 1, instead of 2 + if (((node->left != NULL && node->left->height == 1) || + (node->right != NULL && node->right->height == 1)) && + delta > 4) { + delta--; + } + + node->edge_length = ((delta + 1) / 2) - 1; + } + + // now fill in the height of node + h = 1; + if (node->left != NULL) { + h = MAX(node->left->height + node->edge_length + 1, h); + } + if (node->right != NULL) { + h = MAX(node->right->height + node->edge_length + 1, h); + } + node->height = h; +} + +// This function prints the given level of the given tree, assuming +// that the node has the given x cordinate. +void print_level(asciinode *node, int x, int level) { + int i, isleft; + if (node == NULL) + return; + isleft = (node->parent_dir == -1); + if (level == 0) { + for (i = 0; i < (x - print_next - ((node->lablen - isleft) / 2)); i++) { + printf(" "); + } + print_next += i; + printf("%s", node->label); + print_next += node->lablen; + } else if (node->edge_length >= level) { + if (node->left != NULL) { + for (i = 0; i < (x - print_next - (level)); i++) { + printf(" "); + } + print_next += i; + printf("/"); + print_next++; + } + if (node->right != NULL) { + for (i = 0; i < (x - print_next + (level)); i++) { + printf(" "); + } + print_next += i; + printf("\\"); + print_next++; + } + } else { + print_level(node->left, x - node->edge_length - 1, + level - node->edge_length - 1); + print_level(node->right, x + node->edge_length + 1, + level - node->edge_length - 1); + } +} + +// prints ascii tree for given Node structure +void printTree(Node *root) { + asciinode *proot; + int xmin, i; + if (root == NULL) + return; + proot = build_ascii_tree(root); + compute_edge_lengths(proot); + for (i = 0; i < proot->height && i < MAX_HEIGHT; i++) { + lprofile[i] = INFINITY; + } + compute_lprofile(proot, 0, 0); + xmin = 0; + for (i = 0; i < proot->height && i < MAX_HEIGHT; i++) { + xmin = MIN(xmin, lprofile[i]); + } + for (i = 0; i < proot->height; i++) { + print_next = 0; + print_level(proot, -xmin, i); + printf("\n"); + } + if (proot->height >= MAX_HEIGHT) { + printf("(This tree is taller than %d, and may be drawn incorrectly.)\n", + MAX_HEIGHT); + } + free_ascii_tree(proot); +}