插入:从根结点开始,沿树降低。指针x跟踪这条路径,而y始终指向x的父结点。根据key[z]与key[x]的比较结果,决定向左向右转。直到x成为NIL为止。这个NIL所占位置及咱们想插入z的地方,y即为z的父结点。算法
删除:以指向z的指针为参数,考虑三种状况。若z没有子女,则修改其父结点p[z],是NIL为其子女;若是结点z只有一个子女,则能够经过在其子结点与父结点之间创建一条链来删除z。若是结点z有两个子女,先删除z的后继y(它没有左子女),再用y的内容来替代z的内容。数据结构
void treeInsert(NODE *z) { NODE *y = NULL; NODE *x = root; while (x != NULL) { y = x; if (z->key < x->key) x = x->l; else x = x->r; } z->p = y; if (y == NULL) root = z; else { if (z->key < y->key) y->l = z; else y->r = z; } } NODE* treeDelete(NODE* z) { NODE *y, *x; if (z->l == NULL || z->r ==NULL) y = z; else y = treeSuccessor(z); if (y->l != NULL) x = y->l; else x = y->r; if (x != NULL) x->p = y->p; if (y->p == NULL) root = x; else { if (y == y->p->l) y->p->l = x; else y->p->r = x; } if (y != z) { z->key = y->key; } return y; }
12.3-1 给出过程TREE-INSERT的一个递归版本。性能
void insert(NODE *rt, NODE *z,NODE *pa = NULL) { if (rt == NULL) { z->p = pa; z->l = z->r = NULL; if (pa == NULL) root = z; else { if (z->key < pa->key) pa->l = z; else pa->r = z; } return; } if (z->key < rt->key) insert(rt->l,z,rt); else insert(rt->r,z,rt); }
12.3-2 假设咱们经过反复插入不一样的关键字的作法来构造一棵二叉查找树。论证:为在树中查找一个关键字,所检查的结点数等于插入该关键字时所检查的结点数+1。指针
插入时的比较与查找时的比较几乎彻底相同,惟一区别为查找时要多检查插入时的结点。code
12.3-3 能够这样来对n个数进行排序:先构造一棵包含这些数的二叉查找树(重复应用TREE-INSERT来逐个地插入这些数),而后按中序遍从来输出这些数。这个排序算法的最坏状况和最好状况运行时间怎样?blog
最坏状况,二叉树退化成链,则构造O(n^2),遍历O(n),运行时间O(n^2)。排序
最好状况,二叉树平衡,构造O(nlogn),遍历O(n),运行时间O(nlogn)。递归
12.3-4 假设另有一种数据结构中包含指向二叉查找树中某结点y的指针,并假设用过程TREE-DELETE来删除y的前驱z。这样作会出现哪些问题?如何改写TREE-DELETE来解决这些问题?ip
有可能指向y的指针已被删除,而y的值已被复制到z。class
将y指向父结点子结点的指针改成与z相同,并改变z的父结点指向z的指针与子结点指向父亲的指针。
12.3-5 删除操做是能够交换的吗?说明为何是的,或给出一个反例。
12.3-6 当TREE-DELETE中的结点z有两个子结点时,能够将其前驱拼接掉。有些人提出了一种公平的策略,即为前驱和后继结点赋予相同的优先级,从而能够获得更好的经验性能。那么,应该如何修改TREE-DELETE来实现这样一种公平的策略?