【算法导论】学习笔记——第12章 二叉搜索树

搜索树数据结构支持多种动态集合操作,包括SEARCH、MINIMUM、MAXIMUM、PREDECESSOR、SUCCESSOR、INSRT和DELETE操作等。基本的搜索树就是一棵二叉搜索树。
12.1 什么是二叉搜索树
1. 二叉搜索树的性质:
设x是二叉搜索树中的一个结点。如果y是x左子树中的一个结点,那么y.key<=x.key。如果y是x右子树中的一个结点,那么y.key>=x.key。
三种遍历时间复杂度是O(n),这是显然的。

12.1-3

 1 void Inorder_Tree_Walk_Nonrecursive_1(Node_t *x) {
 2     stack<Node_t *> S;
 3     bool mid = false;
 4 
 5     printf("Using stack to implement Inorder_Tree_Walk:\n");
 6     S.push(x);
 7     while (!S.empty()) {
 8         if (x->l == NULL || mid) {
 9             printf("%d ", x->key);
10             S.pop();
11             if (x->r == NULL) {
12                 if (S.empty())
13                     break;
14                 x = S.top();
15                 mid = true;
16             } else {
17                 x = x->r;
18                 S.push(x);
19                 mid = false;
20             }
21         } else {
22             x = x->l;
23             S.push(x);
24         }
25     }
26     printf("\n");
27 }
28 void Inorder_Tree_Walk_Nonrecursive_2(Node_t *x) {
29     printf("Using nonstack to implement Inorder_Tree_Walk:\n");
30     Node_t *p = x->p, *y = NULL;
31     bool ret = false, retr = false;
32 
33     while (!retr || y!=p) {
34         if (x->l == NULL || ret) {
35             if (!retr)
36                 printf("%d ", x->key);
37             if (x->r == NULL || retr) {
38                 retr = (x == y->r);
39                 x = y;
40                 y = y->p;
41                 ret = true;
42             } else {
43                 y = x;
44                 x = x->r;
45                 ret = false;
46             }
47         } else {
48             y = x;
49             x = x->l;
50         }
51     }
52     printf("\n");
53 }


12.1-5


12.2 查询二叉搜索树
除了基本的SEARCH外,还包括MINIMUM、MAXIMUM、SUCCESSOR、PREDESSOR等查询操作。

12.2-5


12.2-6


12.2-7


12.2-8


12.2-9


12.3 插入和删除
插入操作比较简,基本二叉树的删除操作需要分类讨论。书中使用了一个子函数TRANSPLANT简化了一些基本操作,使得DELETE过程变得更加清晰。
插入和删除的时间复杂度都是O(h).

12.3-2


12.3-3


12.3-4
不可交换,反例如下图:


12.3-5
中文的《算法导论(第3版)》这道题完全翻译错了,去看了一下英文的搞懂了题目做的。
如提示所示,就是利用后继的属性重新实现插入、删除、查找函数。
求结点p的父节点的思路是先求得p所在子树的最大值,该值所在结点的后继就是p的父节点。 其余
操作均需要利用后继的性质。以插入为例。

 1 void Tree_Insert(Tree_t *t, Node_t *z) {
 2     Node_t *y = NULL;
 3     Node_t *x = t->root;
 4     while (x != NULL) {
 5         y = x;
 6         if (z->key < x->key)
 7             x = x->l;
 8         else
 9             x = x->r;
10     }
11     if (y == NULL) {
12         t->root = z;    // tree t was empty
13         z->succ = NULL;
14     } else if (z->key < y->key) {
15         Node_t *p = ParentOf(y);
16         z.succ = y;
17         p.succ = z;
18     } else {
19         z->succ = y->succ
20         y->succ = z;
21     }
22 }

 12.4 随机构建二叉搜索树
算法导论很多章节都会讲随机算法在数据结构上的随机化。而且都是大段大段的证明,挺犀利。随机算法我个人打算单独花时间学习,因此涉及到的题目都在第二遍读算导的时候再做。
主要证明一棵有n个不同关键字的随机构建的二叉搜索树的期望高度为O(lgn)。主要随机搜索树的很多基本操作的时间复杂度都是O(lgn)。随机化的效率还是很高的,其实可以写个随机数据发生器,测试一下。

posted on 2015-02-14 21:25  Bombe  阅读(768)  评论(0编辑  收藏  举报

导航