《算法导论》笔记 第12章 12.3 插入和删除

【笔记】

插入:从根结点开始,沿树下降。指针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;
    }


对于高度为h的二叉查找树,动态集合操作INSERT和DELETE的运行时间为O(h)。


【练习】


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。

插入时的比较与查找时的比较几乎完全相同,唯一区别为查找时要多检查插入时的结点。


12.3-3 可以这样来对n个数进行排序:先构造一棵包含这些数的二叉查找树(重复应用TREE-INSERT来逐个地插入这些数),然后按中序遍历来输出这些数。这个排序算法的最坏情况和最好情况运行时间怎样?

最坏情况,二叉树退化成链,则构造O(n^2),遍历O(n),运行时间O(n^2)。

最好情况,二叉树平衡,构造O(nlogn),遍历O(n),运行时间O(nlogn)。


12.3-4 假设另有一种数据结构中包含指向二叉查找树中某结点y的指针,并假设用过程TREE-DELETE来删除y的前驱z。这样做会出现哪些问题?如何改写TREE-DELETE来解决这些问题?

有可能指向y的指针已被删除,而y的值已被复制到z。

将y指向父结点子结点的指针改为与z相同,并改变z的父结点指向z的指针与子结点指向父亲的指针。


12.3-5 删除操作是可以交换的吗?说明为什么是的,或给出一个反例。



12.3-6 当TREE-DELETE中的结点z有两个子结点时,可以将其前驱拼接掉。有些人提出了一种公平的策略,即为前驱和后继结点赋予相同的优先级,从而可以得到更好的经验性能。那么,应该如何修改TREE-DELETE来实现这样一种公平的策略?





posted on 2014-04-18 19:51  电子幼体  阅读(1058)  评论(0编辑  收藏  举报

导航