From 679b38ab78416c5b4f5827419f65804aff0a2148 Mon Sep 17 00:00:00 2001 From: A-hungry-wolf Date: Wed, 26 May 2021 20:10:40 +0800 Subject: [PATCH] week 13 AVL tree --- week13/AVL.c | 246 +++++++++++++++++++++++++++++++++++++ week13/AVL.h | 59 +++++++++ week13/main.c | 33 +++++ week13/printTree.c | 295 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 633 insertions(+) create mode 100644 week13/AVL.c create mode 100644 week13/AVL.h create mode 100644 week13/main.c create mode 100644 week13/printTree.c diff --git a/week13/AVL.c b/week13/AVL.c new file mode 100644 index 0000000..8d1a38c --- /dev/null +++ b/week13/AVL.c @@ -0,0 +1,246 @@ +#include +#include "AVL.h" +#include +#include +#include + +int max(int a, int b) +{ + if (a > b) + { + return a; + } + + return b; +} + +int getHeight(Node *N) +{ + if (N == NULL) + return -1; + + int x = getHeight(N->left); + int y = getHeight(N->right); + + if (x >= y) + return x + 1; + + return y + 1; +} + +int getBalance(Node *N) +{ + return getHeight(N->left) - getHeight(N->right); +} + +Node *findNode(Node *root, int x) +{ + if (root == NULL) + { + return NULL; + } + + if (root->key == x) + { + return root; + } + + if (x < root->key) + { + return findNode(root->left, x); + } + + return findNode(root->right, x); +} + +Node *rightRotate(Node *N) +{ + Node *N1 = N->left; + Node *N2 = N1->right; + + N1->right = N; + N->left = N2; + + N->height = max(getHeight(N->left), getHeight(N->right)) + 1; + N1->height = max(getHeight(N1->left), getHeight(N1->right)) + 1; + + return N1; +} + +Node *leftRotate(Node *N) +{ + Node *N1 = N->right; + Node *N2 = N1->left; + + N1->left = N; + N->right = N2; + + N->height = max(getHeight(N->left), getHeight(N->right)) + 1; + N1->height = max(getHeight(N1->left), getHeight(N1->right)) + 1; + + return N1; +} + +Node *minNode(Node *N) +{ + while (N->left != NULL) + { + N = N->left; + } + return N; +} + +Node *insertNode(Node **root, int x) +{ + Node *ans; + + /* insert the data */ + if (*root == NULL) + { + Node *temp = (Node *)malloc(sizeof(Node)); + temp->key = x; + temp->height = 0; + temp->left = NULL; + temp->right = NULL; + *root = temp; + ans = temp; + return ans; + } + else if ((*root)->key > x) + { + ans = insertNode(&(*root)->left, x); + } + else if ((*root)->key < x) + { + ans = insertNode(&(*root)->right, x); + } + + /* handle the unbalance problem */ + (*root)->height = 1 + max(getHeight((*root)->left), getHeight((*root)->right)); + + int balance = getBalance(*root); + + /* case 1 left left unbalance */ + if (balance > 1 && getBalance((*root)->left) >= 0) + { + *root = rightRotate(*root); + } + + /* case 2 left right unbalance */ + if (balance > 1 && getBalance((*root)->left) < 0) + { + (*root)->left = leftRotate((*root)->left); + *root = rightRotate(*root); + } + + /* case 3 right left unbalance */ + if (balance < -1 && getBalance((*root)->right) > 0) + { + (*root)->right = rightRotate((*root)->right); + *root = leftRotate(*root); + } + + /* case 4 right right unbalance */ + if (balance < -1 && getBalance((*root)->right) <= 0) + { + *root = leftRotate(*root); + } + + return ans; +} + +Node *deleteNode(Node **root, int x) +{ + Node *temp = *root; + + if (*root == NULL) + return *root; + + if (x < (*root)->key) + { + temp = deleteNode(&(*root)->left, x); + } + + else if (x > (*root)->key) + { + temp = deleteNode(&(*root)->right, x); + } + + else + { + if ((*root)->left == NULL || (*root)->right == NULL) + { + Node *child = (*root)->left != NULL ? (*root)->left : (*root)->right; + + if (child == NULL) + { // no child case; + *root = NULL; + return temp; + } + else + { + (*root)->key = child->key; + if ((*root)->left && (*root)->left->key == child->key) + { // left child case; + temp = deleteNode(&(*root)->left, child->key); + } + else if ((*root)->right && (*root)->right->key == child->key) + { // right child case; + temp = deleteNode(&(*root)->right, child->key); + } + } + } + else + { // two children case; + Node *child = minNode((*root)->right); + (*root)->key = child->key; + temp = deleteNode(&(*root)->right, child->key); + } + } + + if ((*root) == NULL) + return *root; + + int balance = getBalance(*root); + + (*root)->height = 1 + max(getHeight((*root)->left), getHeight((*root)->right)); + + /* case 1 left left unbalance */ + if (balance > 1 && getBalance((*root)->left) >= 0) + { + *root = rightRotate(*root); + } + + /* case 2 left right unbalance */ + if (balance > 1 && getBalance((*root)->left) < 0) + { + (*root)->left = leftRotate((*root)->left); + *root = rightRotate(*root); + } + + /* case 3 right left unbalance */ + if (balance < -1 && getBalance((*root)->right) > 0) + { + (*root)->right = rightRotate((*root)->right); + *root = leftRotate(*root); + } + + /* case 4 right right unbalance */ + if (balance < -1 && getBalance((*root)->right) <= 0) + { + *root = leftRotate(*root); + } + + return temp; +} + +void destroyTree(Node *root) +{ + if (root == NULL) + return; + + destroyTree(root->left); + destroyTree(root->right); + + free(root); +} \ No newline at end of file diff --git a/week13/AVL.h b/week13/AVL.h new file mode 100644 index 0000000..e434b11 --- /dev/null +++ b/week13/AVL.h @@ -0,0 +1,59 @@ +typedef struct Node Node; +typedef struct Node +{ + int key, height; + Node *left, *right; +} Node; + +Node *insertNode(Node **proot, int x); +/* + 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 *deleteNode(Node **proot, 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 *findNode(Node *root, 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 +*/ + +void destroyTree(Node *root); +/* + function: + deletes all the nodes in the tree and frees the memory occupied by them + input: + root - pointer to the tree node +*/ + +void printTree(Node *root); +/* + function: + prints ascii tree for given Node structure + this function is already implemented in printTree.cpp + input: + root - pointer to the tree node +*/ diff --git a/week13/main.c b/week13/main.c new file mode 100644 index 0000000..59b459d --- /dev/null +++ b/week13/main.c @@ -0,0 +1,33 @@ +#include +#include +#include "AVL.h" + +int main() +{ + Node *root = NULL; + + int ins[] = {16, 10, 21, 5, 12, 18, 24, 2, 8, 11, 15, 19, 23, 31, 1, 6, 9, 13, 22, 7}; + int len = 20, x; + for (int i = 0; i < len; i++) + { + printf("\nAfter inserting key %d..\n", ins[i]); + insertNode(&root, ins[i]); + printTree(root); + } + printf("\nInsert a new node (+ to insert, - to delete, 0 to exit): "); + scanf("%d", &x); + while (x) + { + if (x > 0) + insertNode(&root, x); + else + free(deleteNode(&root, -x)); + printTree(root); + printf("\nInsert a new node (+ to insert, - to delete, 0 to exit): "); + scanf("%d", &x); + } + + destroyTree(root); + + return 0; +} \ No newline at end of file diff --git a/week13/printTree.c b/week13/printTree.c new file mode 100644 index 0000000..ec94a03 --- /dev/null +++ b/week13/printTree.c @@ -0,0 +1,295 @@ +#include +#include +#include +#include "AVL.h" + +//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|%d", t->key, t->height); + + 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); +} \ No newline at end of file