二叉树存储表示和遍历

合集下载

汇编二叉树的遍历

汇编二叉树的遍历

一、软件背景介绍树的遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。

访问结点所做的操作依赖于具体的应用问题。

遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算的基础。

从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。

因此,在任一给定结点上,可以按某种次序执行三个操作:⑴访问结点本身(N),⑵遍历该结点的左子树(L),⑶遍历该结点的右子树(R)。

所以二叉树的遍历也包括三种:先序遍历,中序遍历,和后序遍历。

图1:程序显示结果二、核心算法思想二叉树的存储:在内存中为数组binary分配一个大小为63(0,0,0)的存储空间,所有数组元素初始化为0,用来存放二叉树。

每三个连续的数组地址存放一个节点:第一个地址存放节点的值;第二个地址存放有无左孩子的信息,如果有则将其置为1,否则为0;第三个地址存放有无右孩子的信息,如果有则将其置为1,否则为0。

将binary的首址偏移赋给si,cx初始化为0用来计数,用回车代表输入的为空,即没有输入。

按先根存储的方式来存二叉树,首先输入一个字符,若为回车则退出程序,否则cx+3且调用函数root。

然后该结点若有左孩子,调用leftchild函数,置该结点标志即第二个地址中的0为1,该结点进栈,再存储左孩子结点,递归调用左右,若没有左孩子,看有没有右孩子,若有,则调用rightchild置该结点标志位即上第三个地址中的0为1,然后该结点进栈,再存储右孩子结点,递归调用左右,整个用cx计数,数组binary中每多一个节点,cx加3。

此存储方式正好符合先序遍历思想。

遍历二叉树的执行踪迹:三种递归遍历算法的搜索路线相同,具体线路为:从根结点出发,逆时针沿着二叉树外缘移动,对每个结点均途径三次,最后回到根结点。

二叉树的遍历有常用的三种方法,分别是:先根次序、中根次序、后根次序。

为了验证这几种遍历算法的区别,本次的实验将会实现所有的算法。

二叉树的性质及其遍历

二叉树的性质及其遍历
12.2 二叉树的遍历 12.3 二叉树的存储结构
12.3.1 顺序存储结构 12.3.2 链式存储
•二叉树的性质及其遍历
12.1 二叉树的基本性质
定理 1:满二叉树第i层上恰好有2i-1个结点 (i≥1).
证:使用归纳法。i=1时,结论显然成立。设i=k时结 论成立,则考虑i=k+1的情形。由于(k+1)层上结点 是k层上结点的儿子,而且满二叉树每个非叶子结 点恰好有两个儿子,故(k+1)层上结点个数为k层上 结点个数的2倍,即2·2k-1 = 2k = 2(k+1)-1. 这表明, i=k+1时结论也成立。由归纳法原理,结论对任意 的k都成立,证毕。
x的相对地址x的编号x的父亲/儿子的编 号(性质7) x的父亲/儿子的相对地址。
•二叉树的性质及其遍历
至于结点的相对地址与编号之间的换算,有下列关系: 结点相对地址 = (结点编号 – 1)×每个结点所
占单元数目
a
b
f
cegh d
1 2 34 56 7 8 a b f ce g h d …
图 12-2 顺序二叉树的顺序存储
•二叉树的性质及其遍历
12.1.7 定理7 若对一棵有n个结点的顺序二叉树的结点按层序 编号,则对任一结点i(1≤i≤n),有(1)若i=1, 则结点i是根, 无父亲;若i〉1,则其父亲是结点i/2。(2)若2i>n,则结点i 无左儿子(从而也无右儿子,为叶子);否则i的左儿子是结 点2i。(3)若2i+1>n,则结点i无右儿子;否则右儿子是结点 2i+1。
12.3.1顺序存储结构
(一) 顺序二叉树的顺序存储结构
这种存储结构是按结点的层序编号的次序,将 结点存储在一片连续存储区域内。由定理 7知, 对顺序二叉树,若已知结点的层序编号,则可推 算出它的父亲和儿子的编号,所以,在这种存储 结构中,很容易根据结点的相对地址计算出它的 父亲和儿子的相对地址,方法是:

二叉树的存储结构及基本操作

二叉树的存储结构及基本操作

二叉树的存储结构及基本操作二叉树是一种常见的数据结构,广泛应用于计算机科学领域。

二叉树具有其独特的存储结构和基本操作,下面将详细介绍。

一、二叉树的存储结构二叉树的存储结构通常有两种形式:顺序存储和链式存储。

1. 顺序存储顺序存储是将二叉树中的所有元素按照一定的顺序存储在一段连续的内存单元中,通常采用数组来表示。

对于任意一个节点i,其左孩子节点的位置为2*i+1,右孩子节点的位置为2*i+2。

这种存储方式的优点是访问速度快,但需要预先确定节点总数,且不易于插入和删除操作。

2. 链式存储链式存储是采用指针的方式将二叉树的节点链接起来。

每个节点包含数据元素以及指向左孩子节点和右孩子节点的指针。

链式存储方式的优点是易于插入和删除操作,但访问速度较慢。

二、二叉树的基本操作1. 创建二叉树创建二叉树的过程就是将数据元素按照一定的顺序插入到二叉树中。

对于顺序存储的二叉树,需要预先分配内存空间;对于链式存储的二叉树,可以直接创建节点对象并链接起来。

2. 遍历二叉树遍历二叉树是指按照某种规律访问二叉树中的所有节点,通常有前序遍历、中序遍历和后序遍历三种方式。

前序遍历的顺序是根节点-左孩子节点-右孩子节点;中序遍历的顺序是左孩子节点-根节点-右孩子节点;后序遍历的顺序是左孩子节点-右孩子节点-根节点。

对于顺序存储的二叉树,可以采用循环结构实现遍历;对于链式存储的二叉树,需要使用指针逐个访问节点。

3. 查找元素在二叉树中查找元素,需要根据一定的规则搜索所有节点,直到找到目标元素或搜索范围为空。

对于顺序存储的二叉树,可以采用线性查找算法;对于链式存储的二叉树,可以采用深度优先搜索或广度优先搜索算法。

4. 插入元素在二叉树中插入元素需要遵循一定的规则,保证二叉树的性质。

对于顺序存储的二叉树,插入操作需要移动大量元素;对于链式存储的二叉树,插入操作相对简单,只需修改指针即可。

5. 删除元素在二叉树中删除元素同样需要遵循一定的规则,保证二叉树的性质。

数据结构实验报告 二叉树

数据结构实验报告 二叉树

数据结构实验报告二叉树数据结构实验报告:二叉树引言:数据结构是计算机科学中的重要基础,它为我们提供了存储和组织数据的方式。

二叉树作为一种常见的数据结构,广泛应用于各个领域。

本次实验旨在通过实践,深入理解二叉树的概念、性质和操作。

一、二叉树的定义与性质1.1 定义二叉树是一种特殊的树结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。

二叉树可以为空树,也可以是由根节点和左右子树组成的非空树。

1.2 基本性质(1)每个节点最多有两个子节点;(2)左子树和右子树是有顺序的,不能颠倒;(3)二叉树的子树仍然是二叉树。

二、二叉树的遍历2.1 前序遍历前序遍历是指首先访问根节点,然后按照先左后右的顺序遍历左右子树。

在实际应用中,前序遍历常用于复制一颗二叉树或创建二叉树的副本。

2.2 中序遍历中序遍历是指按照先左后根再右的顺序遍历二叉树。

中序遍历的结果是一个有序序列,因此在二叉搜索树中特别有用。

2.3 后序遍历后序遍历是指按照先左后右再根的顺序遍历二叉树。

后序遍历常用于计算二叉树的表达式或释放二叉树的内存。

三、二叉树的实现与应用3.1 二叉树的存储结构二叉树的存储可以使用链式存储或顺序存储。

链式存储使用节点指针连接各个节点,而顺序存储则使用数组来表示二叉树。

3.2 二叉树的应用(1)二叉搜索树:二叉搜索树是一种特殊的二叉树,它的左子树上的节点都小于根节点,右子树上的节点都大于根节点。

二叉搜索树常用于实现查找、插入和删除等操作。

(2)堆:堆是一种特殊的二叉树,它满足堆序性质。

堆常用于实现优先队列,如操作系统中的进程调度。

(3)哈夫曼树:哈夫曼树是一种带权路径最短的二叉树,常用于数据压缩和编码。

四、实验结果与总结通过本次实验,我成功实现了二叉树的基本操作,包括创建二叉树、遍历二叉树和查找节点等。

在实践中,我进一步理解了二叉树的定义、性质和应用。

二叉树作为一种重要的数据结构,在计算机科学中有着广泛的应用,对于提高算法效率和解决实际问题具有重要意义。

二叉树的顺序存储及基本操作

二叉树的顺序存储及基本操作

二叉树的顺序存储及基本操作二叉树的顺序存储是将树中的节点按照完全二叉树从上到下、从左到右的顺序依次存储到一个一维数组中,采用这种方式存储的二叉树也被称为完全二叉树。

一、在使用顺序存储方式时,可以使用以下公式来计算一个节点的左右子节点和父节点:
1. 左子节点:2i+1(i为父节点的在数组中的下标)
2. 右子节点:2i+2
3. 父节点:(i-1)/2(i为子节点在数组中的下标)
二、基本操作:
1. 创建二叉树:按照上述公式将节点存储到数组中。

2. 遍历二叉树:可采用递归或非递归方式,进行前序、中序、后序、层次遍历。

3. 插入节点:先将节点插入到数组末尾,然后通过比较节点和其父节点的大小,进行上浮操作直到满足二叉树的性质。

4. 删除节点:先将待删除节点和最后一个节点交换位置,然后通过比较交换后的节点和其父节点的大小,进行下沉操作直到满足二
叉树的性质。

5. 查找节点:根据节点值进行查找,可采用递归或非递归方式。

6. 修改节点:根据节点值进行查找,然后进行修改操作。

数据结构之二叉树(BinaryTree)

数据结构之二叉树(BinaryTree)

数据结构之⼆叉树(BinaryTree)⽬录导读 ⼆叉树是⼀种很常见的数据结构,但要注意的是,⼆叉树并不是树的特殊情况,⼆叉树与树是两种不⼀样的数据结构。

⽬录 ⼀、⼆叉树的定义 ⼆、⼆叉树为何不是特殊的树 三、⼆叉树的五种基本形态 四、⼆叉树相关术语 五、⼆叉树的主要性质(6个) 六、⼆叉树的存储结构(2种) 七、⼆叉树的遍历算法(4种) ⼋、⼆叉树的基本应⽤:⼆叉排序树、平衡⼆叉树、赫夫曼树及赫夫曼编码⼀、⼆叉树的定义 如果你知道树的定义(有限个结点组成的具有层次关系的集合),那么就很好理解⼆叉树了。

定义:⼆叉树是n(n≥0)个结点的有限集,⼆叉树是每个结点最多有两个⼦树的树结构,它由⼀个根结点及左⼦树和右⼦树组成。

(这⾥的左⼦树和右⼦树也是⼆叉树)。

值得注意的是,⼆叉树和“度⾄多为2的有序树”⼏乎⼀样,但,⼆叉树不是树的特殊情形。

具体分析如下⼆、⼆叉树为何不是特殊的树 1、⼆叉树与⽆序树不同 ⼆叉树的⼦树有左右之分,不能颠倒。

⽆序树的⼦树⽆左右之分。

2、⼆叉树与有序树也不同(关键) 当有序树有两个⼦树时,确实可以看做⼀颗⼆叉树,但当只有⼀个⼦树时,就没有了左右之分,如图所⽰:三、⼆叉树的五种基本状态四、⼆叉树相关术语是满⼆叉树;⽽国际定义为,不存在度为1的结点,即结点的度要么为2要么为0,这样的⼆叉树就称为满⼆叉树。

这两种概念完全不同,既然在国内,我们就默认第⼀种定义就好)。

完全⼆叉树:如果将⼀颗深度为K的⼆叉树按从上到下、从左到右的顺序进⾏编号,如果各结点的编号与深度为K的满⼆叉树相同位置的编号完全对应,那么这就是⼀颗完全⼆叉树。

如图所⽰:五、⼆叉树的主要性质 ⼆叉树的性质是基于它的结构⽽得来的,这些性质不必死记,使⽤到再查询或者⾃⼰根据⼆叉树结构进⾏推理即可。

性质1:⾮空⼆叉树的叶⼦结点数等于双分⽀结点数加1。

证明:设⼆叉树的叶⼦结点数为X,单分⽀结点数为Y,双分⽀结点数为Z。

数据结构-二叉树的存储结构和遍历


return(p); }
建立二叉树
以字符串的形式“根左子树右子树”定义 一棵二叉树
1)空树 2)只含一个根 结点的二叉树 A 3)
B C
A
以空白字符“ ”表示
以字符串“A ”表示
D
以下列字符串表示 AB C D
建立二叉树 A B C C
T
A ^ B ^ C^ ^ D^
D
建立二叉树
Status CreateBiTree(BiTree &T) {
1 if (!T) return;
2 Inorder(T->lchild, visit); // 遍历左子树 3 visit(T->data); } // 访问结点 4 Inorder(T->rchild, visit); // 遍历右子树
后序(根)遍历
若二叉树为空树,则空操

左 子树
右 子树
作;否则, (1)后序遍历左子树; (2)后序遍历右子树; (3)访问根结点。
统计二叉树中结点的个数
遍历访问了每个结点一次且仅一次
设置一个全局变量count=0
将visit改为:count++
统计二叉树中结点的个数
void PreOrder (BiTree T){ if (! T ) return; count++; Preorder( T->lchild); Preorder( T->rchild); } void Preorder (BiTree T,void( *visit)(TElemType& e)) { // 先序遍历二叉树 1 if (!T) return; 2 visit(T->data); // 访问结点 3 Preorder(T->lchild, visit); // 遍历左子树 4 Preorder(T->rchild, visit);// 遍历右子树 }

数据结构入门-树的遍历以及二叉树的创建

数据结构⼊门-树的遍历以及⼆叉树的创建树定义:1. 有且只有⼀个称为根的节点2. 有若⼲个互不相交的⼦树,这些⼦树本⾝也是⼀个树通俗的讲:1. 树是有结点和边组成,2. 每个结点只有⼀个⽗结点,但可以有多个⼦节点3. 但有⼀个节点例外,该节点没有⽗结点,称为根节点⼀、专业术语结点、⽗结点、⼦结点、根结点深度:从根节点到最底层结点的层数称为深度,根节点第⼀层叶⼦结点:没有⼦结点的结点⾮终端节点:实际上是⾮叶⼦结点度:⼦结点的个数成为度⼆、树的分类⼀般树:任意⼀个结点的⼦结点的个数都不受限制⼆叉树:任意⼀个结点的⼦结点个数最多是两个,且⼦结点的位置不可更改⼆叉数分类:1. ⼀般⼆叉数2. 满⼆叉树:在不增加树层数的前提下,⽆法再多添加⼀个结点的⼆叉树3. 完全⼆叉树:如果只是删除了满⼆叉树最底层最右边的连续若⼲个结点,这样形成的⼆叉树就是完全⼆叉树森林:n个互不相交的树的集合三、树的存储⼆叉树存储连续存储(完全⼆叉树)优点:查找某个结点的⽗结点和⼦结点(也包括判断有没有⼦结点)速度很快缺点:耗⽤内存空间过⼤链式存储⼀般树存储1. 双亲表⽰法:求⽗结点⽅便2. 孩⼦表⽰法:求⼦结点⽅便3. 双亲孩⼦表⽰法:求⽗结点和⼦结点都很⽅便4. ⼆叉树表⽰法:把⼀个⼀般树转化成⼀个⼆叉树来存储,具体转换⽅法:设法保证任意⼀个结点的左指针域指向它的第⼀个孩⼦,右指针域指向它的兄弟,只要能满⾜此条件,就可以把⼀个⼀般树转化为⼆叉树⼀个普通树转换成的⼆叉树⼀定没有右⼦树森林的存储先把森林转化为⼆叉树,再存储⼆叉树四、树的遍历先序遍历:根左右先访问根结点,再先序访问左⼦树,再先序访问右⼦树中序遍历:左根右中序遍历左⼦树,再访问根结点,再中序遍历右⼦树后续遍历:左右根后续遍历左⼦树,后续遍历右⼦树,再访问根节点五、已知两种遍历求原始⼆叉树给定了⼆叉树的任何⼀种遍历序列,都⽆法唯⼀确定相应的⼆叉树,但是如果知道了⼆叉树的中序遍历序列和任意的另⼀种遍历序列,就可以唯⼀地确定⼆叉树已知先序和中序求后序先序:ABCDEFGH中序:BDCEAFHG求后序:这个⾃⼰画个图体会⼀下就可以了,⾮常简单,这⾥简单记录⼀下1. ⾸先根据先序确定根,上⾯的A就是根2. 中序确定左右,A左边就是左树(BDCE),A右边就是右树(FHG)3. 再根据先序,A左下⾯就是B,然后根据中序,B左边没有,右边是DCE4. 再根据先序,B右下是C,根据中序,c左下边是D,右下边是E,所以整个左树就确定了5. 右树,根据先序,A右下是F,然后根据中序,F的左下没有,右下是HG,6. 根据先序,F右下为G,然后根据中序,H在G的左边,所以G的左下边是H再来⼀个例⼦,和上⾯的思路是⼀样的,这⾥就不详细的写了先序:ABDGHCEFI中序:GDHBAECIF已知中序和后序求先序中序:BDCEAFHG后序:DECBHGFA这个和上⾯的思路是⼀样的,只不过是反过来找,后序找根,中序找左右树简单应⽤树是数据库中数据组织⼀种重要形式操作系统⼦⽗进程的关系本⾝就是⼀棵树⾯向对象语⾔中类的继承关系哈夫曼树六、⼆叉树的创建#include <stdio.h>#include <stdlib.h>typedef struct Node{char data;struct Node * lchild;struct Node * rchild;}BTNode;/*⼆叉树建⽴*/void BuildBT(BTNode ** tree){char ch;scanf("%c" , &ch); // 输⼊数据if(ch == '#') // 如果这个节点的数据是#说明这个结点为空*tree = NULL;else{*tree = (BTNode*)malloc(sizeof(BTNode));//申请⼀个结点的内存 (*tree)->data = ch; // 将数据写⼊到结点⾥⾯BuildBT(&(*tree)->lchild); // 递归建⽴左⼦树BuildBT(&(*tree)->rchild); // 递归建⽴右⼦树}}/*⼆叉树销毁*/void DestroyBT(BTNode *tree) // 传⼊根结点{if(tree != NULL){DestroyBT(tree->lchild);DestroyBT(tree->rchild);free(tree); // 释放内存空间}}/*⼆叉树的先序遍历*/void Preorder(BTNode * node){if(node == NULL)return;else{printf("%c ",node->data );Preorder(node->lchild);Preorder(node->rchild);}}/*⼆叉树的中序遍历*/void Inorder(BTNode * node){if(node == NULL)return;else{Inorder(node->lchild);printf("%c ",node->data );Inorder(node->rchild);}}/*⼆叉树的后序遍历*/void Postorder(BTNode * node){if(node == NULL)return;else{Postorder(node->lchild);Postorder(node->rchild);printf("%c ",node->data );}}/*⼆叉树的⾼度树的⾼度 = max(左⼦树⾼度,右⼦树⾼度) +1*/int getHeight(BTNode *node){int Height = 0;if (node == NULL)return 0;else{int L_height = getHeight(node->lchild);int R_height = getHeight(node->rchild);Height = L_height >= R_height ? L_height +1 : R_height +1; }return Height;}int main(int argc, char const *argv[]){BTNode * BTree; // 定义⼀个⼆叉树printf("请输⼊⼀颗⼆叉树先序序列以#表⽰空结点:");BuildBT(&BTree);printf("先序序列:");Preorder(BTree);printf("\n中序序列:");Inorder(BTree);printf("\n后序序列:");Postorder(BTree);printf("\n树的⾼度为:%d" , getHeight(BTree));return 0;}// ABC##DE##F##G##。

二叉树遍历讲课教案ppt课件

I; 中序遍历序列:D,C,B,E,H,A,G, I,F,试画出二叉树,并写出该二叉树的前序 遍历序列和中序遍历序列。
资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
6.5 线索二叉树
§ 何谓线索二叉树? § 线索链表的遍历算法 § 如何建立线索链表?
一、问题的提出
顺着某一条搜索路径巡访二叉树 中的结点,使得每个结点均被访问一 次,而且仅被访问一次。
“访问”的含义可以很是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
if (T) {
visit(T->data);
// 访问结点
Preorder(T->lchild, visit); // 遍历左子树
Preorder(T->rchild, visit);// 遍历右子树 }
}
资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
二、先左后右的遍历算法
先(根)序的遍历算法 中(根)序的遍历算法 后(根)序的遍历算法
资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
先(根)序的遍历算法:
若二叉树为空树,则空操作;否则, (1)访问根结点; (2)先序遍历左子树; (3)先序遍历右子树。

二叉树的存储结构

二叉树的存储结构二叉树是一种常见的数据结构,在计算机科学中被广泛应用。

它的存储结构有多种形式,包括顺序存储和链式存储。

下面将详细介绍这些存储结构。

1.顺序存储:顺序存储是将二叉树的节点按照从上到下、从左到右的顺序依次存储在一个数组中。

对于完全二叉树来说,这种存储方式最为简单有效,可以节省空间。

但是对于一般的二叉树,由于节点的数量不固定,会浪费一定的存储空间。

具体的存储方式可以按照如下的规则进行:-对于二叉树的第i个节点(i从1开始计数),其左子节点存储在数组中的位置为2i,右子节点存储在位置为2i+1、根节点存储在位置为1、这种存储方式可以方便地根据节点的索引计算出其子节点的索引。

- 如果一些位置没有节点,则用一个特殊的标记(如null或者0)代替。

-这种存储方式要求节点按照其中一种顺序进行填充,通常采用层序遍历的方式进行填充。

-在进行节点遍历的时候,可以根据节点的索引来判断其父节点的位置,从而方便地进行遍历。

虽然顺序存储可以节省存储空间,但是在插入和删除节点时涉及到数组元素的移动,效率比较低。

2.链式存储:链式存储是通过节点之间的引用关系来实现。

每个节点包含一个数据域和两个指针域,分别指向其左子节点和右子节点。

链式存储充分利用了指针的特性,可以方便地进行插入和删除节点的操作。

同时,链式存储可以灵活地处理任意形状的二叉树,不需要事先确定节点的数量。

具体的链式存储方式有以下几种:-树的孩子兄弟表示法:每个节点包含两个指针,一个指向其第一个子节点,另一个指向其下一个兄弟节点。

这种表示方式适用于任意形状的二叉树,但是树的操作比较复杂。

-二叉链表表示法:节点包含三个指针,一个指向其左子节点,一个指向其右子节点,另一个指向其父节点。

这种表示方式适用于二叉树,可以方便地进行遍历和操作。

-线索二叉树:在二叉链表表示法的基础上,加入了线索信息。

节点的左指针指向其前驱,右指针指向其后继。

这种方式可以方便地进行中序遍历,节省了遍历时的存储开销。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

石家庄经济学院华信学院实验报告学院: 石家庄经济学院华信学院专业: 计算机科学与技术班级: 计算机一班学号: 411417080118姓名: 李验磊实验题目:二叉树存储表示及基本操作的实现实验室:a280 设备编号:46 完成日期:5/22一、实验目的1.掌握二叉树的存储表示。

2.掌握二叉树的遍历思想。

二、实验内容编程实现二叉树的存储以及二叉树的基本操作。

三、实验的内容及完成情况1. 需求分析(1)二叉树的抽象数据类型ADT的描述及实现。

本实验实现使用Visual c++6.0实现线性表顺序存储结构的表示及操作。

具体实现要求:(2)完成二叉树的表示和实现。

(3)实现二叉树的遍历。

2.概要设计抽象数据类型二叉树的定义:ADT BinaryTree{数据对象D:D是具有相同特性的数据元素的集合数据关系R:若D=Φ,则R=Φ,称BinaryTree为空二叉树;若D≠Φ,则R={H},H是如下关系:(1)在D中存在唯一的称为根的数据元素root,它在关系H下无前驱;(2)若D-{root}≠Φ,则存在D-{root}={D l,D r},且D l∩D r=Φ;(3)若D l≠Φ,则D l中存在唯一的元素x l,<root,x l>∈H,关系H l⊂H;若D r≠Φ,则D r中存在唯一的元素x r,<root,x r>∈H,且存在D r上的关系H r⊂H;H={<root,x l>,<root,x r>,H l,H r};(4)(D l,{H l})是一颗符合本定义的二叉树,称为根的左子树,(D r,{H r})是一颗符合本定义的二叉树,称为根的右子树基本操作P:Status CreateBiTree(BiTree &T);//按先序次序输入二叉树中结点的值(一个字符),空格字符表示空树,//构造二叉链表表示的二叉树T。

Status PreOrderTraverse(BiTree T,Status(*Visit)(TElemType e))//采用二叉链表存储结构,Visit是对结点操作的应用函数。

//先序遍历二叉树T,对每个结点调用函数Visit一次且仅一次。

//一旦Visit()失败,则操作失败。

Status InOrderTraverse(BiTree T,Status(*Visit)(TElemType e))//采用二叉链表存储结构,Visit是对结点操作的应用函数。

//中序遍历二叉树T,对每个结点调用函数Visit一次且仅一次。

//一旦Visit()失败,则操作失败。

Status PostOrderTraverse(BiTree T,Status(*Visit)(TElemType e))//采用二叉链表存储结构,Visit是对结点操作的应用函数。

//后序遍历二叉树T,对每个结点调用函数Visit一次且仅一次。

//一旦Visit()失败,则操作失败。

Status Visit(TElemType e)初始条件:二叉树T存在且非空。

操作结果:输出指针所指的二叉树的结点。

Status BitreeDepth(BiTree T)初始条件:二叉树T存在。

操作结果:计算出二叉树的深度。

Status coutBiTree(BiTNode *T)初始条件:二叉树T存在。

操作结果:分别计算出二叉树中叶子结点、度为2的结点和度为1的结点的个数Status coutNode(BiTree T)初始条件:二叉树T存在。

操作结果:计算出二叉树总结点个数。

Status DestroyBiTree(BiTree &T)初始条件:二叉树T存在。

操作结果:销毁二叉树。

} ADT BinaryTree;3.详细设计(1)抽象数据类型二叉树的表示和实现typedef struct BiTNode{//二叉链表结构类型TElemType data;struct BiTNode *lchild,*rchild;//左右孩子指针}BiTNode, *BiTree;//以下为非递归遍历算法typedef BiTree SElemType;typedef struct SqStack{SElemType *base;SElemType *top;int stacksize;}SqStack;Status InitStack(SqStack &S){//构造一个空栈SS.base=(SElemType *)malloc(STACK_INIT_SIZE *sizeof(SElemType));if(!S.base)exit(OVERFLOW);//存储分配失败S.top=S.base;S.stacksize=STACK_INIT_SIZE;return OK;}//InitStackStatus Push(SqStack &S,SElemType &e){//插入元素e为新的栈顶元素。

if(S.top-S.base>=S.stacksize){S.base=(SElemType *)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));if(!S.base)exit(OVERFLOW);S.top=S.base+S.stacksize;S.stacksize+=STACKINCREMENT;}*S.top++=e;return OK;}//PushStatus Pop(SqStack &S,SElemType &e){//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR。

if(S.top==S.base)return ERROR;e=*--S.top;return OK;}//PopStatus StackEmpty(SqStack S){//判断栈是否为空,若栈为空返回TURE,否则返回FLASE。

if(S.top==S.base)return TRUE;else return FALSE;}//StackEmptyStatus FPreOrderTraverse(BiTree T,Status(*Visit)(TElemType e)){//先序遍历二叉树的非递归算法,对每个数据元素调用函数Visit。

InitStack(S);while(T||!StackEmpty(S)){if(T){if(!Visit(T->data)) return ERROR;Push(S,T);T=T->lchild;}//访问根结点,根结点入栈,遍历左子树else{Pop(S,T);T=T->rchild;}//指针退栈,遍历右子树}return OK;}//FPreOrderTraverseStatus FInOrderTraverse(BiTree T,Status(*Visit)(TElemType e)){//中序遍历二叉树的非递归算法,对每个数据元素调用函数Visit。

InitStack(S);while(T||!StackEmpty(S)){if(T){Push(S,T);T=T->lchild;}//根指针入栈,遍历左子树else{Pop(S,T);if(!Visit(T->data)) return ERROR;T=T->rchild;}//根指针退栈,访问根结点,遍历右子树}return OK;}//FInOrderTraverse//以下为递归算法Status CreateBiTree(BiTree &T){//以先序创建二叉树printf("请输入一个字符,以空格表示空节点:");scanf("%c",&ch);getchar();//接收“enter”输入,避免将“enter”做为二叉树结点if(ch==' ') T=NULL;else{if(!(T=(BiTNode *)malloc(sizeof(BiTNode)))) exit(OVERFLOW);T->data=ch;//生成根结点CreateBiTree(T->lchild);//构造左子树CreateBiTree(T->rchild);//构造右子树}return OK;}//CreateBiTreeStatus PreOrderTraverse(BiTree T,Status(*Visit)(TElemType e)){//先序遍历二叉树的递归算法,对每个数据元素调用函数Visit。

if(T){if(Visit(T->data))if(PreOrderTraverse(T->lchild,Visit))if(PreOrderTraverse(T->rchild,Visit)) return OK;return ERROR;}else return OK;}//PreOrderTraverseStatus InOrderTraverse(BiTree T,Status(*Visit)(TElemType e)){//中序遍历二叉树的递归算法,对每个数据元素调用函数Visit。

if(T){if(InOrderTraverse(T->lchild,Visit))if(Visit(T->data))if(InOrderTraverse(T->rchild,Visit)) return OK;return ERROR;}else return OK;}//InOrderTraverseStatus PostOrderTraverse(BiTree T,Status(*Visit)(TElemType e)) {//后序遍历二叉树的递归算法,对每个数据元素调用函数Visit。

if(T){if(PostOrderTraverse(T->lchild,Visit))if(PostOrderTraverse(T->rchild,Visit))if(Visit(T->data)) return OK;return ERROR;}else return OK;}//PostOrderTraverseStatus Visit(TElemType e){//访问结点printf("%c---",e);return OK;}//VisitStatus BitreeDepth(BiTree T){//求二叉树的深度int dep1;int dep2;if(T==NULL) return(ERROR);else{dep1=BitreeDepth(T->lchild);dep2=BitreeDepth(T->rchild);return(dep1>dep2?dep1:dep2)+1;}}//BitreeDepthStatus coutBiTree(BiTNode *T){//求二叉树中叶子结点、度为2的结点和度为1的结点的个数if(T){if((T->lchild)&&(T->rchild))degree2++;//度为2的结点else if((T->lchild==NULL) && (T->rchild==NULL))degree0++;//叶子结点elsedegree1++;//度为1的结点coutBiTree(T->lchild);coutBiTree(T->rchild);}return OK;}//coutBiTreeStatus coutNode(BiTree T){//求二叉树总结点个数//其实函数内可改为://BitreeDepth(T);//num=degree0+degree1+degree2;//为了熟悉递归调用和二叉树的结构和相关操作才写的这么麻烦的~if(T){num++;coutNode(T->lchild);coutNode(T->rchild);}return OK;}//coutNodeStatus DestroyBiTree(BiTree &T){//销毁二叉树if(T){if(T->lchild)DestroyBiTree(T->lchild);if(T->rchild)DestroyBiTree(T->rchild);free(T);T=NULL;}return OK;}//DestroyBiTree(2)主函数的伪码算法void main()//主函数{int a;printf("》》》》》》》》>>数据结构实验三<<《《《《《《《《\n");printf("*********二叉树的存储表示及基本操作的实现*********\n");do{menu();degree0=degree1=degree2=num=0;//销毁二叉树后各结点个数为0遂每次都还原宏观变量为0 printf("请按提示输入指令:");scanf("%d",&a);getchar();//接收“enter”输入,避免将“enter”做为二叉树结点switch(a){//调用各函数case 1:printf("现在开始以先序次序创建二叉树:\n");CreateBiTree(T);break;case 2:SelectTraverse();break;case 3:deep=BitreeDepth(T);printf("二叉树的深度为:%d",deep);break;case 4:{coutBiTree(T);printf("叶子结点数度为1的结点数度为2的结点数\n");printf(" %d %d %d",degree0,degree1,degree2);}break;case 5:coutNode(T);printf("二叉树的总结点数为:%d",num);break;case 6:DestroyBiTree(T);printf("二叉树已销毁!");break;case 0:printf("谢谢您的使用,再见(*^__^*)!\n");return;default :printf("输入有误,请重新输入(*^__^*)\n");}}while(a!=0);}4. 调试分析(1) 调试过程中出现的问题调试过程中出现了两大问题:1.在主函数中调用遍历子函数时,不了解函数作为参数的调用,造成编写语句错误,不能通过编译。

相关文档
最新文档