CLRS2e读书笔记—二叉搜索树

搜索树是一种很常用的数据结构,支持search、minimum、maximum、predecessor、successor、insert和delete等多种动态集合的操作,经常被用来做字典或优先级队列。binary search tree的所有操作都与树的高度成正比,也就是O(h)。我们称一颗二叉树是平衡的——如果二叉树是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

本章着重介绍了二叉查找树,下面几章分别介绍了几种常见的平衡二叉树,包括红黑树、B树和AVL树(思考题中)。

binary search tree的定义是,对于每个结点,其左子树的所有节点必须满足left[k]<=k,其右子树的所有结点必须满足right[k]>=k。这个定义是以下所有算法的基础。

search:查找一个指定结点。从根(或任意位置)开始,比较key值,如果结点的key小于被当前结点,查找左子树,否则查找右子树。如果超出叶结点,则待查找的结点不存在。

minimum:从根(或任意位置)开始,不断查找左儿子直到遇到叶结点。

maximum:类似,不断查找右儿子。

predecessor:前驱。一个结点的前驱(即有序化后其前面的结点)是其左子树的最大值。如果不存在左子树,那么向上查找父节点,直到某个节点是其父节点的右结点为止。如果不存在这样的结点,那么该节点就是整棵树的最小值。

successor:后继。类似地,一个节点的后继是其右子树的最小值。如果不存在右子树,那么向上查找父节点,直到某个节点是其父节点的左结点为止。

insert:插入的过程类似查找。先沿根节点(或任意结点)开始查找,如果当前结点大于待插入结点的key值,那么递归查找其右子树,如果小于,那么查找其左子树,重复以上过程直到遇到相等的结点或者叶子结点。然后根据确定的结点和待插入结点key的大小关系,选择正确的位置予以插入。

delete:删除的过程最为复杂。如果待删除的结点(仍然要先搜索)拥有0或1个子节点,那么可以通过删除链表结点的方法删除该结点,否则,必须用其前驱或后缀结点代替该结点,然后删除其前驱或后缀结点(可以证明其前驱和后缀结点最多拥有一个子节点)。

相关C程序(未经过调试):

  1 #ifndef BINARY_NODE_INCLUDED_
  2 #define BINARY_NODE_INCLUDED_
  3 
  4 struct node {
  5     struct node *parent;
  6     struct node *left;
  7     struct node *right;
  8     void *value;
  9 };
 10 
 11 #include <assert.h>
 12 #include <malloc.h>
 13 
 14 
 15 typedef struct node node;
 16 
 17 typedef int (*compare)(void *n1, void *n2);
 18 
 19 typedef struct binary_tree {
 20     node *root;
 21     size_t size;
 22 } binary_tree;
 23 
 24 node *binary_tree_minimum(const node *nd) {
 25     assert(nd);
 26     while (nd->left) {
 27         nd = nd->left;
 28     }
 29     return nd;
 30 }
 31 
 32 node *binary_tree_maximum(const node *nd) {
 33     assert(nd);
 34     while (nd->right)nd = nd->right;
 35     return nd;
 36 }
 37 
 38 node *binary_tree_search(const node *nd, void *value, compare cp) {
 39     assert(nd);
 40     int cp_result;
 41     while (nd && (cp_result = cp(nd->value, value))) {
 42         if (cp_result < 0)
 43             nd = nd->left;
 44         else
 45             nd = nd->right;
 46     }
 47     if (!nd)
 48         return NULL;
 49     return nd;
 50 }
 51 
 52 node *binary_node_precursor(const node *nd) {
 53     assert(nd);
 54     if (nd->left)
 55         return binary_tree_maximum(nd->left);
 56     while (nd == nd->parent->right)nd = nd->parent;
 57     return nd;
 58 }
 59 
 60 node *binary_node_succssor(const node *nd) {
 61     assert(nd);
 62     if (nd->right)
 63         return binary_tree_minimum(nd->right);
 64     while (nd == nd->parent->left)nd = nd->left;
 65     return nd;
 66 }
 67 
 68 node *binary_tree_insert(binary_tree *tree, void *value, compare cp) {
 69     assert(tree);
 70     tree->size += 1;
 71     node *nd = tree->root;
 72     node *newnode = (node *) malloc(sizeof(node));
 73     assert(newnode);
 74     newnode->left = NULL;
 75     newnode->right = NULL;
 76     newnode->parent = NULL;
 77     newnode->value = value;
 78     if (!nd) {
 79         tree->root = newnode;
 80         return NULL;
 81     }
 82     node *pre = NULL;
 83     int cp_result;
 84     while (nd && (cp_result = cp(nd->value, value))) {
 85         pre = nd;
 86         if (cp_result < 0)nd = nd->right;
 87         else
 88             nd = nd->left;
 89     }
 90     newnode->parent = pre;
 91     if (cp(pre->value, value) < 0)
 92         pre->right = newnode;
 93     else
 94         pre->left = newnode;
 95     return newnode;
 96 }
 97 
 98 void binary_tree_delete(binary_tree *tree, void *value, compare cp) {
 99     assert(tree);
100     node *nd = tree->root;
101     node *bak = nd;
102     if (!nd)return;
103     nd = binary_tree_search(nd, value, cp);
104     if (!nd)return;
105     int i = (nd->left != NULL) + (nd->right != NULL);
106     if (i > 1)nd = binary_node_succssor(nd);
107     if (nd->left) {
108         nd->left->parent = nd->parent;
109         nd->parent->left = nd->left;
110     } else {
111         nd->right->parent = nd->parent;
112         nd->parent->right = nd->right;
113     }
114     nd->left = 0;
115     nd->right = 0;
116     nd->parent = 0;
117     if (nd != bak)bak->value = nd->value;
118     free(nd);
119 }
120 
121 binary_tree *binary_tree_cretae() {
122     binary_tree *tree = (binary_tree *)malloc(sizeof(binary_tree));
123     if (!tree)return NULL;
124     tree->size = 0;
125     tree->root = NULL;
126     return tree;
127 }
128 
129 void postorder_traversal(node *nd, void visit(node *)) {
130     if (!nd)return;
131     postorder_traversal(nd->left, visit);
132     postorder_traversal(nd->right, visit);
133     visit(nd);
134 }
135 
136 void inorder_traversal(node *nd);
137 
138 void binary_node_destroy(node * nd) {
139     if (!nd)return;
140     nd->left = 0;
141     nd->right = 0;
142     nd->parent = 0;
143     free(nd);
144 }
145 
146 //the problem is that we can't make sure every node was built by `malloc`
147 void binary_tree_destroy(binary_tree *tree) {
148     if (!tree)return;
149     postorder_traversal(tree->root, binary_node_destroy);
150     free(tree);
151 }
152 
153 #endif

 

 

 1 #include "binary_tree.h"
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 typedef int VALUE_TYPE;
 6 
 7 int node_cmp(void *n1, void *n2) {
 8     VALUE_TYPE v1 = *(VALUE_TYPE *) n1;
 9     VALUE_TYPE v2 = *(VALUE_TYPE *) n2;
10 
11     return v1 == v2 ? 0 : (v1 > v2 ? 1 : -1);
12 }
13 
14 void visit(node * nd) {
15     printf("%d\n", *(int) nd->value);
16 }
17 
18 int main() {
19     VALUE_TYPE n1[10];
20     binary_tree *tree = binary_tree_create();
21     assert(tree);
22     int i = 0;
23     for (; i < 10; ++i) {
24         n1[i] = rand();
25         binary_tree_insert(tree, n1 + i);
26     }
27     inorder_traversal(tree);
28 
29     return 0;
30 }

 

 

 

posted @ 2012-09-25 21:06  生无所息  阅读(344)  评论(0编辑  收藏  举报