20162309《程序设计与设计结构》第九周学习总结

学号 20162309《程序设计与数据结构》第9周学习总结

教材学习内容总结

一、关于二叉查找树:二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。
定义:二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值。
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值。
(3)左、右子树也分别为二叉排序树。

查找方法:
步骤:
二叉树
若根结点的关键字值等于查找的关键字,成功。
否则,若小于根结点的关键字值,递归查左子树。
若大于根结点的关键字值,递归查右子树。
若子树为空,查找不成功。

插入删除方法:
与次优二叉树相对,二叉排序树是一种动态树表。其特点是:树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字等于给定值的结点时再进行插入。新插入的结点一定是一个新添加的叶子结点,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。

关于二叉查找树的插入算法:
首先执行查找算法,找出被插结点的父亲结点。
判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
若二叉树为空。则首先单独生成根结点。
注意:新插入的结点总是叶子结点。

代码实现:
//在二叉排序树中插入查找关键字key
BiTree* InsertBST(BiTree *t,int key)
{
    if (t == NULL)
    {
        t = new BiTree();
        t->lchild = t->rchild = NULL;
        t->data = key;
        return t;
    }
 
    if (key < t->data) 
        t->lchild = InsertBST(t->lchild, key);
    else
        t->rchild = InsertBST(t->rchild, key);
 
    return t;
}
关键字key建立后,对查找方法有很大的帮助,对查找最大最小值可以简便地实现。

在上周的实验,使用二叉查找树实现findMax和findMin方法,在变量定义处设关键字key会便于实现方法。

结点删除:
在在二叉排序树删去一个结点,分三种情况:
1.若p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则可以直接删除此子结点。
2.若
p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点f的左子树(当p是左子树)或右子树(当p是右子树)即可,作此修改也不破坏二叉排序树的特性。
3.若
p结点的左子树和右子树均不空。在删去p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:
其一是令
p的左子树为f的左/右(依p是f的左子树还是右子树而定)子树,s为p左子树的最右下的结点,而p的右子树为s的右子树;
其二是令
p的直接前驱(或直接后继)替代p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让f的左子树(如果有的话)成为p左子树的最左下结点(如果有的话),再让f成为*p的左右结点的父节点。

结点删除的代码实现:
需要使用递归的方法来实现:
private void deleteNode(BinarySortTree p)
{
    //TODOAuto-generatedmethodstub
    if(p!=null)
    {
        //如果结点有左子树
        /*1。若p有左子树,找到其左子树的最右边的叶子结点r,用该叶子结点r来替代p,把r的左孩子
        作为r的父亲的右孩子。
        2。若p没有左子树,直接用p的右孩子取代它。
        */
        if(p.lChild!=null)
        {
            BinarySortTree r=p.lChild;
            BinarySortTree prev=p.lChild;
                while(r.rChild!=null)
               {
                    prev=r;
                    r=r.rChild;
                }
                p.data=r.data;
            //若r不是p的左子树,p的左子树不变,r的左子树作为r的父结点的右孩子结点
            if(prev!=r)
            {
                prev.rChild=r.lChild;
             }
            else
            {
             //若r是p的左子树,则p的左子树指向r的左子树
            p.lChild=r.lChild;
            }
        }
        else
        {
            p=p.rChild;
        }
    }
}
关于二叉查找树的性能分析:
每个结点的C(i)为该结点的层次数。最坏情况下,当先后插入的关键字有序时,构成的二叉排序树蜕变为单支树,树的深度为其平均查找长度(n+1)/2(和顺序查找相同),最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和log 2 (n)成正比。

二、关于堆
堆与栈进行对比:
栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

关于最大堆:
最大堆是堆的两种形式之一。
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆,又称最大堆(大顶堆)。
大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值。

教材学习中的问题和解决过程

  • 问题1:对于一个二叉平衡树,左右旋转方法的具体实现过程。
  • 问题1解决方案:平衡二叉查找树具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。常用算法有红黑树、AVL、Treap、伸展树等。在平衡二叉搜索树中,我们可以看到,其高度一般都良好地维持在O(log(n)),大大降低了操作的时间复杂度。为什么要引入旋转?因为在建立平衡二叉树,插入二叉树节点的时候,如果发现平衡因子不是-1,0,1的时候就会进行调整,而平衡因子是判断一个二叉树的每层是否平衡的数据
    在进程调制的时候就会有左单旋,右单旋,左右旋转,右左旋转,通过这四种旋转来使得不管插入多少数据都可以保持平衡二叉树的特点
    具体方法:



代码调试中的问题和解决过程

  • 问题1:哈夫曼树的方法实现:解码方法decode
  • 问题1解决方案:可以先讲已经译码的0/1序列输入进数组,设定一个临时变量,并将A、B、C、D所对应的0\1序列值输入,轮流从数组中取出数进行比对,如果比对成功就输出对应的变量,如果比对失败就和下一个值进行组合来循环比对,最后返回结果。

代码托管

https://gitee.com/xingtianyue/events
(statistics.sh脚本的运行结果截图)

上周考试错题总结

  • 错题1及原因,理解情况

  • 错题2及原因,理解情况

-错题3及原因,理解情况

  • ...

结对及互评

本周与结对伙伴20162313苑洪铭共同学习了关于二叉查找树和堆的相关知识,并完成了课上实验的相关内容。

本周结对学习情况

- [结对同学学号1](博客链接)
- 结对照片
- 结对学习内容
    - 二叉查找树
    - 堆/最大堆
    - ...

其他(感悟、思考等,可选)

关于平衡二叉树的补充
伸展树:伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由Daniel Sleator和Robert Tarjan创造。它的优势在于不需要记录用于平衡树的冗余信息。在伸展树上的一般操作都基于伸展操作。
AVL:AVL是最先发明的自平衡二叉查找树算法。在AVL中任何节点的两个儿子子树的高度最大差别为一,所以它也被称为高度平衡树,n个结点的AVL树最大深度约1.44log2n。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
xxx
xxx

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第七周 200/200 4/4 20/20
第八周 300/500 2/2 18/38
第九周 500/1000 1/2 22/60
第十周 300/1300 0/9 30/90
  • 计划学习时间:16小时

  • 实际学习时间:16小时

posted @ 2017-11-05 19:00  邢天岳  阅读(228)  评论(0编辑  收藏  举报