目录
3.1.2 写代码:定义顺序存储的二叉树(数组实现,树的结点从数组下标1开始存储)
3.3.1写代码:使用“双亲表示法”,定义顺序存储的树(以及森林)
3.3.2写代码:使用“孩子表示法”,定义链式存储的树(以及森林)
3.3.3对比:树的孩子表示法存储 v.s. 图的邻接表存储 v.s. 散列表的拉链法 v.s. 基数排序。你发现了什么?
3.3.4写代码:使用“孩子兄弟表示法”,定义链式存储的树(以及森林)
3.3.5自己动手创造,画一个结点总数不少于10的树,并画出对应的“双亲表示法、孩子表示法、孩子兄弟表示法”三种数据结构的示意图
3.3.6自己动手创造,画一个至少包含3棵树的森林,并画出对应的“双亲表示法、孩子表示法、孩子兄弟表示法”三种数据结构的示意图
3.4.1自己动手创造,写10个字符,并给每个字符设置权值,画出构造哈夫曼树的过程
3.4.3基于你所构造的哈夫曼树,写出10个字符的哈夫曼编码
3.4.3用文字描述根据一棵哈夫曼树“译码”的过程(即如何将二进制哈夫曼编码翻译为字符)编辑
3.5.2基于上述定义,实现并查集的基本操作—— 并 Union
3.5.3基于上述定义,实现并查集的基本操作—— 查 Find
3.5.4自己设计一个例子,并查集初始有10个元素,进行若干次Union操作,画出每一次Union后的样子——(Union的优化)
3.5.5自己设计一个例子,基于上一步得到的并查集,进行若干次find操作(每次find会进行“路径压缩”)。画出每次 find (路径压缩)后的样子——(find优化)
3.6.1自己设计一个例子,给出不少于10个关键字序列,按顺序插入一棵初始为空的二叉排序树,画出每一次插入后的样子
3.6.2基于你设计的例子,计算二叉排序树在查找成功和查找失败时的 ASL
3.6.3基于你设计的例子,依次删除不少于4个元素,画出每一次删除之后的样子(需要包含四种删除情况——删一个叶子结点、删一个只有左子树的结点、删一个只有右子树的结点、删一个既有左子树又有右子树的结点)
自己设计一个例子,给出不少于10个关键字序列,按顺序插入一棵初始为空的平衡二叉树,画出每一次插入后的样子(你设计的例子要涵盖LL、RR、LR、RL四种调整平衡的情况)
基于你设计的例子,计算平衡二叉树在查找成功和查找失败时的 ASL
二叉树的性质
3.1.1总结二叉树的度、树高、结点数等属性之间的关系
性质1:在二叉树的第i层上最多有2^(i-1)个结点(i≥1)。
第一层是根结点,只有一个, 第二层有两个。 第三层有四个, 第四层有八个。性质2:深度为k的二叉树至多有2^k-1个结点(k≥1)。
注意这里一定要看清楚,是2k后再减去1,而不是2(k-1)。以前很多同学不能完全理解,这样去记忆,就容易把性质2与性质1给弄混淆了。 深度为k意思就是有k层的二叉树,我们先来看看简单的。 如果有一层,至多1=21-1个结点。 如果有二层,至多1+2=3=22-1个结点。 如果有三层,至多1+2+4=7=23-1个结点。 如果有四层,至多1+2+4+8=15=2^4-1个结点。二叉树的性质3:对任何一棵二叉树,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1
终端结点数其实就是叶子结点数,而一棵二叉树,除了叶子结点外,剩下的就是度为1或2的结点数了,我们设n1为度是1的结点数。则树T结点总数n=n0+n1+n2
终端结点数其实就是叶子结点数,而一棵二叉树,除了叶子结点外,剩下的就是度为1或2的结点数了,我们设n1为度是1的结点数。则树T结点总数n=n0+n1+n2 。二叉树性质4:具有n个结点的完全二叉树的深度为|log(2^n)+1|
由满二叉树的定义我们可以知道,深度为k的满二叉树的结点数n一定是2k-1。因为这是最多的结点个数。那么对于n=2k-1倒推得到满二叉树的深度为k=log2(n+1),比如结点数为15的满二叉树,深度为4。二叉树性质5:如果对一棵有n个结点的完全二叉树(其深度为|log(2^n)+1|)的结点按层序编号(从第一层到第层,每层从左到右),对任一结点i(1<=i<=n),有
1.如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点。
2.如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i。
3.如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1
二叉树的顺序存储和基本操作实现
3.1.2 写代码:定义顺序存储的二叉树(数组实现,树的结点从数组下标1开始存储)
- 为了方便存储,从数组下标1开始存储数据。
- 树的顺序存储通常只用于存储完全二叉树(普通二叉树采用顺序存储的方式跟完全二叉树一样,但是采用这种方式的代价是浪费大量存储空间)
#define MAXSIZE 100
typedef struct treeNode{
elemType value; //结点中元素的值
bool isEmpty; //结点是否为空
}treeNode;
//申明一个长度为MAXSIZE的结构体数组
//由上至下、从左至右的方式存放完全二叉树的各个结点数据
treeNode T[MAXSIZE];
//初始化时,把结点置空
for(int i = 0; i < MAXSIZE; i++) T[i].isEmpty = true;
假设根节点的索引为1(树的结点从数组下标1开始存储)
3.1.3基于上述定义,写一个函数 int findFather ( i ) ,返回结点 i 的父节点编号
3.1.4基于上述定义,写一个函数 int leftChild ( i ) ,返回结点 i 的左孩子编号
3.1.5基于上述定义,写一个函数 int rightChild ( i ) ,返回结点 i 的右孩子编号
写代码:定义顺序存储的二叉树(数组实现,树的结点从数组下标0开始存储)
假设根节点的索引为0(树的结点从数组下标0开始存储)
左子节点的索引会是 2 i + 1 以及右子节点会是 2 i + 2,
而它的父节点(如果有)索引则为(i − 1) / 2。
基于上述定义,写一个函数 int findFather ( i ) ,返回结点 i 的父节点编号
基于上述定义,写一个函数 int leftChild ( i ) ,返回结点 i 的左孩子编号
基于上述定义,写一个函数 int rightChild ( i ) ,返回结点 i 的右孩子编号
实现先/中/后序/层次遍历
先序遍历
中序遍历
后序遍历
层次遍历
二叉树的链式存储
单向链:
typedef struct BiTNode{ elemtype data; struct BiTNode *lchild, *rchild; }BiTNode, *BiTree;
双向链:双亲结点指向孩子结点,孩子结点也指向双亲结点
typedef struct BiTNode{ struct BiTNode *lchild, *rchild, *parent; //parent指针指向该结点的双亲结点 int data; }BiTNode, *BiTree;
树的性质
树(森林)的定义和画图
3.3.1写代码:使用“双亲表示法”,定义顺序存储的树(以及森林)
3.3.2写代码:使用“孩子表示法”,定义链式存储的树(以及森林)
3.3.3对比:树的孩子表示法存储 v.s. 图的邻接表存储 v.s. 散列表的拉链法 v.s. 基数排序。你发现了什么?
(都长这样,具体怎么描述还不知道)
3.3.4写代码:使用“孩子兄弟表示法”,定义链式存储的树(以及森林)
3.3.5自己动手创造,画一个结点总数不少于10的树,并画出对应的“双亲表示法、孩子表示法、孩子兄弟表示法”三种数据结构的示意图
3.3.6自己动手创造,画一个至少包含3棵树的森林,并画出对应的“双亲表示法、孩子表示法、孩子兄弟表示法”三种数据结构的示意图
哈夫曼树的应用
3.4.1自己动手创造,写10个字符,并给每个字符设置权值,画出构造哈夫曼树的过程
3.4.2用文字描述构造哈夫曼树的过程
3.4.3基于你所构造的哈夫曼树,写出10个字符的哈夫曼编码
3.4.3用文字描述根据一棵哈夫曼树“译码”的过程(即如何将二进制哈夫曼编码翻译为字符)
并查集的应用
3.5.1写代码:定义一个并查集(用长度为n的数组实现)
3.5.2基于上述定义,实现并查集的基本操作—— 并 Union
3.5.3基于上述定义,实现并查集的基本操作—— 查 Find
3.5.4自己设计一个例子,并查集初始有10个元素,进行若干次Union操作,画出每一次Union后的样子——(Union的优化)
3.5.5自己设计一个例子,基于上一步得到的并查集,进行若干次find操作(每次find会进行“路径压缩”)。画出每次 find (路径压缩)后的样子——(find优化)
二叉排序树、平衡二叉树的应用题潜在考法 |
3.6.1自己设计一个例子,给出不少于10个关键字序列,按顺序插入一棵初始为空的二叉排序树,画出每一次插入后的样子
关键字序列的顺序不同,构造出的二叉排序树也可能不同
3.6.2基于你设计的例子,计算二叉排序树在查找成功和查找失败时的 ASL
【例题】:
【解答】
3.6.3基于你设计的例子,依次删除不少于4个元素,画出每一次删除之后的样子(需要包含四种删除情况——删一个叶子结点、删一个只有左子树的结点、删一个只有右子树的结点、删一个既有左子树又有右子树的结点)
3.6.4 平衡二叉树
自己设计一个例子,给出不少于10个关键字序列,按顺序插入一棵初始为空的平衡二叉树,画出每一次插入后的样子(你设计的例子要涵盖LL、RR、LR、RL四种调整平衡的情况)
基于你设计的例子,计算平衡二叉树在查找成功和查找失败时的 ASL
【例题】
![]()
![]()
查找成功的平均长度:ASL=(1*1+2*2+3*4)/7 = 17/7
查找失败的平均长度:ASL = (8*3)/8 = 3