构造二叉树.doc
二叉树的建立与基本操作
二叉树的建立与基本操作二叉树是一种特殊的树形结构,它由节点(node)组成,每个节点最多有两个子节点。
二叉树的基本操作包括建立二叉树、遍历二叉树、查找二叉树节点、插入和删除节点等。
本文将详细介绍二叉树的建立和基本操作,并给出相应的代码示例。
一、建立二叉树建立二叉树有多种方法,包括使用数组、链表和前序、中序、后序遍历等。
下面以使用链表的方式来建立二叉树为例。
1.定义二叉树节点类首先,定义一个二叉树节点的类,包含节点值、左子节点和右子节点三个属性。
```pythonclass Node:def __init__(self, value):self.value = valueself.left = Noneself.right = None```2.建立二叉树使用递归的方法来建立二叉树,先构造根节点,然后递归地构造左子树和右子树。
```pythondef build_binary_tree(lst):if not lst: # 如果 lst 为空,则返回 Nonereturn Nonemid = len(lst) // 2 # 取 lst 的中间元素作为根节点的值root = Node(lst[mid])root.left = build_binary_tree(lst[:mid]) # 递归构造左子树root.right = build_binary_tree(lst[mid+1:]) # 递归构造右子树return root```下面是建立二叉树的示例代码:```pythonlst = [1, 2, 3, 4, 5, 6, 7]root = build_binary_tree(lst)```二、遍历二叉树遍历二叉树是指按照其中一规则访问二叉树的所有节点,常见的遍历方式有前序遍历、中序遍历和后序遍历。
1.前序遍历前序遍历是指先访问根节点,然后访问左子节点,最后访问右子节点。
```pythondef pre_order_traversal(root):if root:print(root.value) # 先访问根节点pre_order_traversal(root.left) # 递归访问左子树pre_order_traversal(root.right) # 递归访问右子树```2.中序遍历中序遍历是指先访问左子节点,然后访问根节点,最后访问右子节点。
树-二叉树
信息学奥赛培训之『树——二叉树』树——二叉树为何要重点研究二叉树? 引 : 为何要重点研究二叉树 ? (1)二叉树的结构最简单,规律性最强; (2)可以证明,所有树都能转为唯一对应的二叉树,不失一般性。
一、二叉树基础1. 二叉树的定义 二叉树是一类非常重要的树形结构,它可以递归地定义如下: 二叉树 T 是有限个结点的集合,它或者是空集,或者由一个根结点以及分别称为左 子树和右子树的两棵互不相交的二叉树。
因此,二叉树的根可以有空的左子树或空的右子树,或者左、右子树均为空。
二叉树有 5 种基本形态,如图 1 所示。
图1 二叉树的 5 种基本形态在二叉树中,每个结点至多有两个儿子,并且有左、右之分。
因此任一结点的儿子 不外 4 种情况:没有儿子;只有一个左儿子;只有一个右儿子;有一个左儿子并且有一 个右儿子。
注意:二叉树与树和有序树 的区别 二叉树与度数不超过 2 的树不同,与度数不超过 2 的有序树也不同。
在有序树中,11如果将树中结点的各子树看成从左至右是有次序的,则称该树为有序树,否则称为无序树。
-1-信息学奥赛培训之『树——二叉树』虽然一个结点的儿子之间是有左右次序的,但若该结点只有一个儿子时,就无须区分其 左右次序。
而在二叉树中,即使是一个儿子也有左右之分。
例如图 2-1 中(a)和(b)是两棵 不同的二叉树。
虽然它们与图 2-2 中的普通树(作为无序树或有序树)很相似,但它们却 不能等同于这棵普通的树。
若将这 3 棵树均看作是有序树,则它们就是相同的了。
图2-1 两棵不同的二叉树图2-2 一棵普通的树由此可见,尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形。
不是 ..2. 二叉树的性质图3 二叉树性质1: 在二叉树的第 i 层上至多有 2 i −1 结点(i>=1)。
性质2: 深度为 k 的二叉树至多有 2 k − 1 个结点(k>=1)。
性质3: 对任何一棵二叉树 T,如果其终端结点数为 n0,度为 2 的结点数为 n2,则 n0=n2+1。
[精品]【数据结构】二叉树实验报告
[精品]【数据结构】二叉树实验报告二叉树实验报告一、实验目的:1.掌握二叉树的基本操作;2.理解二叉树的性质;3.熟悉二叉树的广度优先遍历和深度优先遍历算法。
二、实验原理:1.二叉树是一种树形结构,由n(n>=0)个节点组成;2.每个节点最多有两个子节点,称为左子节点和右子节点;3.二叉树的遍历分为四种方式:前序遍历、中序遍历、后序遍历和层次遍历。
三、实验环境:1.编程语言:C++;2.编译器:Dev-C++。
四、实验内容:1.定义二叉树节点结构体:struct BinaryTreeNode{int data; // 节点数据BinaryTreeNode *leftChild; // 左子节点指针BinaryTreeNode *rightChild; // 右子节点指针};2.初始化二叉树:queue<BinaryTreeNode *> q; // 使用队列存储节点q.push(root);int i = 1; // 创建子节点while (!q.empty() && i < length){BinaryTreeNode *node = q.front();q.pop();if (data[i] != -1) // 创建左子节点 {BinaryTreeNode *leftChild = new BinaryTreeNode;leftChild->data = data[i];leftChild->leftChild = nullptr;leftChild->rightChild = nullptr;node->leftChild = leftChild;q.push(leftChild);}i++;if (data[i] != -1) // 创建右子节点 {BinaryTreeNode *rightChild = new BinaryTreeNode;rightChild->data = data[i];rightChild->leftChild = nullptr;rightChild->rightChild = nullptr;node->rightChild = rightChild;q.push(rightChild);}i++;}return root;}3.前序遍历二叉树:五、实验结果:输入:int data[] = {1, 2, 3, 4, -1, -1, 5, 6, -1, -1, 7, 8};输出:前序遍历结果:1 2 4 5 3 6 7 8中序遍历结果:4 2 5 1 6 3 7 8后序遍历结果:4 5 2 6 8 7 3 1层次遍历结果:1 2 3 4 5 6 7 8通过本次实验,我深入理解了二叉树的性质和遍历方式,并掌握了二叉树的基本操作。
CRR二叉树模型及例题
CRR 二叉树模型CRR 二叉树模型(Cox-Ross-Rubinstein 模型),简称CRR 模型。
第1步:确定p,u,d 参数。
tt t r e d e u d u d e p ∆-∆∆==--=σσ其中, t ∆为把时间分成的许多小的时间段; 上升的比率为u,它的概率为p; 下降的比率为d,它的概率为1-p; r 为利率;σ为标准差;第2步:二叉树结构。
当时间为0时,证券价格为S ,时间为t ∆时,证券价格要么上涨到Su ,要么下跌到Sd;时间为2t ∆时,证券价格就有3种可能,分别为22,,Sd Sud Su ,以此类推,在时间i t ∆,证券价格有i+1种可能,用公式表示为j i j d Su -其中,j=0,1,2,3,…,i=1,2,3,…。
第3步:根据二叉树进行倒推定价。
在二叉树模型中,期权定价从树形图末端开始,采用倒推定价法进行。
由于在T 时刻欧式看跌期权现金流为max(K-S T ,0),求解T-t ∆时刻每一节点上的期权价格时都可以通过将T 时刻齐全现金流预期值以无风险收益率进行贴现求出。
假设将欧式看跌期权的存续期分成N 个长度为t ∆的小区间,设)0,0(i j N i f j i ≤≤≤≤-表示在时刻i t ∆第j 个节点处的欧式看跌期权价格,也称j i f -为节点(i,j )的期权价值,同时j i j d Su -表示节点(i,j )处的标的价格,欧式看跌期权到期价值是max(K-S T ,0),所以有)0,max(,j N j j N d Su K f --=其中,j=0,1,2,3,…,N 。
当时间从i t ∆变到(i+1)t ∆时,从节点(i,j )移动到(i+1,j+1)的概率为p,移动到(i+1,j )的概率为(1-p ),则在风险中性情况下i j N i f p pf e f j i j i t r j i ≤≤-≤≤-+=+++∆-0,10],)1([,11,1,当我们选择的时间间隔足够小时,就可以求出欧式看跌期权的精确值。
实验六二叉树实验报告
实验四二叉树的操作班级:计算机1002班姓名:唐自鸿学号:201003010207 完成日期:2010.6.14 题目:对于给定的一二叉树,实现各种约定的遍历。
一、实验目的:(1)掌握二叉树的定义和存储表示,学会建立一棵特定二叉树的方法;(2)掌握二叉树的遍历算法(先序、中序、后序遍历算法)的思想,并学会遍历算法的递归实现和非递归实现。
二、实验内容:构造二叉树,再实现二叉树的先序、中序、后序遍历,最后统计二叉树的深度。
三、实验步骤:(一) 需求分析1. 二叉树的建立首先要建立一个二叉链表的结构体,包含根节点和左右子树。
因为树的每一个左右子树又是一颗二叉树,所以用递归的方法来建立其左右子树。
二叉树的遍历是一种把二叉树的每一个节点访问并输出的过程,遍历时根结点与左右孩子的输出顺序构成了不同的遍历方法,这个过程需要按照不同的遍历的方法,先输出根结点还是先输出左右孩子,可以用选择语句来实现。
2.程序的执行命令为:1)构造结点类型,然后创建二叉树。
2)根据提示,从键盘输入各个结点。
3)通过选择一种方式(先序、中序或者后序)遍历。
4)输出结果,结束。
(二)概要设计1.二叉树的二叉链表结点存储类型定义typedef struct Node{DataType data;struct Node *LChild;struct Node *RChild;}BitNode,*BitTree;2.建立如下图所示二叉树:void CreatBiTree(BitTree *bt)用扩展先序遍历序列创建二叉树,如果是当前树根置为空,否则申请一个新节点。
3.本程序包含四个模块1) 主程序模块:2)先序遍历模块3)中序遍历模块4)后序遍历模块4.模块调用关系:主程序模块(三)详细设计1.建立二叉树存储类型//==========构造二叉树=======void CreatBiTree(BitTree *bt)//用扩展先序遍历序列创建二叉树,如果是当前树根置为空,否则申请一个新节点//{char ch;ch=getchar();if(ch=='.')*bt=NULL;else{*bt=(BitTree)malloc(sizeof(BitNode));//申请一段关于该节点类型的存储空间(*bt)->data=ch; //生成根结点CreatBiTree(&((*bt)->LChild)); //构造左子树CreatBiTree(&((*bt)->RChild)); //构造右子树}}2. 编程实现以上二叉树的前序、中序和后序遍历操作,输出遍历序列1)先序遍历二叉树的递归算法如下:void PreOrder(BitTree root){if (root!=NULL){Visit(root ->data);PreOrder(root ->LChild); //递归调用核心PreOrder(root ->RChild);}}2)中序遍历二叉树的递归算法如下:void InOrder(BitTree root){if (root!=NULL){InOrder(root ->LChild);Visit(root ->data);InOrder(root ->RChild);}}3)后序遍历二叉树的递归算法如下:void PostOrder(BitTree root){if(root!=NULL){PostOrder(root ->LChild);PostOrder(root ->RChild);Visit(root ->data);}}4)计算二叉树的深度算法如下:int PostTreeDepth(BitTree bt) //求二叉树的深度{int hl,hr,max;if(bt!=NULL){hl=PostTreeDepth(bt->LChild); //求左子树的深度hr=PostTreeDepth(bt->RChild); //求右子树的深度max=hl>hr?hl:hr; //得到左、右子树深度较大者return(max+1); //返回树的深度}else return(0); //如果是空树,则返回0}四、调试分析及测试结果1. 进入演示程序后的显示主界面:请输入二叉树中的元素;先序、中序和后序遍历分别输出结果。
二叉树结构体定义
二叉树结构体定义
二叉树是一种重要的数据结构,它由根节点、左子树和右子树组成。
在程序中,我们通常使用结构体来定义二叉树。
二叉树结构体通常包含三个成员变量:根节点指针、左子树指针和右子树指针。
其中,根节点指针指向二叉树的根节点,左子树指针指向左子树的根节点,右子树指针指向右子树的根节点。
二叉树结构体的定义如下:
```c
typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode;
```
上述代码中,我们使用 typedef 关键字定义了一个名为TreeNode 的结构体类型。
结构体中包含了一个 int 型的 val 成员变量,以及两个指向 TreeNode 类型的指针 left 和 right。
通过定义二叉树结构体,我们可以轻松地创建二叉树,并对其进行操作。
- 1 -。
二叉树
平衡树——特点:所有结点左右子树深度差≤1排序树——特点:所有结点―左小右大字典树——由字符串构成的二叉排序树判定树——特点:分支查找树(例如12个球如何只称3次便分出轻重)带权树——特点:路径带权值(例如长度)最优树——是带权路径长度最短的树,又称Huffman树,用途之一是通信中的压缩编码。
1.1 二叉排序树:或是一棵空树;或者是具有如下性质的非空二叉树:(1)若左子树不为空,左子树的所有结点的值均小于根的值;(2)若右子树不为空,右子树的所有结点均大于根的值;(3)它的左右子树也分别为二叉排序树。
例:二叉排序树如图9.7:二叉排序树的查找过程和次优二叉树类似,通常采取二叉链表作为二叉排序树的存储结构。
中序遍历二叉排序树可得到一个关键字的有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。
每次插入的新的结点都是二叉排序树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。
搜索,插入,删除的复杂度等于树高,期望O(logn),最坏O(n)(数列有序,树退化成线性表).虽然二叉排序树的最坏效率是O(n),但它支持动态查询,且有很多改进版的二叉排序树可以使树高为O(logn),如SBT,AVL,红黑树等.故不失为一种好的动态排序方法.2.2 二叉排序树b中查找在二叉排序树b中查找x的过程为:1. 若b是空树,则搜索失败,否则:2. 若x等于b的根节点的数据域之值,则查找成功;否则:3. 若x小于b的根节点的数据域之值,则搜索左子树;否则:4. 查找右子树。
[cpp]view plaincopyprint?1.Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p){2. //在根指针T所指二叉排序樹中递归地查找其关键字等于key的数据元素,若查找成功,3. //则指针p指向该数据元素节点,并返回TRUE,否则指针P指向查找路径上访问的4. //最好一个节点并返回FALSE,指针f指向T的双亲,其初始调用值为NULL5. if(!T){ p=f; return FALSE;} //查找不成功6. else if EQ(key, T->data.key) {P=T; return TRUE;} //查找成功7. else if LT(key,T->data.key)8. return SearchBST(T->lchild, key, T, p); //在左子树继续查找9. else return SearchBST(T->rchild, key, T, p); //在右子树继续查找10.}2.3 在二叉排序树插入结点的算法向一个二叉排序树b中插入一个结点s的算法,过程为:1. 若b是空树,则将s所指结点作为根结点插入,否则:2. 若s->data等于b的根结点的数据域之值,则返回,否则:3. 若s->data小于b的根结点的数据域之值,则把s所指结点插入到左子树中,否则:4. 把s所指结点插入到右子树中。
数据结构实验三——二叉树基本操作及运算实验报告
《数据结构与数据库》实验报告实验题目二叉树的基本操作及运算一、需要分析问题描述:实现二叉树(包括二叉排序树)的建立,并实现先序、中序、后序和按层次遍历,计算叶子结点数、树的深度、树的宽度,求树的非空子孙结点个数、度为2的结点数目、度为2的结点数目,以及二叉树常用运算。
问题分析:二叉树树型结构是一类重要的非线性数据结构,对它的熟练掌握是学习数据结构的基本要求。
由于二叉树的定义本身就是一种递归定义,所以二叉树的一些基本操作也可采用递归调用的方法。
处理本问题,我觉得应该:1、建立二叉树;2、通过递归方法来遍历(先序、中序和后序)二叉树;3、通过队列应用来实现对二叉树的层次遍历;4、借用递归方法对二叉树进行一些基本操作,如:求叶子数、树的深度宽度等;5、运用广义表对二叉树进行广义表形式的打印。
算法规定:输入形式:为了方便操作,规定二叉树的元素类型都为字符型,允许各种字符类型的输入,没有元素的结点以空格输入表示,并且本实验是以先序顺序输入的。
输出形式:通过先序、中序和后序遍历的方法对树的各字符型元素进行遍历打印,再以广义表形式进行打印。
对二叉树的一些运算结果以整型输出。
程序功能:实现对二叉树的先序、中序和后序遍历,层次遍历。
计算叶子结点数、树的深度、树的宽度,求树的非空子孙结点个数、度为2的结点数目、度为2的结点数目。
对二叉树的某个元素进行查找,对二叉树的某个结点进行删除。
测试数据:输入一:ABC□□DE□G□□F□□□(以□表示空格),查找5,删除E预测结果:先序遍历ABCDEGF中序遍历CBEGDFA后序遍历CGEFDBA层次遍历ABCDEFG广义表打印A(B(C,D(E(,G),F)))叶子数3 深度5 宽度2 非空子孙数6 度为2的数目2 度为1的数目2查找5,成功,查找的元素为E删除E后,以广义表形式打印A(B(C,D(,F)))输入二:ABD□□EH□□□CF□G□□□(以□表示空格),查找10,删除B预测结果:先序遍历ABDEHCFG中序遍历DBHEAGFC后序遍历DHEBGFCA层次遍历ABCDEFHG广义表打印A(B(D,E(H)),C(F(,G)))叶子数3 深度4 宽度3 非空子孙数7 度为2的数目2 度为1的数目3查找10,失败。
数据结构实验二叉树
实验六:二叉树及其应用一、实验目的树是数据结构中应用极为广泛的非线性结构,本单元的实验达到熟悉二叉树的存储结构的特性,以及如何应用树结构解决具体问题。
二、问题描述首先,掌握二叉树的各种存储结构和熟悉对二叉树的基本操作。
其次,以二叉树表示算术表达式的基础上,设计一个十进制的四则运算的计算器。
如算术表达式:a+b*(c-d)-e/f三、实验要求如果利用完全二叉树的性质和二叉链表结构建立一棵二叉树,分别计算统计叶子结点的个数。
求二叉树的深度。
十进制的四则运算的计算器可以接收用户来自键盘的输入。
由输入的表达式字符串动态生成算术表达式所对应的二叉树。
自动完成求值运算和输出结果。
四、实验环境PC微机DOS操作系统或Windows 操作系统Turbo C 程序集成环境或Visual C++ 程序集成环境五、实验步骤1、根据二叉树的各种存储结构建立二叉树;2、设计求叶子结点个数算法和树的深度算法;3、根据表达式建立相应的二叉树,生成表达式树的模块;4、根据表达式树,求出表达式值,生成求值模块;5、程序运行效果,测试数据分析算法。
六、测试数据1、输入数据:2.2*(3.1+1.20)-7.5/3正确结果:6.962、输入数据:(1+2)*3+(5+6*7);正确输出:56七、表达式求值由于表达式求值算法较为复杂,所以单独列出来加以分析:1、主要思路:由于操作数是任意的实数,所以必须将原始的中缀表达式中的操作数、操作符以及括号分解出来,并以字符串的形式保存;然后再将其转换为后缀表达式的顺序,后缀表达式可以很容易地利用堆栈计算出表达式的值。
例如有如下的中缀表达式:a+b-c转换成后缀表达式为:ab+c-然后分别按从左到右放入栈中,如果碰到操作符就从栈中弹出两个操作数进行运算,最后再将运算结果放入栈中,依次进行直到表达式结束。
如上述的后缀表达式先将a 和b 放入栈中,然后碰到操作符“+”,则从栈中弹出a 和b 进行a+b 的运算,并将其结果d(假设为d)放入栈中,然后再将c 放入栈中,最后是操作符“-”,所以再弹出d和c 进行d-c 运算,并将其结果再次放入栈中,此时表达式结束,则栈中的元素值就是该表达式最后的运算结果。
数据结构二叉树实验报告
数据结构二叉树实验报告1. 引言二叉树是一种常见的数据结构,由节点(Node)和链接(Link)构成。
每个节点最多有两个子节点,分别称为左子节点和右子节点。
二叉树在计算机科学中被广泛应用,例如在搜索算法中,二叉树可以用来快速查找和插入数据。
本实验旨在通过编写二叉树的基本操作来深入理解二叉树的特性和实现方式。
2. 实验内容2.1 二叉树的定义二叉树可以用以下方式定义:class TreeNode:def__init__(self, val):self.val = valself.left =Noneself.right =None每个节点包含一个值和两个指针,分别指向左子节点和右子节点。
根据需求,可以为节点添加其他属性。
2.2 二叉树的基本操作本实验主要涉及以下二叉树的基本操作:•创建二叉树:根据给定的节点值构建二叉树。
•遍历二叉树:将二叉树的节点按照特定顺序访问。
•查找节点:在二叉树中查找特定值的节点。
•插入节点:向二叉树中插入新节点。
•删除节点:从二叉树中删除特定值的节点。
以上操作将在下面章节详细讨论。
3. 实验步骤3.1 创建二叉树二叉树可以通过递归的方式构建。
以创建一个简单的二叉树为例:def create_binary_tree():root = TreeNode(1)root.left = TreeNode(2)root.right = TreeNode(3)root.left.left = TreeNode(4)root.left.right = TreeNode(5)return root以上代码创建了一个二叉树,根节点的值为1,左子节点值为2,右子节点值为3,左子节点的左子节点值为4,左子节点的右子节点值为5。
3.2 遍历二叉树二叉树的遍历方式有多种,包括前序遍历、中序遍历和后序遍历。
以下是三种遍历方式的代码实现:•前序遍历:def preorder_traversal(root):if root:print(root.val)preorder_traversal(root.left)preorder_traversal(root.right)•中序遍历:def inorder_traversal(root):if root:inorder_traversal(root.left)print(root.val)inorder_traversal(root.right)•后序遍历:def postorder_traversal(root):if root:postorder_traversal(root.left)postorder_traversal(root.right)print(root.val)3.3 查找节点在二叉树中查找特定值的节点可以使用递归的方式实现。
简单算术表达式的二叉树的构建和求值
一、概述二、算术表达式的二叉树表示1. 什么是二叉树2. 算术表达式的二叉树表示方法三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式2. 后缀表达式构建二叉树四、算术表达式二叉树的求值五、应用举例六、总结一、概述在数学和计算机科学中,处理算术表达式是一个常见的问题。
在计算机中,算术表达式通常以中缀、前缀或后缀的形式出现,其中中缀表达式最为常见。
而采用二叉树来表示和求解算术表达式,是一种常见且高效的方法。
二、算术表达式的二叉树表示1. 什么是二叉树二叉树是一种树形数据结构,它的每个节点最多只能有两个子节点,分别是左子节点和右子节点。
二叉树可以为空,也可以是非空的。
2. 算术表达式的二叉树表示方法在二叉树中,每个节点要么是操作符,要么是操作数。
操作符节点的左子节点和右子节点分别表示运算符的两个操作数,而操作数节点则不包含任何子节点。
通过这种方式,可以将算术表达式表示为一个二叉树结构。
三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式为了构建算术表达式的二叉树,首先需要将中缀表达式转换为后缀表达式。
中缀表达式是人们常见的形式,例如"2 + 3 * 5",而后缀表达式则更适合计算机处理,例如"2 3 5 * +"。
将中缀转后缀的算法即为中缀表达式的后缀转换法则。
2. 后缀表达式构建二叉树构建二叉树的过程通常采用栈来辅助完成。
从左到右扫描后缀表达式,对于每个元素,如果是操作数,则入栈;如果是操作符,则弹出栈顶两个元素作为其左右子节点,然后将操作符节点入栈。
最终栈中只剩一个节点,即为构建的二叉树的根节点。
四、算术表达式二叉树的求值算术表达式二叉树的求值是递归进行的。
对于二叉树的每个节点,如果是操作符节点,则递归求解其左右子节点的值,并进行相应的操作;如果是操作数节点,则直接返回其值。
最终得到根节点的值,即为整个算术表达式的值。
五、应用举例以中缀表达式"2 + 3 * 5"为例,首先将其转换为后缀表达式"2 3 5 * +",然后根据后缀表达式构建二叉树,最终求得二叉树的根节点即为算术表达式的值。
数据结构实验报告-树(二叉树)
实验5:树(二叉树)(采用二叉链表存储)一、实验项目名称二叉树及其应用二、实验目的熟悉二叉树的存储结构的特性以及二叉树的基本操作。
三、实验基本原理之前我们都是学习的线性结构,这次我们就开始学习非线性结构——树。
线性结构中结点间具有唯一前驱、唯一后继关系,而非线性结构中结点的前驱、后继的关系并不具有唯一性。
在树结构中,节点间关系是前驱唯一而后继不唯一,即结点之间是一对多的关系。
直观地看,树结构是具有分支关系的结构(其分叉、分层的特征类似于自然界中的树)。
四、主要仪器设备及耗材Window 11、Dev-C++5.11五、实验步骤1.导入库和预定义2.创建二叉树3.前序遍历4.中序遍历5.后序遍历6.总结点数7.叶子节点数8.树的深度9.树根到叶子的最长路径10.交换所有节点的左右子女11.顺序存储12.显示顺序存储13.测试函数和主函数对二叉树的每一个操作写测试函数,然后在主函数用while+switch-case的方式实现一个带菜单的简易测试程序,代码见“实验完整代码”。
实验完整代码:#include <bits/stdc++.h>using namespace std;#define MAX_TREE_SIZE 100typedef char ElemType;ElemType SqBiTree[MAX_TREE_SIZE];struct BiTNode{ElemType data;BiTNode *l,*r;}*T;void createBiTree(BiTNode *&T){ElemType e;e = getchar();if(e == '\n')return;else if(e == ' ')T = NULL;else{if(!(T = (BiTNode *)malloc(sizeof (BiTNode)))){cout << "内存分配错误!" << endl;exit(0);}T->data = e;createBiTree(T->l);createBiTree(T->r);}}void createBiTree2(BiTNode *T,int u) {if(T){SqBiTree[u] = T->data;createBiTree2(T->l,2 * u + 1);createBiTree2(T->r,2 * u + 2); }}void outputBiTree2(int n){int cnt = 0;for(int i = 0;cnt <= n;i++){cout << SqBiTree[i];if(SqBiTree[i] != ' ')cnt ++;}cout << endl;}void preOrderTraverse(BiTNode *T) {if(T){cout << T->data;preOrderTraverse(T->l);preOrderTraverse(T->r);}}void inOrderTraverse(BiTNode *T) {if(T){inOrderTraverse(T->l);cout << T->data;inOrderTraverse(T->r);}}void beOrderTraverse(BiTNode *T){if(T){beOrderTraverse(T->l);beOrderTraverse(T->r);cout << T->data;}}int sumOfVer(BiTNode *T){if(!T)return 0;return sumOfVer(T->l) + sumOfVer(T->r) + 1;}int sumOfLeaf(BiTNode *T){if(!T)return 0;if(T->l == NULL && T->r == NULL)return 1;return sumOfLeaf(T->l) + sumOfLeaf(T->r);}int depth(BiTNode *T){if(!T)return 0;return max(depth(T->l),depth(T->r)) + 1;}bool LongestPath(int dist,int dist2,vector<ElemType> &ne,BiTNode *T) {if(!T)return false;if(dist2 == dist)return true;if(LongestPath(dist,dist2 + 1,ne,T->l)){ne.push_back(T->l->data);return true;}else if(LongestPath(dist,dist2 + 1,ne,T->r)){ne.push_back(T->r->data);return true;}return false;}void swapVer(BiTNode *&T){if(T){swapVer(T->l);swapVer(T->r);BiTNode *tmp = T->l;T->l = T->r;T->r = tmp;}}//以下是测试程序void test1(){getchar();cout << "请以先序次序输入二叉树结点的值,空结点用空格表示:" << endl; createBiTree(T);cout << "二叉树创建成功!" << endl;}void test2(){cout << "二叉树的前序遍历为:" << endl;preOrderTraverse(T);cout << endl;}void test3(){cout << "二叉树的中序遍历为:" << endl;inOrderTraverse(T);cout << endl;}void test4(){cout << "二叉树的后序遍历为:" << endl;beOrderTraverse(T);cout << endl;}void test5(){cout << "二叉树的总结点数为:" << sumOfVer(T) << endl;}void test6(){cout << "二叉树的叶子结点数为:" << sumOfLeaf(T) << endl; }void test7(){cout << "二叉树的深度为:" << depth(T) << endl;}void test8(){int dist = depth(T);vector<ElemType> ne;cout << "树根到叶子的最长路径:" << endl;LongestPath(dist,1,ne,T);ne.push_back(T->data);reverse(ne.begin(),ne.end());cout << ne[0];for(int i = 1;i < ne.size();i++)cout << "->" << ne[i];cout << endl;}void test9(){swapVer(T);cout << "操作成功!" << endl;}void test10(){memset(SqBiTree,' ',sizeof SqBiTree);createBiTree2(T,0);cout << "操作成功!" << endl;}void test11(){int n = sumOfVer(T);outputBiTree2(n);}int main(){int op = 0;while(op != 12){cout << "-----------------menu--------------------" << endl;cout << "--------------1:创建二叉树--------------" << endl;cout << "--------------2:前序遍历----------------" << endl;cout << "--------------3:中序遍历----------------" << endl;cout << "--------------4:后序遍历----------------" << endl;cout << "--------------5:总结点数----------------" << endl;cout << "--------------6:叶子节点数--------------" << endl;cout << "--------------7:树的深度----------------" << endl;cout << "--------------8:树根到叶子的最长路径----" << endl;cout << "--------------9:交换所有节点左右子女----" << endl;cout << "--------------10:顺序存储---------------" << endl;cout << "--------------11:显示顺序存储-----------" << endl;cout << "--------------12:退出测试程序-----------" << endl;cout << "请输入指令编号:" << endl;if(!(cin >> op)){cin.clear();cin.ignore(INT_MAX,'\n');cout << "请输入整数!" << endl;continue;}switch(op){case 1:test1();break;case 2:test2();break;case 3:test3();break;case 4:test4();break;case 5:test5();break;case 6:test6();break;case 7:test7();break;case 8:test8();break;case 9:test9();break;case 10:test10();break;case 11:test11();break;case 12:cout << "测试结束!" << endl;break;default:cout << "请输入正确的指令编号!" << endl;}}return 0;}六、实验数据及处理结果测试用例:1.创建二叉树(二叉链表形式)2.前序遍历3.中序遍历4.后序遍历5.总结点数6.叶子结点数7.树的深度8.树根到叶子的最长路径9.交换所有左右子女10.顺序存储七、思考讨论题或体会或对改进实验的建议通过这次实验,我掌握了二叉树的顺序存储和链式存储,体会了二叉树的存储结构的特性,掌握了二叉树的树上相关操作。
试写出在链式存储结构上建立一棵二叉树的算法
试写出在链式存储结构上建立一棵二叉树的算法对于链式存储结构的二叉树,需要定义一个节点结构体来表示每个节点:```ctypedef struct node {int data;struct node *left;struct node *right;} node;```其中,data 表示节点的数据,left 和right 分别表示节点的左子节点和右子节点。
接下来,我们可以设计一个函数来创建一棵二叉树,算法步骤如下:1. 首先创建一个新节点,并让用户输入节点的数据。
2. 如果当前二叉树为空,则将新节点插入到根节点。
3. 否则,从根节点开始遍历二叉树。
4. 如果新节点的数据小于当前节点的数据,则继续遍历左子树。
5. 如果新节点的数据大于当前节点的数据,则继续遍历右子树。
6. 直到找到一个空位置,将新节点插入到该位置。
以下是一个示例代码实现:```c#include <stdio.h>#include <stdlib.h>typedef struct node {int data;struct node *left;struct node *right;} node;node *create_node(int data) {node *new_node = (node *)malloc(sizeof(node));new_node->data = data;new_node->left = NULL;new_node->right = NULL;return new_node;}node *insert_node(node *root, int data) {if (root == NULL) {return create_node(data);}else if (data < root->data) {root->left = insert_node(root->left, data);}else if (data > root->data) {root->right = insert_node(root->right, data);}return root;}void inorder_traversal(node *root) {if (root != NULL) {inorder_traversal(root->left);printf("%d ", root->data);inorder_traversal(root->right);}}int main() {node *root = NULL;int n, data;printf("Enter the number of nodes: ");scanf("%d", &n);printf("Enter the data of each node: ");for (int i = 0; i < n; i++) {scanf("%d", &data);root = insert_node(root, data);}printf("Inorder Traversal: ");inorder_traversal(root);printf("\n");return 0;}```该程序首先让用户输入二叉树的节点数量和每个节点的数据,然后调用insert_node 函数来插入节点,并最终输出中序遍历的结果。
构造表达式二叉树
构造表达式二叉树构造表达式二叉树,需要先确定二叉树的构造规则,然后将表达式按照规则转换为对应的二叉树结构。
下面是一个简单的例子,演示如何构造一个表达式的二叉树:假设我们有一个简单的四则运算表达式:3 + 4 2 - 1 / 2。
根据二叉树的构造规则,我们可以将这个表达式转换为如下的二叉树结构:```+/ \3/ \4 2/ \- 1/ \/ 2```这个二叉树表示的表达式是:3 + (4 2) - (1 / 2)。
其中,根节点表示运算符"+",左子树表示3,右子树是一个二叉树,根节点表示运算符"",左子树表示4,右子树表示2。
在右子树的下面是一个三叉树,根节点表示运算符"-",左子树是空,中子树表示1,右子树是一个二叉树,根节点表示运算符"/",左子树是空,右子树表示2。
在构造这个二叉树时,需要注意以下几点:1. 先处理运算符和操作数。
在表达式中,运算符和操作数之间有一个空格。
在构造二叉树时,我们需要保留这个空格,将其视为两个节点的分隔符。
2. 根据运算符的优先级和结合性,确定子树的构造顺序。
在本例中,""的优先级高于"+",所以先构造""的子树。
同时,""是左结合的,所以先构造左子树。
3. 对于复杂的表达式,需要使用括号来明确运算顺序。
在本例中,"1 / 2"被括起来,表示先进行除法运算。
在构造二叉树时,需要将括号视为一个节点,并将其作为父节点包含其它的子节点。
二叉树的建立和遍历的实验报告
竭诚为您提供优质文档/双击可除二叉树的建立和遍历的实验报告篇一:二叉树遍历实验报告数据结构实验报告报告题目:二叉树的基本操作学生班级:学生姓名:学号:一.实验目的1、基本要求:深刻理解二叉树性质和各种存储结构的特点及适用范围;掌握用指针类型描述、访问和处理二叉树的运算;熟练掌握二叉树的遍历算法;。
2、较高要求:在遍历算法的基础上设计二叉树更复杂操作算法;认识哈夫曼树、哈夫曼编码的作用和意义;掌握树与森林的存储与便利。
二.实验学时:课内实验学时:3学时课外实验学时:6学时三.实验题目1.以二叉链表为存储结构,实现二叉树的创建、遍历(实验类型:验证型)1)问题描述:在主程序中设计一个简单的菜单,分别调用相应的函数功能:1…建立树2…前序遍历树3…中序遍历树4…后序遍历树5…求二叉树的高度6…求二叉树的叶子节点7…非递归中序遍历树0…结束2)实验要求:在程序中定义下述函数,并实现要求的函数功能:createbinTree(binTreestructnode*lchild,*rchild;}binTnode;元素类型:intcreatebinTree(binTreevoidpreorder(binTreevoidInorder(binTreevoidpostorder(binTreevoidInordern(binTreeintleaf(bi nTreeintpostTreeDepth(binTree2、编写算法实现二叉树的非递归中序遍历和求二叉树高度。
1)问题描述:实现二叉树的非递归中序遍历和求二叉树高度2)实验要求:以二叉链表作为存储结构3)实现过程:1、实现非递归中序遍历代码:voidcbiTree::Inordern(binTreeinttop=0;p=T;do{while(p!=nuLL){stack[top]=p;;top=top+1;p=p->lchild;};if(top>0){top=top-1;p=stack[top];printf("%3c",p->data);p=p->rchild;}}while(p!=nuLL||top!=0);}2、求二叉树高度:intcbiTree::postTreeDepth(binTreeif(T!=nuLL){l=postTreeDepth(T->lchild);r=postTreeDepth(T->rchil d);max=l>r?l:r;return(max+1);}elsereturn(0);}实验步骤:1)新建一个基于consoleApplication的工程,工程名称biTreeTest;2)新建一个类cbiTree二叉树类。
二叉树的建立实验报告
二叉树的建立实验报告二叉树的建立实验报告引言:二叉树是计算机科学中常用的数据结构之一,它具有良好的组织和查找性能。
本实验旨在通过建立二叉树的过程,深入理解二叉树的概念和操作,并通过实际操作验证其性能。
实验目的:1. 掌握二叉树的基本概念和性质;2. 熟悉二叉树的建立和遍历操作;3. 了解二叉树在实际应用中的作用。
实验过程:1. 二叉树的定义与性质二叉树是一种特殊的树状结构,每个节点最多有两个子节点。
根据节点的位置关系,可以分为左子树和右子树。
二叉树的性质包括:每个节点最多有两个子节点、左子树和右子树也是二叉树、二叉树可以为空。
2. 二叉树的建立为了验证二叉树的性质,我们首先需要建立一个二叉树。
在本实验中,我们选择使用数组来表示二叉树。
具体建立过程如下:- 定义一个数组,用于存储二叉树的节点;- 根据二叉树的性质,按照特定规则将节点填充到数组中;- 通过数组索引的方式,建立节点之间的关联关系。
3. 二叉树的遍历二叉树的遍历是指按照一定顺序访问二叉树中的节点。
常用的遍历方式包括前序遍历、中序遍历和后序遍历。
在本实验中,我们选择中序遍历来验证二叉树的建立是否正确。
中序遍历的过程如下:- 从根节点开始,递归地遍历左子树;- 访问当前节点;- 递归地遍历右子树。
4. 实验结果与分析经过建立和遍历操作,我们得到了一个完整的二叉树。
通过中序遍历,我们可以观察到二叉树节点的有序性,证明了二叉树的建立正确性。
此外,我们还可以通过其他遍历方式来验证二叉树的结构和性质。
实验总结:通过本次实验,我们深入了解了二叉树的概念和操作,并通过实际操作验证了二叉树的性质。
二叉树作为一种常用的数据结构,具有良好的组织和查找性能,在实际应用中发挥着重要的作用。
通过进一步学习和实践,我们可以更加熟练地运用二叉树,并将其应用于解决实际问题中。
参考文献:1. 《数据结构与算法分析》(C语言版),Mark Allen Weiss 著,机械工业出版社,2012年。
树与二叉树.doc
树与二叉树(总分:228.00,做题时间:90分钟)一、单项选择题(总题数:24,分数:48.00)1.具有10个叶结点的二叉树中有( )个度为2的结点。
(分数:2.00)A.8B.9C.10D.112.分别以下列序列构造二叉排序树,与用其他三个序列所构造的结果不同的是( )。
(分数:2.00)A.(100,80,90,60,120,110,130)B.(100,120,110,130,80,60,90)C.(100,60,80,90,120,110,130)D.(100,80,60,90,120,130,110)3.一棵左子树为空的二叉树在先序线索化后,其中空的链域的个数是( )。
(分数:2.00)A.不确定B.0C.1D.24.中缀表达式D/C“A+B*E—D*F的前缀表达式为( )。
(分数:2.00)A.-+/D^CA*BE*DFB.DCA^/BE*+DF*-C.-C^A+/D*BE*DFD.-+/D^C*ABE*DF5.设F是一个森林,B是由F变换得的二叉树。
若F中有n个非终端结点,则B中右指针域为空的结点有( )个。
(分数:2.00)A.n-1B.nC.n+1D.n+26.一棵二叉树的前序遍历序列为ABCDEFG,它的中序遍历序列可能是( )。
(分数:2.00)A.CABDEFGB.ABCDEFGC.DACEFBGD.ADCFEG7.在一棵三元树中度为3的结点数为2个,度为2的结点数为1个,度为1的结点数为2个,则度为0的结点数为( )个。
(分数:2.00)A.4B.5C.6D.78.设有一表示算术表达式的二叉树(见图),它所表示的算术表达式是( )。
2.00)A.B.C.D.9.已知一棵二叉树先序遍历结果为ABDEFG,中序遍历结果为BAEDGF,则后序遍历结果为( )。
(分数:2.00)A.BCDEFAB.BFDECAC.BEGFDAD.BEFGDA10.设某哈夫曼树中有199个结点,则该哈夫曼树中有( )个叶子结点。
c++二叉树的拷贝构造
c++二叉树的拷贝构造C++中的二叉树拷贝构造是指创建一个新的二叉树对象,并将原始二叉树的内容复制到新的对象中。
下面我将从多个角度全面回答你关于C++二叉树拷贝构造的问题。
在C++中,二叉树通常由节点(Node)组成,每个节点包含一个值和指向左子节点和右子节点的指针。
要实现二叉树的拷贝构造,我们需要递归地复制每个节点及其子树。
首先,我们需要定义一个二叉树节点的结构,包含值和指向左右子节点的指针。
例如:cpp.struct TreeNode {。
int value;TreeNode left;TreeNode right;};接下来,我们可以实现一个拷贝构造函数来复制二叉树。
拷贝构造函数是一个特殊的构造函数,它接受一个同类型的对象作为参数,并创建一个新对象,将原始对象的值复制到新对象中。
例如:cpp.class BinaryTree {。
public:// 构造函数。
BinaryTree(int value) : root(nullptr) {。
root = new TreeNode;root->value = value;root->left = nullptr;root->right = nullptr;}。
// 拷贝构造函数。
BinaryTree(const BinaryTree& other) {。
root = copyTree(other.root);}。
// 递归辅助函数,复制二叉树。
TreeNode copyTree(TreeNode node) {。
if (node == nullptr) {。
return nullptr;}。
TreeNode newNode = new TreeNode;newNode->value = node->value;newNode->left = copyTree(node->left);newNode->right = copyTree(node->right);return newNode;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<math.h> /* floor(),ceil(),abs() */#include<string.h>#include<stdlib.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等*/ typedef char TElemType;TElemType Nil=' '; /* 以空格符为空*/#define MAX_TREE_SIZE 100typedef struct{TElemType data;int parent; /* 双亲位置域*/} PTNode;typedef struct{PTNode nodes[MAX_TREE_SIZE];int n; /* 结点数*/} PTree;Status InitTree(PTree *T){ /* 操作结果: 构造空树T */(*T).n=0;return OK;}void DestroyTree(){ /* 由于PTree是定长类型,无法销毁*/}typedef struct{int num;TElemType name;}QElemType; /* 定义队列元素类型*/typedef struct QNode{QElemType data;struct QNode *next;}QNode,*QueuePtr;typedef struct{QueuePtr front,rear; /* 队头、队尾指针*/}LinkQueue;Status InitQueue(LinkQueue *Q){ /* 构造一个空队列Q */(*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));if(!(*Q).front)exit(OVERFLOW);(*Q).front->next=NULL;return OK;}Status QueueEmpty(LinkQueue Q){ /* 若Q为空队列,则返回TRUE,否则返回FALSE */if(Q.front==Q.rear)return TRUE;elsereturn FALSE;}Status EnQueue(LinkQueue *Q,QElemType e){ /* 插入元素e为Q的新的队尾元素*/QueuePtr p=(QueuePtr)malloc(sizeof(QNode));if(!p) /* 存储分配失败*/exit(OVERFLOW);p->data=e;p->next=NULL;(*Q).rear->next=p;(*Q).rear=p;return OK;}Status DeQueue(LinkQueue *Q,QElemType *e){ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */ QueuePtr p;if((*Q).front==(*Q).rear)return ERROR;p=(*Q).front->next;*e=p->data;(*Q).front->next=p->next;if((*Q).rear==p)(*Q).rear=(*Q).front;free(p);return OK;}Status CreateTree(PTree *T){ /* 操作结果: 构造树T */LinkQueue q;QElemType p,qq;int i=1,j,l;char c[MAX_TREE_SIZE]; /* 临时存放孩子结点数组*/InitQueue(&q); /* 初始化队列*/printf("请输入根结点(字符型,空格为空): ");scanf("%c%*c",&(*T).nodes[0].data); /* 根结点序号为0,%*c吃掉回车符*/if((*T).nodes[0].data!=Nil) /* 非空树*/{(*T).nodes[0].parent=-1; /* 根结点无双亲*/=(*T).nodes[0].data;qq.num=0;EnQueue(&q,qq); /* 入队此结点*/while(i<MAX_TREE_SIZE&&!QueueEmpty(q)) /* 数组未满且队不空*/{DeQueue(&q,&qq); /* 出队一个结点*/printf("请按长幼顺序输入结点%c的所有孩子: ",);gets(c);l=strlen(c);for(j=0;j<l;j++){(*T).nodes[i].data=c[j];(*T).nodes[i].parent=qq.num;=c[j];p.num=i;EnQueue(&q,p); /* 入队此结点*/i++;}}if(i>MAX_TREE_SIZE){printf("结点数超过数组容量\n");exit(OVERFLOW);}(*T).n=i;}else(*T).n=0;return OK;}#define ClearTree InitTree /* 二者操作相同*/Status TreeEmpty(PTree T){ /* 初始条件: 树T存在。
操作结果: 若T为空树,则返回TRUE,否则返回FALSE */ if(T.n)return FALSE;elsereturn TRUE;}int TreeDepth(PTree T){ /* 初始条件: 树T存在。
操作结果: 返回T的深度*/int k,m,def,max=0;for(k=0;k<T.n;++k){def=1; /* 初始化本际点的深度*/m=T.nodes[k].parent;while(m!=-1){m=T.nodes[m].parent;def++;}if(max<def)max=def;}return max; /* 最大深度*/}TElemType Root(PTree T){ /* 初始条件: 树T存在。
操作结果: 返回T的根*/int i;for(i=0;i<T.n;i++)if(T.nodes[i].parent<0)return T.nodes[i].data;return Nil;}TElemType Value(PTree T,int i){ /* 初始条件: 树T存在,i是树T中结点的序号。
操作结果: 返回第i个结点的值*/ if(i<T.n)return T.nodes[i].data;elsereturn Nil;}Status Assign(PTree *T,TElemType cur_e,TElemType value){ /* 初始条件: 树T存在,cur_e是树T中结点的值。
操作结果: 改cur_e为value */ int j;for(j=0;j<(*T).n;j++){if((*T).nodes[j].data==cur_e){(*T).nodes[j].data=value;return OK;}}return ERROR;}TElemType Parent(PTree T,TElemType cur_e){ /* 初始条件: 树T存在,cur_e是T中某个结点*//* 操作结果: 若cur_e是T的非根结点,则返回它的双亲,否则函数值为"空"*/int j;for(j=1;j<T.n;j++) /* 根结点序号为0 */if(T.nodes[j].data==cur_e)return T.nodes[T.nodes[j].parent].data;return Nil;}TElemType LeftChild(PTree T,TElemType cur_e){ /* 初始条件: 树T存在,cur_e是T中某个结点*//* 操作结果: 若cur_e是T的非叶子结点,则返回它的最左孩子,否则返回"空"*/int i,j;for(i=0;i<T.n;i++)if(T.nodes[i].data==cur_e) /* 找到cur_e,其序号为i */break;for(j=i+1;j<T.n;j++) /* 根据树的构造函数,孩子的序号>其双亲的序号*/if(T.nodes[j].parent==i) /* 根据树的构造函数,最左孩子(长子)的序号<其它孩子的序号*/return T.nodes[j].data;return Nil;}TElemType RightSibling(PTree T,TElemType cur_e){ /* 初始条件: 树T存在,cur_e是T中某个结点*//* 操作结果: 若cur_e有右(下一个)兄弟,则返回它的右兄弟,否则返回"空"*/int i;for(i=0;i<T.n;i++)if(T.nodes[i].data==cur_e) /* 找到cur_e,其序号为i */break;if(T.nodes[i+1].parent==T.nodes[i].parent)/* 根据树的构造函数,若cur_e有右兄弟的话则右兄弟紧接其后*/return T.nodes[i+1].data;return Nil;}Status Print(PTree T){ /* 输出树T。
加*/int i;printf("结点个数=%d\n",T.n);printf(" 结点双亲\n");for(i=0;i<T.n;i++){printf(" %c",Value(T,i)); /* 结点*/if(T.nodes[i].parent>=0) /* 有双亲*/printf(" %c",Value(T,T.nodes[i].parent)); /* 双亲*/printf("\n");}return OK;}Status InsertChild(PTree *T,TElemType p,int i,PTree c){ /* 初始条件: 树T存在,p是T中某个结点,1≤i≤p所指结点的度+1,非空树c与T不相交*/ /* 操作结果: 插入c为T中p结点的第i棵子树*/int j,k,l,f=1,n=0; /* 设交换标志f的初值为1,p的孩子数n的初值为0 */PTNode t;if(!TreeEmpty(*T)) /* T不空*/{for(j=0;j<(*T).n;j++) /* 在T中找p的序号*/if((*T).nodes[j].data==p) /* p的序号为j */break;l=j+1; /* 如果c是p的第1棵子树,则插在j+1处*/if(i>1) /* c不是p的第1棵子树*/{for(k=j+1;k<(*T).n;k++) /* 从j+1开始找p的前i-1个孩子*/if((*T).nodes[k].parent==j) /* 当前结点是p的孩子*/{n++; /* 孩子数加1 */if(n==i-1) /* 找到p的第i-1个孩子,其序号为k1 */break;}l=k+1; /* c插在k+1处*/} /* p的序号为j,c插在l处*/if(l<(*T).n) /* 插入点l不在最后*/for(k=(*T).n-1;k>=l;k--) /* 依次将序号l以后的结点向后移c.n个位置*/{(*T).nodes[k+c.n]=(*T).nodes[k];if((*T).nodes[k].parent>=l)(*T).nodes[k+c.n].parent+=c.n;}for(k=0;k<c.n;k++){(*T).nodes[l+k].data=c.nodes[k].data; /* 依次将树c的所有结点插于此处*/(*T).nodes[l+k].parent=c.nodes[k].parent+l;}(*T).nodes[l].parent=j; /* 树c的根结点的双亲为p */(*T).n+=c.n; /* 树T的结点数加c.n个*/while(f){ /* 从插入点之后,将结点仍按层序排列*/f=0; /* 交换标志置0 */for(j=l;j<(*T).n-1;j++)if((*T).nodes[j].parent>(*T).nodes[j+1].parent){/* 如果结点j的双亲排在结点j+1的双亲之后(树没有按层序排列),交换两结点*/t=(*T).nodes[j];(*T).nodes[j]=(*T).nodes[j+1];(*T).nodes[j+1]=t;f=1; /* 交换标志置1 */for(k=j;k<(*T).n;k++) /* 改变双亲序号*/if((*T).nodes[k].parent==j)(*T).nodes[k].parent++; /* 双亲序号改为j+1 */else if((*T).nodes[k].parent==j+1)(*T).nodes[k].parent--; /* 双亲序号改为j */}}return OK;}else /* 树T不存在*/return ERROR;}Status deleted[MAX_TREE_SIZE+1]; /* 删除标志数组(全局量) */void DeleteChild(PTree *T,TElemType p,int i){ /* 初始条件: 树T存在,p是T中某个结点,1≤i≤p所指结点的度*//* 操作结果: 删除T中结点p的第i棵子树*/int j,k,n=0;LinkQueue q;QElemType pq,qq;for(j=0;j<=(*T).n;j++)deleted[j]=0; /* 置初值为0(不删除标记) */='a'; /* 此成员不用*/InitQueue(&q); /* 初始化队列*/for(j=0;j<(*T).n;j++)if((*T).nodes[j].data==p)break; /* j为结点p的序号*/for(k=j+1;k<(*T).n;k++){if((*T).nodes[k].parent==j)n++;if(n==i)break; /* k为p的第i棵子树结点的序号*/}if(k<(*T).n) /* p的第i棵子树结点存在*/{n=0;pq.num=k;deleted[k]=1; /* 置删除标记*/n++;EnQueue(&q,pq);while(!QueueEmpty(q)){DeQueue(&q,&qq);for(j=qq.num+1;j<(*T).n;j++)if((*T).nodes[j].parent==qq.num){pq.num=j;deleted[j]=1; /* 置删除标记*/n++;EnQueue(&q,pq);}}for(j=0;j<(*T).n;j++)if(deleted[j]==1){for(k=j+1;k<=(*T).n;k++){deleted[k-1]=deleted[k];(*T).nodes[k-1]=(*T).nodes[k];if((*T).nodes[k].parent>j)(*T).nodes[k-1].parent--;}j--;}(*T).n-=n; /* n为待删除结点数*/}}void TraverseTree(PTree T,void(*Visit)(TElemType)){ /* 初始条件:二叉树T存在,Visit是对结点操作的应用函数*//* 操作结果:层序遍历树T,对每个结点调用函数Visit一次且仅一次*/ int i;for(i=0;i<T.n;i++)Visit(T.nodes[i].data);printf("\n");}void vi(TElemType c){printf("%c ",c);}void main(){int i;PTree T,p;TElemType e,e1;InitTree(&T);printf("构造空树后,树空否? %d(1:是0:否) 树根为%c 树的深度为%d\n",TreeEmpty(T),Root(T),TreeDepth(T));CreateTree(&T);printf("构造树T后,树空否? %d(1:是0:否) 树根为%c 树的深度为%d\n",TreeEmpty(T),Root(T),TreeDepth(T));printf("层序遍历树T:\n");TraverseTree(T,vi);printf("请输入待修改的结点的值新值: ");scanf("%c%*c%c%*c",&e,&e1);Assign(&T,e,e1);printf("层序遍历修改后的树T:\n");TraverseTree(T,vi);printf("%c的双亲是%c,长子是%c,下一个兄弟是%c\n",e1,Parent(T,e1),LeftChild(T,e1),RightSibling(T,e1));printf("建立树p:\n");InitTree(&p);CreateTree(&p);printf("层序遍历树p:\n");TraverseTree(p,vi);printf("将树p插到树T中,请输入T中p的双亲结点子树序号: ");scanf("%c%d%*c",&e,&i);InsertChild(&T,e,i,p);Print(T);printf("删除树T中结点e的第i棵子树,请输入e i: ");scanf("%c%d",&e,&i);DeleteChild(&T,e,i);Print(T);}。