【2021-MOOC-浙江大学-陈越、何钦铭-数据结构】树

1.查找

image-20210307110341293

1.1 静态查找

顺序查找

image-20210307110434750

顺序查找算法的时间复杂度为O(n)

二分查找

image-20210307110542964

要查找的元素是存在的

image-20210307110654703

要查找的元素是不存在的

image-20210307110753406

二分查找算法

image-20210307110908091

image-20210307111010446

2.树的定义

image-20210307111143269

怎么判定 树与非树呢?

image-20210307111417302

3.树的基本术语

image-20210307112048694

image-20210307112554292

4.树的表示

儿子-兄弟 表示法

image-20210307112747114

旋转45度,就可以变成二叉树了

image-20210307112808522

5.二叉树

二叉树的定义

image-20210307113100634

image-20210307113135768

怎么判断完美二叉树 和 完全二叉树呢?

img

一棵深度为k且有 2^k - 1 个结点的二叉树称为满二叉树(完美二叉树)

分析:上图中树的深度是4,结点个数是 2^4 - 1 = 15

那么,将编号为15, 14, …, 9的叶子结点从右到左依次拿掉或者拿掉部分,则是一棵完全二叉树,例如,将上图中的编号为15, 14, 13, 12, 11叶子结点都拿掉(从右到左的顺序)

img

下图就不是一棵完全二叉树

img

分析:如果将编号11(K)结点从编号6(E)的左儿子位置移动到编号5(E)的右儿子位置,则变成一棵完全二叉树。

二叉树的几个重要性质

image-20210307115408927

思考题:

有一颗二叉树,其两个儿子的结点个数为15个,一个儿子的结点个数为32个,问该二叉树的叶结点个数是多少?

n2 = 15;n1 = 32;

n0 = n2 - 1 = 16

所以该二叉树的叶结点个数是16

该二叉树总共有 n0 + n1 + 2 * n2 = 0 + 32 + 30 = 62 条边

也可以用 n0 + n1 + n2 = 63 表示该二叉树的总结点树,总边数 = 总结点数 - 1 = 62

二叉树基本操作

image-20210307120455001

思考题

1、如果一个完全二叉树最底下一层为第六层(根为第一层)且该层共有8个叶结点,那么该完全二叉树共有多少个结点?

解析:

完全二叉树,除最后一层可以不满外,其他各层都必须是满的

前五层的结点个数是:2^5 - 1 = 31

加上最后一层 8 个结点

总共是 31 + 8 = 39

2、若有一二叉树的总结点数为98,只有一个儿子的结点数为48,则该树的叶结点数是多少?

解析:这样的树是不存在的,二叉树的总结点树是n0 + n1 + n2 = 98,又因为n1 = 48,

所以n0 + n2 = 50,n0 = n2 - 1,代入得n2 = 51/2,故这样的树是不存在的

3、设深度为d(只有一个根结点时,d为1)的二叉树只有度为0和2的结点,则此类二叉树的结点数至少为2d-1?

解析:正确。考虑结点最少的情况:

image-20210307133157663

可以看到,该树每一级都只有一个节点有两个子节点。深度为d,即除了第一级,其余每一级都有2个节点,故总共2d-1个节点。

二叉树的存储结构

顺序存储结构

image-20210307133448141

image-20210307133548272

链式存储

image-20210307133802478

二叉树遍历

先序遍历

image-20210307134852633

中序遍历

image-20210307134746381

后序遍历

image-20210307134815394

总结

image-20210307135626760

二叉树的递归遍历

void InorderTraversal( BinTree BT ) //中序遍历
{
    if( BT ) {
        InorderTraversal( BT->Left );
        /* 此处假设对BT结点的访问就是打印数据 */
        printf("%d ", BT->Data); /* 假设数据为整型 */
        InorderTraversal( BT->Right );
    }
}

void PreorderTraversal( BinTree BT ) //前序遍历
{
    if( BT ) {
        printf("%d ", BT->Data );
        PreorderTraversal( BT->Left );
        PreorderTraversal( BT->Right );
    }
}

void PostorderTraversal( BinTree BT ) //后序遍历
{
    if( BT ) {
        PostorderTraversal( BT->Left );
        PostorderTraversal( BT->Right );
        printf("%d ", BT->Data);
    }
}

void LevelorderTraversal ( BinTree BT )
{ 
    Queue Q; 
    BinTree T;

    if ( !BT ) return; /* 若是空树则直接返回 */
    
    Q = CreatQueue(); /* 创建空队列Q */
    AddQ( Q, BT );
    while ( !IsEmpty(Q) ) {
        T = DeleteQ( Q );
        printf("%d ", T->Data); /* 访问取出队列的结点 */
        if ( T->Left )   AddQ( Q, T->Left );
        if ( T->Right )  AddQ( Q, T->Right );
    }
}

二叉树的非递归遍历

基本思路:使用堆栈

中序遍历非递归算法

image-20210307141944235

先序遍历非递归算法

无图,直接上代码

void InOrderTraversal(BinTree BT) {
    BinTree T = BT;
    Stack S = CreateStack(MaxSize);
    while (T || !IsEmpty(S)) { //如果二叉树存在,并且堆栈不为空
        while (T) { //先打印该结点,并压入堆栈,再向左一直遍历
            printf("%5d", T->Data);
            Push(S, T);
            T = T->Left;
        }
        if (!IsEmpty(S)) {
            T = Pop(S); //将结点弹出堆栈
            T = T->Right; //将该结点向右遍历
        }
    }
}

层序遍历

image-20210307163105612

image-20210307163156260

遍历二叉树的应用

image-20210307164430545

image-20210307164449337

image-20210307164507892

由两种遍历序列确定二叉树

注意:必须要有中序遍历,才能确定二叉树

image-20210307165421045

image-20210307165511786

先由先序序列的第一个元素,确定根结点

再把根结点放到中序序列,确定左子树有哪些元素

image-20210307165743484
image-20210307170656159
image-20210307170624774

思考题

1、假定只有四个结点A、B、C、D的二叉树,其前序遍历序列为ABCD,则下面哪个序列是不可能的中序遍历序列?

A、ABCD

B、ACDB

C、DCBA

D、DABC

解析:

选项A有可能:img

选项B有可能:img

选项C有可能:img

选项D:首先根据中序,A在中间,所以左子树的节点只有一个D,而右子树节点是B和C,但问题是根据前序遍历的规则,打印出A以后应该接着打印B,但是若D在左子树,B在右子树,则前序遍历不可能先打印出B再打印出D,所以这种情况不可能

2、对于二叉树,如果其中序遍历结果与前序遍历结果一样,那么可以断定该二叉树

解析:所有结点都没有左儿子

3、已知一二叉树的后序和中序遍历的结果分别是FDEBGCA 和FDBEACG,那么该二叉树的前序遍历结果是什么?

在这里插入图片描述
  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿小羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值