数据结构专升本资料第五周Word下载.docx
《数据结构专升本资料第五周Word下载.docx》由会员分享,可在线阅读,更多相关《数据结构专升本资料第五周Word下载.docx(9页珍藏版)》请在冰豆网上搜索。
![数据结构专升本资料第五周Word下载.docx](https://file1.bdocx.com/fileroot1/2022-11/25/fe2d8116-4901-4fd7-98c2-fda85f08083c/fe2d8116-4901-4fd7-98c2-fda85f08083c1.gif)
否则其左孩子LCHILD(i)是结点2i。
如果2i+1>n,则结点i无右孩子;
否则其右孩子RCHILD(i)是结点2i+1。
如果i为奇数且不为1,则其左兄弟的编号是i-1;
否则,无左兄弟。
如果i为偶数且小于n,则其右兄弟的编号是i+1;
否则,无右兄弟。
四、二叉树的存储结构
1、顺序存储结构
就是用一组连续的存储单元来存放二叉树的各结点信息。
顺序存储结构可以用一个一维数组来顺序存储二叉树中所有结点的数据信息,并通过数组元素的下标关系来反映完全二叉树中结点间的逻辑关系。
一般的二叉树也必须按完全二叉树的形式来存储,这将造成存贮的浪费。
在最坏的情况下,一个深度为k且只有k个结点的单支树(树中无度为2的结点)却需2k-1个存储分量。
2、链式存储结构
二叉树的链式存储结构是用链来建立树中结点之间的关系,二叉树的这种链式存储结构我们通常称为二叉链表。
在含有n个结点的二叉链表中有n+1个空链域。
6.3遍历二叉树
遍历(Traversal):
是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。
从二叉树的递归定义可知,二叉树是由三个基本单元组成:
根结点、左子树和右子树。
因此,若能依次遍历这三部分,便是遍历了整个二叉树。
假如以L,D,R分别表示遍历左子树、访问根结点和遍历右子树,则可有DLR、LDR、LRD、DRL、RDL、RLD六种遍历二叉树的方案。
若限定先左后右,则只有前三种情况,分别称之为前序遍历,中序遍历和后序遍历。
●前序遍历
前序遍历(PreorderTraversal)亦称先序遍历,定义为:
若二叉树为空,则空操作;
否则,执行下列步骤:
(1)访问根结点
(2)遍历左子树
(3)遍历右子树
●中序遍历
中序遍历(InorderTraversal)定义为:
(1)遍历左子树
(2)访问根结点
●后序遍历
后序遍历(PostorderTraversal)定义为:
若二叉树为空,则空操作;
(1)遍历左子树
(2)遍历右子树
(3)访问根结点
对二叉树进行遍历还可以从上到下,从左到右按层次进行。
/*前序遍历二叉树*/
voidPreorder(BinTreeT)
{
if(T)
{
printf("
%c"
T->
data);
/*访问结点*/
Preorder(T->
lchild);
rchild);
}
}
/*中序遍历二叉树*/
voidInorder(BinTreeT)
Inorder(T->
/*后序遍历二叉树*/
voidPostorder(BinTreeT)
Postorder(T->
●构造二叉链表
基于先序遍历构造二叉链表算法。
/*构造二叉链表*/
voidCreateBinTree(BinTree*T)
charch;
if((ch=getchar())=='
'
)
*T=NULL;
else
{/*读入非空格*/
*T=(BinTNode*)malloc(sizeof(BinTNode));
/*生成结点*/
(*T)->
data=ch;
CreateBinTree(&
(*T)->
lchild);
/*构造左子树*/
rchild);
/*构造右子树*/
给定结点的前序、中序或后序、中序序列,可唯一的确定一棵二叉树
⏹利用前序遍历、中序遍历构造二叉树:
已知结点的前序序列和中序序列分别为:
ABDGHCEFI和GDHBAECIF
⏹利用中序遍历、后序遍历构造二叉树:
已知结点的中序序列和后序序列分别为:
BDCEAFHG和DECBHGFA
6.4树和森林
一、树的存储结构
1、双亲链表表示法
树中除了根结点外,树中每个结点有且仅有一个双亲结点。
利用这一性质,可在存储结点信息的同时,为每个结点附设一个指向其双亲的指针parent,就可唯一地表示任何一棵树。
2、孩子链表表示法
●孩子链表表示法
为树中每个结点设置一个孩子链表,并将这些结点及相应的孩子链表的头指针存放在一个向量中。
●双亲孩子链表表示法
将双亲链表表示法与孩子链表表示法结合起来,形成双亲孩子链表表示法。
3、孩子兄弟链表表示法
在存储结点信息的同时,附加两个分别指向该结点最左孩子和右邻兄弟的指针域leftmostchild和rightsibling。
二、森林与二叉树的转换
1、树转换为二叉树
在所有兄弟结点之间加一连线;
对每个结点,除了保留与其长子的连线外,去掉该结点与其它孩子的连线;
以树的根结点为轴心,将整棵树顺时针转动一定的角度,使之结构层次分明。
2、森林转换为二叉树
先将森林中的每棵树变为二叉树;
将各二叉树的根结点视为兄弟从左至右连在一起,就形成了一棵二叉树。
3、二叉树到树、森林的转换
若某结点是其双亲的左孩子,则把该结点的右孩子、右孩子的右孩子……都与该结点的双亲结点用线连起来;
删掉原二叉树中所有的双亲结点与右孩子结点的连线;
整理上述两步所得到的树或森林,使之结构层次分明。
三、树和森林的遍历
1、树的遍历
●前序(先根)遍历树
步骤:
(1)访问根结点;
(2)按从左至右的次序前序遍历根的各棵子树。
前序遍历树和前序遍历与该树相对应的二叉树具有相同的遍历结果,即它们的前序遍历是相同的。
●后序遍历树
(1)按从左至右的次序后序遍历根的各棵子树;
(2)访问根结点。
后序遍历树和中序遍历与该树相对应的二叉树具有相同的遍历结果。
以二叉链表作树的存储结构时,树的先序遍历和后序遍历可借用二叉树的先序和中序遍历的算法实现之。
2、森林的遍历
●前序遍历森林
(1)访问森林中第一棵树的根结点;
(2)前序遍历森林中第一棵树的根结点的各子树;
(3)前序遍历森林中除第一棵树外其余各树所构成的森林。
前序遍历森林和前序遍历与该森林相对应的二叉树具有相同的遍历结果。
●后序遍历森林
(1)后序遍历森林中第一棵树的根结点的各子树;
(2)访问森林中第一棵树的根结点;
(3)后序遍历森林中除第一棵树外其余各树所构成的森林。
后序遍历森林和中序遍历与该树相对应的二叉树具有相同的遍历结果。
6.5Huffman树极其应用
一、最优二叉树(Huffman树)
1、基本术语
路径(Path)和路径长度:
从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上的分支数目称做路径长度。
树的路径长度:
从树根到每一结点的路径长度之和。
树的带权路径长度(WeightedPathLengthofTree):
树中所有叶结点的带权路径长度之和。
记作:
WPL=W1*L1+W2*L2+…+Wn*Ln.其中:
Wi表示权,Li表示路径长度
Huffman树:
又称最优二叉树,它是n个带叶结点构成的所有二叉树中,带权路径长度WPL最小的二叉树。
2、构造Huffman树
1)、Huffman算法
(1)根据给定的n个权值{w1,w2,…,wn}构成n棵二叉树的集合F={T1,T2,…,Tn},其中每棵二叉树Ti中只有一个带权为wi的根结点,其左右子树均空。
(2)在F中选取两棵根结点的权值最小的树作为左右子树构成一棵新的二叉树,且置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。
(3)在F中删除这两棵树,同时将新得到的二叉树加入F中。
(4)重复
(2)和(3),直到F只含一棵树为止。
这棵树便是Huffman树。
⏹例:
以权值分别为7,5,2,4的结点a、b、c、d构造Huffman树。
二、Huffman编码
可利用Huffman树构造用于通信的二进制编码称为Huffman编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定指向左子树根的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是Huffman编码。
作业:
intnodes(BinTreeT){
intnum1,num2;
if(T==Null)return(0);
elseif(T->
lchild==NULL&
&
T->
rchild==NULL)return
(1);
else
{num1=nodes(T->
num2=nodes(T->
return(num1+num2+1);
intleafs(BinTreeT){
{num1=leafs(T->
num2=leafs(T->
return(num1+num2);
BinTreeswap(BinTreeT){
BinTreet,t1,t2;
if(T==Null)t=NULL;
{t=(BinTree)malloc(sizeof(BinTNode))
t->
data=T->
data;
t1=swap(T->
t2=swap(T->
lchild=t2;
rchild=t1;
return(t);