Anda di halaman 1dari 9

/* FILE psb_bag.c * Implementation of the bag ADT using an psb tree.

* Author: Dazhi Liao liaodazh and Jeffry Ung ungjeffr */ /****************************************************************************** * Types and Constants. * ******************************************************************************/ #include <stdio.h> #include <stdlib.h> #include "bag.h" /* TYPE psb_note_t -- A node in an psb tree. */ typedef struct psb_node { bag_elem_t elem; /* the element stored in this node */ struct psb_node *left; /* pointer to this node's left child */ struct psb_node *right; /* pointer to this node's right child */ } psb_node_t; /* TYPE struct bag -- Definition of struct bag from the header. */ struct bag { size_t size; /* number of elements in this bag */ psb_node_t *root; /* root of the psb tree storing the elements */ int (*cmp)(bag_elem_t, bag_elem_t); /* function to compare elements */ }; /****************************************************************************** * Declarations of helper functions -- including full documentation. * ******************************************************************************/ /* FUNCTION psb_destroy * Free the memory allocated for the binary tree rooted at a given node. * Parameters and preconditions: * root: the root of the tree to free * Return value: none * Side-effects: * all the memory allocated for nodes in the subtree rooted at root has been * freed */ static void psb_destroy(psb_node_t *root); /* FUNCTION psb_traverse * Call a function on every element in a BST, given its root. * Parameters and preconditions: * root: the root of the BST to traverse * fun != NULL: a pointer to a function to apply to each element in the tree * Return value: none * Side-effect: * function fun has been called on each element in the tree rooted at root, * in order */ static void psb_traverse(const psb_node_t *root, void (*fun)(bag_elem_t)); /* FUNCTION psb_contains * Return whether or not a BST contains a certain element, given the root. * Parameters and preconditions:

* root: the root of the BST to search * elem != NULL: the element to search for * cmp != NULL: the comparison function to use for the search * Return value: * elem, if the BST rooted at 'root' contains it; NULL otherwise * Side-effects: none */ static bag_elem_t psb_contains(psb_node_t **root, bag_elem_t elem, int (*cmp)(bag_elem_t, bag_elem_t)); /* FUNCTION psb_insert * Add an element to a BST, given a pointer to its root. * Parameters and preconditions: * root: a pointer to the root of the BST into which to insert * elem != NULL: the element to insert * cmp != NULL: the comparison function to use to find the insertion point * Return value: * elem, if it was inserted; NULL in case of error * Side-effects: * memory has been allocated for the new element, and the tree structure has * been adjusted accordingly */ static bag_elem_t psb_insert(psb_node_t **root, bag_elem_t elem, int (*cmp)(bag_elem_t, bag_elem_t)); /* FUNCTION psb_remove * Remove an element from a BST, given a pointer to its root. * Parameters and preconditions: * root: a pointer to the root of the BST into which to remove * elem != NULL: the element to remove * cmp != NULL: the comparison function to use to find the removal point * Return value: * elem, if it was removed; NULL if the element was not there * Side-effects: * memory has been freed for the element removed, and the tree structure has * been adjusted accordingly */ static bag_elem_t psb_remove(psb_node_t **root, bag_elem_t elem, int (*cmp)(bag_elem_t, bag_elem_t)); /* FUNCTION psb_remove_min * Remove and return the smallest element in a BST, given a pointer to its * root. * Parameters and preconditions: * root: a pointer to the root of the BST * Return value: * the smallest element in the BST rooted at 'root' * Side-effects: * memory has been freed for the node containing the smallest element, and * the tree structure has been adjusted accordingly */ static bag_elem_t psb_remove_min(psb_node_t **root); /* FUNCTION psb_rotate_to_the_left

* Perform a single rotation of *parent to the left. Note that * the minimum node of the right subtree (i.e. b) becomes the * parent of *parent -- the tree structure * goes from *parent to child * / \ / \ * subtree child b C * / \ / * B C *parent * / * subtree * Parameters and precondition: * parent != NULL: a pointer to the pointer to the root of the tree to rotate * (*parent != NULL and (*parent)->right != NULL) * Return value: none * Side-effects: * the subtree rooted at *parent has been modified by rotating *parent with * its right child */ static void psb_rotate_to_the_left(psb_node_t **parent); /* psb_rotate_to_the_right * Perform a single rotation of *parent to the right. Note that * the maximum node of the left subtree (i.e. b) becomes the * parent of *parent -- the tree structure * goes from *parent to child * / \ / \ * child C A B * / \ \ * A B *parent * \ * C * Parameters and precondition: * parent != NULL: a pointer to the pointer to the root of the tree to rotate * (*parent != NULL and (*parent)->left != NULL) * Return value: none * Side-effects: * the subtree rooted at *parent has been modified by rotating *parent with * its left child */ static void psb_rotate_to_the_right(psb_node_t **parent); /* FUNCTION psb_node_create * Create a new psb_node. * Parameters and preconditions: * elem: the element to store in the new node * Return value: * pointer to a new node that stores elem and whose children are both NULL; * NULL in case of error with memory allocation * Side-effects: * memory has been allocated for the new node */ static psb_node_t *psb_node_create(bag_elem_t elem); /* FUNCTION find_min * find the minimum node in the subtree given the root, then return it. * Parameters and preconditions: * root != NULL: the root node of the subtree

* Return value: * the minimum node in the subtree of the given root * Side-effects: none */ static psb_node_t * find_min(psb_node_t *root); /* FUNCTION find_max * find the maximum node in the subtree given the root, then return it. * Parameters and preconditions: * root != NULL: the root node of the subtree * Return value: * the maximum node in the subtree of the given root * Side-effects: none */ static psb_node_t * find_max(psb_node_t *root); /* FUNCTION psb_rotate * perform a single rotation based on the type of the given child node -* if it is a left child, rotate to the right; if it is a right child, * rotate to the left. * Parameters and preconditions: * parent != NULL: the corresponding parent node of the given child node * child != NULL: the child node of the parent; could be either left or right * Return value: none * Side-effects: * the child becomes the parent after rotation */ static void psb_rotate(psb_node_t **parent, psb_node_t *child); /****************************************************************************** * Definitions of "public" functions -- see header file for documentation. * ******************************************************************************/ bag_t *bag_create(int (*cmp)(bag_elem_t, bag_elem_t)) { bag_t *bag = malloc(sizeof(bag_t)); if (bag) { bag->size = 0; bag->root = NULL; bag->cmp = cmp; } return bag; } void bag_destroy(bag_t *bag) { psb_destroy(bag->root); free(bag); } size_t bag_size(const bag_t *bag) { return bag->size; } void bag_traverse(const bag_t *bag, void (*fun)(bag_elem_t)) { psb_traverse(bag->root, fun); }

bag_elem_t bag_contains(bag_t *bag, bag_elem_t elem) { return psb_contains(&bag->root, elem, bag->cmp); } bag_elem_t bag_insert(bag_t *bag, bag_elem_t elem) { bag_elem_t e = psb_insert(&bag->root, elem, bag->cmp); if (e) bag->size++; return e; } bag_elem_t bag_remove(bag_t *bag, bag_elem_t elem) { bag_elem_t e = psb_remove(&bag->root, elem, bag->cmp); if (e) bag->size--; return e; } /****************************************************************************** * Definitions of helper functions -- see above for documentation. * ******************************************************************************/ void psb_destroy(psb_node_t *root) { if (root) { psb_destroy(root->left); psb_destroy(root->right); free(root); } } void psb_traverse(const psb_node_t *root, void (*fun)(bag_elem_t)) { if (root) { psb_traverse(root->left, fun); (*fun)(root->elem); psb_traverse(root->right, fun); } } bag_elem_t psb_contains(psb_node_t **root, bag_elem_t elem, int (*cmp)(bag_elem_t, bag_elem_ t)) { psb_node_t *child, *parent, *grandparent; grandparent = NULL; parent = NULL; child = *root; if (! *root) return NULL; while (child) { // if the given element is smaller than the element // in the child node, then move it to the left if (cmp(elem, child->elem) < 0) { grandparent = parent; parent = child; child = child->left; }

// if the given element is larger than the element // in the child node, then move it to the right else if (cmp(elem, child->elem) > 0) { grandparent = parent; parent = child; child = child->right; } else { // (cmp(elem, root->elem) == 0) // CASE 1: ROOT IS WHAT WE'RE LOOKING FOR if (parent == NULL) return (*root)->elem; // // // // if CASE 2: WE ARE LOOKING FOR ROOT'S IMMEDIATE CHILDREN this case is special because we need to update the root pointer as well (the root of the tree will be altered) (grandparent == NULL) { psb_rotate(&parent, child); *root = parent; return parent->elem; } // CASE 3: child has grandparents // in this case, we just need to link the grandparent to // the child after rotation is performed. else { if (grandparent->left == parent) { psb_rotate(&parent, child); grandparent->left = parent; } else { psb_rotate(&parent, child); grandparent->right = parent; } } return child->elem; } } } void psb_rotate(psb_node_t **parent, psb_node_t *child) { // if it is a left child, rotate to the right; vise versa. if ((*parent)->left == child){ psb_rotate_to_the_right(parent); } else psb_rotate_to_the_left(parent); } bag_elem_t psb_insert(psb_node_t **root, bag_elem_t elem, int (*cmp)(bag_elem_t, bag_elem_t)) { bag_elem_t inserted; // if the node doesn't exist at first if (*root == NULL) { // then just create a new node if ((*root = psb_node_create(elem))) inserted = (*root)->elem; else // if memory allocation fails inserted = NULL; } else if ((*cmp)(elem, (*root)->elem) < 0) inserted = psb_insert(&(*root)->left, elem, cmp); else if ((*cmp)(elem, (*root)->elem) > 0) inserted = psb_insert(&(*root)->right, elem, cmp);

else { /* ((*cmp)(elem, (*root)->elem) == 0) */ /* Just insert into the left, arbitrarily. */ inserted = psb_insert(&(*root)->left, elem, cmp); } return inserted; } bag_elem_t psb_remove(psb_node_t **root, bag_elem_t elem, int (*cmp)(bag_elem_t, bag_elem_t)) { bag_elem_t removed; if (*root == NULL) { removed = NULL; } else if ((*cmp)(elem, (*root)->elem) < 0) removed = psb_remove(&(*root)->left, elem, cmp); else if ((*cmp)(elem, (*root)->elem) > 0) removed = psb_remove(&(*root)->right, elem, cmp); else { /* ((*cmp)(elem, (*root)->elem) == 0) */ removed = (*root)->elem; if ((*root)->left && (*root)->right) { (*root)->elem = psb_remove_min(&(*root)->right); } else { /* Remove *root. */ psb_node_t *old = *root; *root = (*root)->left ? (*root)->left : (*root)->right; free(old); } } return removed; } bag_elem_t psb_remove_min(psb_node_t **root) { bag_elem_t min; if ((*root)->left) { /* *root is not the minimum, keep going and rebalance if necessary. */ min = psb_remove_min(&(*root)->left); } else { /* Remove *root. */ psb_node_t *old = *root; min = (*root)->elem; *root = (*root)->right; free(old); } return min; } /// CHECK THESE void psb_rotate_to_the_left(psb_node_t **parent) { /* Rearrange pointers. */ psb_node_t *child = (*parent)->right; psb_node_t *min = find_min(child); min->left = *parent;

(*parent)->right = NULL; *parent = child; } void psb_rotate_to_the_right(psb_node_t **parent) { /* Rearrange pointers. */ psb_node_t *child = (*parent)->left; psb_node_t *max = find_max(child); max->right = *parent; (*parent)->left = NULL; *parent = child; } psb_node_t * find_min(psb_node_t *root) { if (root->left == NULL) return root; else return find_min(root->left); } psb_node_t * find_max(psb_node_t *root) { if (root->right == NULL) return root; else return find_max(root->right); } psb_node_t *psb_node_create(bag_elem_t elem) { psb_node_t *node = malloc(sizeof(psb_node_t)); if (node) { node->elem = elem; node->left = NULL; node->right = NULL; } return node; } /****************************************************************************** * Additional "hidden" functions, for debugging purposes. * ******************************************************************************/ /* FUNCTION psb_print * Print every value in the subtree rooted at root to stdout, in a "sideways * tree" layout with the root at the given depth. Print each node's element * and height. * Parameters and preconditions: * root != NULL: the root of the subtree to print * depth >= 0: the depth at which to print the root's value * indent > 0: number of spaces to print for each level of depth * print != NULL: the function to use to print each node's value * Return value: none * Side-effects: * every value in the subtree rooted at root is printed to stdout, using a * "sideways tree" layout (with right subtrees above and left subtrees below, * and indentation to indicate each value's depth in the tree) */ static void psb_print(const psb_node_t *root, int depth, int indent, void (*print)(bag_elem_t))

{ if (root) { psb_print(root->right, depth + 1, indent, print); /* Print each value followed by its depth, with INDENT spaces of * indentation for each level of depth in the tree. */ printf("%*s", depth * indent, ""); (*print)(root->elem); psb_print(root->left, depth + 1, indent, print); } } /* FUNCTION bag_print * Print every value in a bag to stdout, in a "sideways tree" layout. * Parameters and preconditions: * bag != NULL: the bag * print != NULL: the function to use to print each value in the bag * Return value: none * Side-effects: * every value in the bag is printed to stdout, using a "sideways tree" * layout (with right subtrees above and left subtrees below, and indentation * to indicate each value's depth in the tree) */ void bag_print(const bag_t *bag, int indent, void (*print)(bag_elem_t)) { psb_print(bag->root, 1, indent, print); }

Anda mungkin juga menyukai