二叉树层次遍历
二叉树的遍历及常用算法
⼆叉树的遍历及常⽤算法⼆叉树的遍历及常⽤算法遍历的定义:按照某种次序访问⼆叉树上的所有结点,且每个节点仅被访问⼀次;遍历的重要性:当我们需要对⼀颗⼆叉树进⾏,插⼊,删除,查找等操作时,通常都需要先遍历⼆叉树,所有说:遍历是⼆叉树的基本操作;遍历思路:⼆叉树的数据结构是递归定义(每个节点都可能包含相同结构的⼦节点),所以遍历也可以使⽤递归,即结点不为空则继续递归调⽤每个节点都有三个域,数据与,左孩⼦指针和右孩⼦之指针,每次遍历只需要读取数据,递归左⼦树,递归右⼦树,这三个操作三种遍历次序:根据访问三个域的不同顺序,可以有多种不同的遍历次序,⽽通常对于⼦树的访问都按照从左往右的顺序;设:L为遍历左⼦树,D为访问根结点,R为遍历右⼦树,且L必须位于R的前⾯可以得出以下三种不同的遍历次序:先序遍历操作次序为DLR,⾸先访问根结点,其次遍历根的左⼦树,最后遍历根右⼦树,对每棵⼦树同样按这三步(先根、后左、再右)进⾏中序遍历操作次序为LDR,⾸先遍历根的左⼦树,其次访问根结点,最后遍历根右⼦树,对每棵⼦树同样按这三步(先左、后根、再右)进⾏后序遍历操作次序为LRD,⾸先遍历根的左⼦树,其次遍历根的右⼦树,最后访问根结点,对每棵⼦树同样按这三步(先左、后右、最后根)进⾏层次遍历层次遍历即按照从上到下从左到右的顺序依次遍历所有节点,实现层次遍历通常需要借助⼀个队列,将接下来要遍历的结点依次加⼊队列中;遍历的应⽤“遍历”是⼆叉树各种操作的基础,可以在遍历过程中对结点进⾏各种操作,如:对于⼀棵已知⼆叉树求⼆叉树中结点的个数求⼆叉树中叶⼦结点的个数;求⼆叉树中度为1的结点个数求⼆叉树中度为2的结点个数5求⼆叉树中⾮终端结点个数交换结点左右孩⼦判定结点所在层次等等...C语⾔实现:#include <stdio.h>//⼆叉链表数据结构定义typedef struct TNode {char data;struct TNode *lchild;struct TNode *rchild;} *BinTree, BinNode;//初始化//传⼊⼀个指针令指针指向NULLvoid initiate(BinTree *tree) {*tree = NULL;}//创建树void create(BinTree *BT) {printf("输⼊当前结点值: (0则创建空节点)\n");char data;scanf(" %c", &data);//连续输⼊整形和字符时.字符变量会接受到换⾏,所以加空格if (data == 48) {*BT = NULL;return;} else {//创建根结点//注意开辟的空间⼤⼩是结构体的⼤⼩⽽不是结构体指针⼤⼩,写错了不会⽴马产⽣问题,但是后续在其中存储数据时极有可能出现内存访问异常(飙泪....) *BT = malloc(sizeof(struct TNode));//数据域赋值(*BT)->data = data;printf("输⼊节点 %c 的左孩⼦ \n", data);create(&((*BT)->lchild));//递归创建左⼦树printf("输⼊节点 %c 的右孩⼦ \n", data);create(&((*BT)->rchild));//递归创建右⼦树}}//求双亲结点(⽗结点)BinNode *Parent(BinTree tree, char x) {if (tree == NULL)return NULL;else if ((tree->lchild != NULL && tree->lchild->data == x) || (tree->rchild != NULL && tree->rchild->data == x))return tree;else{BinNode *node1 = Parent(tree->lchild, x);BinNode *node2 = Parent(tree->rchild, x);return node1 != NULL ? node1 : node2;}}//先序遍历void PreOrder(BinTree tree) {if (tree) {//输出数据printf("%c ", tree->data);//不为空则按顺序继续递归判断该节点的两个⼦节点PreOrder(tree->lchild);PreOrder(tree->rchild);}}//中序void InOrder(BinTree tree) {if (tree) {InOrder(tree->lchild);printf("%c ", tree->data);InOrder(tree->rchild);}}//后序void PostOrder(BinTree tree) {if (tree) {PostOrder(tree->lchild);PostOrder(tree->rchild);printf("%c ", tree->data);}}//销毁结点递归free所有节点void DestroyTree(BinTree *tree) {if (*tree != NULL) {printf("free %c \n", (*tree)->data);if ((*tree)->lchild) {DestroyTree(&((*tree)->lchild));}if ((*tree)->rchild) {DestroyTree(&((*tree)->rchild));}free(*tree);*tree = NULL;}}// 查找元素为X的结点使⽤的是层次遍历BinNode *FindNode(BinTree tree, char x) {if (tree == NULL) {return NULL;}//队列BinNode *nodes[1000] = {};//队列头尾位置int front = 0, real = 0;//将根节点插⼊到队列尾nodes[real] = tree;real += 1;//若队列不为空则继续while (front != real) {//取出队列头结点输出数据BinNode *current = nodes[front];if (current->data == x) {return current;}front++;//若当前节点还有⼦(左/右)节点则将结点加⼊队列if (current->lchild != NULL) {nodes[real] = current->lchild;real++;}if (current->rchild != NULL) {nodes[real] = current->rchild;real++;}}return NULL;}//层次遍历// 查找元素为X的结点使⽤的是层次遍历void LevelOrder(BinTree tree) {if (tree == NULL) {return;}//队列BinNode *nodes[1000] = {};//队列头尾位置int front = 0, real = 0;//将根节点插⼊到队列尾nodes[real] = tree;real += 1;//若队列不为空则继续while (front != real) {//取出队列头结点输出数据BinNode *current = nodes[front];printf("%2c", current->data);front++;//若当前节点还有⼦(左/右)节点则将结点加⼊队列if (current->lchild != NULL) {nodes[real] = current->lchild;real++;}if (current->rchild != NULL) {nodes[real] = current->rchild;real++;}}}//查找x的左孩⼦BinNode *Lchild(BinTree tree, char x) {BinTree node = FindNode(tree, x);if (node != NULL) {return node->lchild;}return NULL;}//查找x的右孩⼦BinNode *Rchild(BinTree tree, char x) {BinTree node = FindNode(tree, x);if (node != NULL) {return node->rchild;}return NULL;}//求叶⼦结点数量int leafCount(BinTree *tree) {if (*tree == NULL)return 0;//若左右⼦树都为空则该节点为叶⼦,且后续不⽤接续递归了else if (!(*tree)->lchild && !(*tree)->rchild)return 1;else//若当前结点存在⼦树,则递归左右⼦树, 结果相加return leafCount(&((*tree)->lchild)) + leafCount(&((*tree)->rchild));}//求⾮叶⼦结点数量int NotLeafCount(BinTree *tree) {if (*tree == NULL)return 0;//若该结点左右⼦树均为空,则是叶⼦,且不⽤继续递归else if (!(*tree)->lchild && !(*tree)->rchild)return 0;else//若当前结点存在左右⼦树,则是⾮叶⼦结点(数量+1),在递归获取左右⼦树中的⾮叶⼦结点,结果相加 return NotLeafCount(&((*tree)->lchild)) + NotLeafCount(&((*tree)->rchild)) + 1;}//求树的⾼度(深度)int DepthCount(BinTree *tree) {if (*tree == NULL)return 0;else{//当前节点不为空则深度+1 在加上⼦树的⾼度,int lc = DepthCount(&((*tree)->lchild)) + 1;int rc = DepthCount(&((*tree)->rchild)) + 1;return lc > rc?lc:rc;// 取两⼦树深度的最⼤值 }}//删除左⼦树void RemoveLeft(BinNode *node){if (!node)return;if (node->lchild)DestroyTree(&(node->lchild));node->lchild = NULL;}//删除右⼦树void RemoveRight(BinNode *node){if (!node)return;if (node->rchild)DestroyTree(&(node->rchild));node->rchild = NULL;}int main() {BinTree tree;create(&tree);BinNode *node = Parent(tree, 'G');printf("G的⽗结点为%c\n",node->data);BinNode *node2 = Lchild(tree, 'D');printf("D的左孩⼦结点为%c\n",node2->data);BinNode *node3 = Rchild(tree, 'D');printf("D的右孩⼦结点为%c\n",node3->data);printf("先序遍历为:");PreOrder(tree);printf("\n");printf("中序遍历为:");InOrder(tree);printf("\n");printf("后序遍历为:");PostOrder(tree);printf("\n");printf("层次遍历为:");LevelOrder(tree);printf("\n");int a = leafCount(&tree);printf("叶⼦结点数为%d\n",a);int b = NotLeafCount(&tree);printf("⾮叶⼦结点数为%d\n",b);int c = DepthCount(&tree);printf("深度为%d\n",c);//查找F节点BinNode *node4 = FindNode(tree,'C');RemoveLeft(node4);printf("删除C的左孩⼦后遍历:");LevelOrder(tree);printf("\n");RemoveRight(node4);printf("删除C的右孩⼦后遍历:");LevelOrder(tree);printf("\n");//销毁树printf("销毁树 \n");DestroyTree(&tree);printf("销毁后后遍历:");LevelOrder(tree);printf("\n");printf("Hello, World!\n");return 0;}测试:测试数据为下列⼆叉树:运⾏程序复制粘贴下列内容:ABDGHECKFIJ特别感谢:iammomo。
二叉树遍历操作的基本应用(复制、求深度、求叶子数、求节点数等)
二叉树遍历操作的基本应用(复制、求深度、求叶子数、求节点数等)1. 引言1.1 概述二叉树是计算机科学领域中常用的数据结构之一,具有广泛的应用场景。
在二叉树的操作中,遍历是其中最基本和常见的操作之一。
通过遍历,我们可以按照特定规则依次访问二叉树中的所有节点。
本文将探讨二叉树遍历操作的基本应用,包括复制、求深度、求叶子数、求节点数等。
这些操作不仅在实际开发中有重要意义,而且对于理解和掌握二叉树数据结构及其相关算法也具有重要作用。
1.2 文章结构本文将分为五个部分进行论述。
首先,在引言部分(第1节)我们将概述文章的主题和目标。
紧接着,在第2节中,我们将介绍二叉树遍历的基本应用,包括复制、求深度、求叶子数和求节点数等。
在第3节中,我们将详细解析这些基本应用,并给出相应算法和实例分析。
接下来,在第4节中,我们将通过实际案例应用来验证并讨论这些基本应用的性能与适用范围。
最后,在第5节中总结全文内容,并对未来研究方向进行展望。
1.3 目的本文的目的是通过对二叉树遍历操作的基本应用进行详细剖析,帮助读者深入理解和掌握二叉树数据结构及其相关算法。
同时,我们希望通过实际案例应用与讨论,探讨如何优化算法性能、提高效率以及适应大规模二叉树遍历问题。
通过本文的阅读,读者将能够全面了解并应用二叉树遍历操作的基本方法,在实际开发中解决相关问题,并为进一步研究和探索提供思路与参考。
该部分主要介绍了文章的概述、结构和目的,引导读者了解全文并明确阅读目标。
2. 二叉树遍历的基本应用:二叉树是一种常见的数据结构,其遍历操作可以应用于多种实际问题中。
本节将介绍四个基本的二叉树遍历应用:复制二叉树、求二叉树的深度、求二叉树的叶子数和求二叉树的节点数。
2.1 复制二叉树:复制一个二叉树意味着创建一个与原始二叉树结构完全相同的新二叉树。
该应用场景在涉及对原始数据进行修改或者对数据进行独立操作时非常有用。
复制操作可以以递归方式实现,通过先复制左子树,再复制右子树,最后创建一个与当前节点值相等的新节点来完成。
二叉树,树,森林遍历之间的对应关系
二叉树,树,森林遍历之间的对应关系一、引言在计算机科学中,数据结构是非常重要的知识点之一。
而树这一数据结构,作为基础的数据结构之一,在软件开发中有着广泛的应用。
本文将重点探讨二叉树、树和森林遍历之间的对应关系,帮助读者更加全面地理解这些概念。
二、二叉树1. 二叉树的定义二叉树是一种特殊的树结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。
二叉树可以为空,也可以是一棵空树。
2. 二叉树的遍历在二叉树中,有三种常见的遍历方式,分别是前序遍历、中序遍历和后序遍历。
在前序遍历中,节点的访问顺序是根节点、左子树、右子树;在中序遍历中,节点的访问顺序是左子树、根节点、右子树;在后序遍历中,节点的访问顺序是左子树、右子树、根节点。
3. 二叉树的应用二叉树在计算机科学领域有着广泛的应用,例如用于构建文件系统、在数据库中存储有序数据、实现算法中的搜索和排序等。
掌握二叉树的遍历方式对于理解这些应用场景非常重要。
三、树1. 树的定义树是一种抽象数据类型,由n(n>0)个节点组成一个具有层次关系的集合。
树的特点是每个节点都有零个或多个子节点,而这些子节点又构成了一颗子树。
树中最顶层的节点称为根节点。
2. 树的遍历树的遍历方式有先根遍历、后根遍历和层次遍历。
在先根遍历中,节点的访问顺序是根节点、子树1、子树2...;在后根遍历中,节点的访问顺序是子树1、子树2...,根节点;在层次遍历中,节点的访问顺序是从上到下、从左到右依次访问每个节点。
3. 树的应用树广泛用于分层数据的表示和操作,例如在计算机网络中的路由算法、在操作系统中的文件系统、在程序设计中的树形结构等。
树的遍历方式对于处理这些应用来说至关重要。
四、森林1. 森林的定义森林是n(n>=0)棵互不相交的树的集合。
每棵树都是一颗独立的树,不存在交集。
2. 森林的遍历森林的遍历方式是树的遍历方式的超集,对森林进行遍历就是对每棵树进行遍历的集合。
3. 森林的应用森林在实际编程中经常用于解决多个独立树结构的问题,例如在数据库中对多个表进行操作、在图像处理中对多个图形进行处理等。
二叉树遍历(前序、中序、后序、层次、广度优先、深度优先遍历)
⼆叉树遍历(前序、中序、后序、层次、⼴度优先、深度优先遍历)⽬录转载:⼆叉树概念⼆叉树是⼀种⾮常重要的数据结构,⾮常多其他数据结构都是基于⼆叉树的基础演变⽽来的。
对于⼆叉树,有深度遍历和⼴度遍历,深度遍历有前序、中序以及后序三种遍历⽅法,⼴度遍历即我们寻常所说的层次遍历。
由于树的定义本⾝就是递归定义,因此採⽤递归的⽅法去实现树的三种遍历不仅easy理解并且代码⾮常简洁,⽽对于⼴度遍历来说,须要其他数据结构的⽀撑。
⽐⽅堆了。
所以。
对于⼀段代码来说,可读性有时候要⽐代码本⾝的效率要重要的多。
四种基本的遍历思想前序遍历:根结点 ---> 左⼦树 ---> 右⼦树中序遍历:左⼦树---> 根结点 ---> 右⼦树后序遍历:左⼦树 ---> 右⼦树 ---> 根结点层次遍历:仅仅需按层次遍历就可以⽐如。
求以下⼆叉树的各种遍历前序遍历:1 2 4 5 7 8 3 6中序遍历:4 2 7 5 8 1 3 6后序遍历:4 7 8 5 2 6 3 1层次遍历:1 2 3 4 5 6 7 8⼀、前序遍历1)依据上⽂提到的遍历思路:根结点 ---> 左⼦树 ---> 右⼦树,⾮常easy写出递归版本号:public void preOrderTraverse1(TreeNode root) {if (root != null) {System.out.print(root.val+" ");preOrderTraverse1(root.left);preOrderTraverse1(root.right);}}2)如今讨论⾮递归的版本号:依据前序遍历的顺序,优先訪问根结点。
然后在訪问左⼦树和右⼦树。
所以。
对于随意结点node。
第⼀部分即直接訪问之,之后在推断左⼦树是否为空,不为空时即反复上⾯的步骤,直到其为空。
若为空。
则须要訪问右⼦树。
注意。
在訪问过左孩⼦之后。
二叉树的四种遍历方式
二叉树的四种遍历方式
(实用版)
目录
1.前序遍历
2.中序遍历
3.后序遍历
4.层次遍历
正文
二叉树是一种非常重要的数据结构,它在计算机科学和信息处理领域有着广泛的应用。
在二叉树中,有四种常见的遍历方式,分别是前序遍历、中序遍历、后序遍历和层次遍历。
1.前序遍历:先访问根节点,然后遍历左子树,最后遍历右子树。
这种遍历方式的特点是先访问根节点,然后按照左子树、右子树的顺序进行遍历。
2.中序遍历:先遍历左子树,然后访问根节点,最后遍历右子树。
这种遍历方式的特点是先遍历左子树,然后访问根节点,最后遍历右子树。
3.后序遍历:先遍历左子树,然后遍历右子树,最后访问根节点。
这种遍历方式的特点是先遍历左子树,然后遍历右子树,最后访问根节点。
4.层次遍历:按照树的层次,从上到下,从左到右进行遍历。
这种遍历方式的特点是按照树的层次进行遍历,每一层的节点都会被依次访问。
第1页共1页。
数据结构-二叉树的存储结构和遍历
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.6 树与二叉树树是一种简单的非线性结构,所有元素之间具有明显的层次特性。
在树结构中,没有前件的结点只有一个,称为树的根结点,简称树的根。
每一个结点可以有多个后件,称为该结点的子结点。
没有后件的结点称为叶子结点。
在树结构中,一个结点所拥有的后件的个数称为该结点的度,所有结点中最大的度称为树的度。
为该结点的左子树与右子树。
二叉树的基本性质:必考的题目(1)在二叉树的第k层上,最多有2k-1(k≥1)个结点;(2)深度为m的二叉树最多有2m-1个结点;(3)度为0的结点(即叶子结点)总是比度为2的结点多一个;(4)二叉树中 n = n0 +n1 +n2k层上有2k-1个结点深度为m的满二叉树有2m-1个结点。
若干结点。
二叉树的遍历:(一般画个图要你把顺序写出来)后序遍历(访问根结点在访问左子树和访问右子树之后)重点题型:二叉树的遍历例1:某二叉树的前序序列为ABCD,中序序列为DCBA,则后序序列为(DCBA )。
【解析】前序序列为ABCD,可知A为根结点。
根据中序序列为DCBA可知DCB是A的左子树。
根据前序序列可知B是CD的根结点。
再根据中序序列可知DC是结点B的左子树。
根据前序序列可知,C是D的根结点,故后序序列为DCBA例2:对下列二叉树进行前序遍历的结果为 ABDYECFXZ例3:设二叉树如下,则后序序列为 DGEBHFCA【解析】本题中前序遍历为ABDEGCFH,中序遍历为DBGEAFHC,后序遍历为DGEBHFCA完全二叉树指除最后一层外,每一层上的结点数均达到最大值,在最后堆排序问题:例1:已知前序序列与中序序列均为ABCDEFGH,求后序序列【解析】设根节点为D≠0,左子树为L,右子树为R,有遍历顺序为:前:D-L-R 已知ABCDEFGH中:L-D-R 已知ABCDEFGH后:L-R-D 待求由此可知,L=0,D-R= ABCDEFGH故R-D=HGFEDCBA,即后序序列= HGFEDCBA变式训练1:已知后序序列与中序序列均为ABCDEFGH,求前序序列答案:HGFEDCBA,(这次R=0)结论:若前序序列与中序序列均为某序列,则后序序列为该序列的倒序,且为折线;同样地,若后序序列与中序序列均为某序列,则前序序列为该序列的倒序,且为折线例2:已知前序序列=ABCD,中序序列=DCBA,求后序序列【解析】设根节点为D≠0,左子树为L,右子树为R,有遍历顺序为:前:D-L-R 已知ABCD中:L-D-R 已知DCBA后:L-R-D 待求因为ABCD与DCBA正好相反,由此可知,R=0所以D-L=ABCD,即L-D=DCBA所以后序序列= DCBA变式训练2-1:中序序列=BDCA,后序序列=DCBA,求前序序列【解析】设根节点为D≠0,左子树为L,右子树为R,有遍历顺序为:前:D-L-R 待求中:L-D-R 已知BDC,A后:L-R-D 已知DCB,A通过观察可知,R=0,L={B,D,C},D=A中、后变换时,{B,D,C}发生了变化,说明左子树结构特殊,进一步令中’:L’-D’-R’已知B,DC后’:L’-R’-D’已知DC,B可知L’=0,即D’=B,R’= DC可以画出二叉树示意图为:Array所以前序序列= ABCD变式训练2-2:中序序列=ABC,后序序列=CBA,求前序序列【解析】设根节点为D≠0,左子树为L,右子树为R,有遍历顺序为:前:D-L-R 待求中:L-D-R 已知ABC后:L-R-D 已知通过观察可知,L=0,D-R=ABC,R-D=CBA所以前序序列=D-L-R= D-R=ABC变式训练2-3:前序序列=ABC,中序序列=CBA,求后序序列【解析】设根节点为D≠0,左子树为L,右子树为R,有遍历顺序为:前:D-L-R 已知A,BC中:L-D-R 已知CB,A后:L-R-D 待求通过观察可知,D=A ,L={B,C},R=0所以后序序列=CBA (一边偏)题型二:求二叉树的深度。
二叉树遍历(前中后序遍历,三种方式)
⼆叉树遍历(前中后序遍历,三种⽅式)⽬录刷题中碰到⼆叉树的遍历,就查找了⼆叉树遍历的⼏种思路,在此做个总结。
对应的LeetCode题⽬如下:,,,接下来以前序遍历来说明三种解法的思想,后⾯中序和后续直接给出代码。
⾸先定义⼆叉树的数据结构如下://Definition for a binary tree node.struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}};前序遍历,顺序是“根-左-右”。
使⽤递归实现:递归的思想很简单就是我们每次访问根节点后就递归访问其左节点,左节点访问结束后再递归的访问右节点。
代码如下:class Solution {public:vector<int> preorderTraversal(TreeNode* root) {if(root == NULL) return {};vector<int> res;helper(root,res);return res;}void helper(TreeNode *root, vector<int> &res){res.push_back(root->val);if(root->left) helper(root->left, res);if(root->right) helper(root->right, res);}};使⽤辅助栈迭代实现:算法为:先把根节点push到辅助栈中,然后循环检测栈是否为空,若不空,则取出栈顶元素,保存值到vector中,之后由于需要想访问左⼦节点,所以我们在将根节点的⼦节点⼊栈时要先经右节点⼊栈,再将左节点⼊栈,这样出栈时就会先判断左⼦节点。
代码如下:class Solution {public:vector<int> preorderTraversal(TreeNode* root) {if(root == NULL) return {};vector<int> res;stack<TreeNode*> st;st.push(root);while(!st.empty()){//将根节点出栈放⼊结果集中TreeNode *t = st.top();st.pop();res.push_back(t->val);//先⼊栈右节点,后左节点if(t->right) st.push(t->right);if(t->left) st.push(t->left);}return res;}};Morris Traversal⽅法具体的详细解释可以参考如下链接:这种解法可以实现O(N)的时间复杂度和O(1)的空间复杂度。
数据结构实验三——二叉树基本操作及运算实验报告
《数据结构与数据库》实验报告实验题目二叉树的基本操作及运算一、需要分析问题描述:实现二叉树(包括二叉排序树)的建立,并实现先序、中序、后序和按层次遍历,计算叶子结点数、树的深度、树的宽度,求树的非空子孙结点个数、度为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,失败。
计算机考研408 数据结构算法总结及二叉树三种遍历算法的源码背诵版
数据结构算法背诵一、线性表1.逆转顺序表中的所有元素算法思想:第一个元素和最后一个元素对调,第二个元素和倒数第二个元素对调,……,依此类推。
void Reverse(int A[], int n){int i, t;for (i=0; i < n/2; i++){t = A[i];A[i] = A[n-i-1];A[n-i-1] = t;}}2.删除线性链表中数据域为item的所有结点算法思想:先从链表的第2个结点开始,从前往后依次判断链表中的所有结点是否满足条件,若某个结点的数据域为item,则删除该结点。
最后再回过头来判断链表中的第1个结点是否满足条件,若满足则将其删除。
void PurgeItem(LinkList &list){LinkList p, q = list;p = list->next;while (p != NULL){if (p->data == item) {q->next = p->next;free(p);p = q->next;} else {q = p;p = p->next;}}if (list->data == item){q = list;list = list->next;free(q);}}3.逆转线性链表void Reverse(LinkList &list){LinkList p, q, r;p = list;q = NULL;while (p != NULL){r = q;q = p;p = p->next;q->next = r;}list = q;}4.复制线性链表(递归)LinkList Copy(LinkList lista){LinkList listb;if (lista == NULL)return NULL;else {listb = (LinkList)malloc(sizeof(LNode));listb->data = lista->data;listb->next = Copy(lista->next);return listb;}}5.将两个按值有序排列的非空线性链表合并为一个按值有序的线性链表LinkList MergeList(LinkList lista, LinkList listb){LinkList listc, p = lista, q = listb, r;// listc 指向 lista 和 listb 所指结点中较小者if (lista->data <= listb->data) {listc = lista;r = lista;p = lista->next;} else {listc = listb;r = listb;q = listb->next;}while (p != NULL && q != NULL){if (p->data <= q->data) {r->next = p;r = p;p = p->next;} else {r->next = q;r = q;q = q->next;}}// 将剩余结点(即未参加比较的且已按升序排列的结点)链接到整个链表后面 r->next = (p != NULL) ? p : q;return listc;}二、树1.二叉树的先序遍历(非递归算法)算法思想:若p所指结点不为空,则访问该结点,然后将该结点的地址入栈,然后再将p指向其左孩子结点;若p所指向的结点为空,则从堆栈中退出栈顶元素(某个结点的地址),将p指向其右孩子结点。
《算法导论》读书笔记之第10章 基本数据结构之二叉树
《算法导论》读书笔记之第10章基本数据结构之二叉树摘要书中第10章10.4小节介绍了有根树,简单介绍了二叉树和分支数目无限制的有根树的存储结构,而没有关于二叉树的遍历过程。
为此对二叉树做个简单的总结,介绍一下二叉树基本概念、性质、二叉树的存储结构和遍历过程,主要包括先根遍历、中根遍历、后根遍历和层次遍历。
1、二叉树的定义二叉树(Binary Tree)是一种特殊的树型结构,每个节点至多有两棵子树,且二叉树的子树有左右之分,次序不能颠倒。
由定义可知,二叉树中不存在度(结点拥有的子树数目)大于2的节点。
二叉树形状如下下图所示:2、二叉树的性质(1)在二叉树中的第i层上至多有2^(i-1)个结点(i>=1)。
备注:^表示此方(2)深度为k的二叉树至多有2^k-1个节点(k>=1)。
(3)对任何一棵二叉树T,如果其终端结点数目为n0,度为2的节点数目为n2,则n0=n2+1。
满二叉树:深度为k且具有2^k-1个结点的二叉树。
即满二叉树中的每一层上的结点数都是最大的结点数。
完全二叉树:深度为k具有n个结点的二叉树,当且仅当每一个结点与深度为k的满二叉树中的编号从1至n的结点一一对应。
可以得到一般结论:满二叉树和完全二叉树是两种特殊形态的二叉树,满二叉树肯定是完全二叉树,但完全二叉树不不一定是满二叉树。
举例如下图是所示:(4)具有n个节点的完全二叉树的深度为log2n + 1。
3、二叉树的存储结构可以采用顺序存储数组和链式存储二叉链表两种方法来存储二叉树。
经常使用的二叉链表方法,因为其非常灵活,方便二叉树的操作。
二叉树的二叉链表存储结构如下所示:1 typedef struct binary_tree_node2 {3 int elem;4 struct binary_tree_node *left;5 struct binary_tree_node *right;6 }binary_tree_node,*binary_tree;举例说明二叉链表存储过程,如下图所示:从图中可以看出:在还有n个结点的二叉链表中有n+1个空链域。
二叉树的遍历及相关题目
⼆叉树的遍历及相关题⽬⼆叉树的遍历及相关题⽬1.1⼆叉树遍历的概念⼆叉树结构体的定义:typedef struct node{ ElemType data; struct node * lchild; struct node * rchild;}⼆叉树的遍历是指按照⼀定的次序访问⼆叉树中的所有的节点,并且每个节点仅访问⼀次的过程。
若规定先遍历左⼦树,后遍历右⼦树,则对于⾮空⼆叉树,可得到如下3种递归的遍历⽅法:(1)先序遍历访问根节点,先序遍历左⼦树,先序遍历右⼦树。
(根,左,右)(2)中序遍历中序遍历左⼦树,访问根节点,中序遍历右⼦树。
(左,根,右)(3)后序遍历后序遍历左⼦树,后序遍历右⼦树,访问根节点。
(左,右,根)除此之外也有层次遍历。
先访问根节点,在从左到右访问第⼆层的所有节点,从左到右访问第三层的所有节点......1.2⼆叉树遍历递归算法先序遍历递归算法:void PreOrder(BTNode * b){ if(n != NULL) { cout<<b->data; PreOrder(b->lchild); PreOrder(b->rchild); }}中序遍历递归算法void InOrder(BTNode * b){ if(n != NULL) { InOrder(b->lchild); cout<<b->data; InOrder(b->rchild); }}后序遍历递归算法:void PostOrder(BTNode * b){ if(b != NULL) { PostOrder(b->lchild); PostOrder(b->rchild); cout<<b->data; }}题⽬1:输出⼀个给定⼆叉树的所有的叶⼦节点:void DispLeaf(BTNode * b){ if(b != NULL) { if(b->lchild == NULL && b->rchild == NULL) cout<<b->data; DispLeaf(b->lchild); DispLeaf(b->rchild); }}以上算法采⽤先序遍历输出了所有的叶⼦节点,所以叶⼦节点是从左到右输出的。
第六章树2
有六种遍历方法:D L R,L D R,L R D,D R L,R D L,R L D D R, R, D, L, L, 约定: R, R, 约定:先左后右,有三种遍历方法: D L R,L D R,L R D , 分别称为先序遍历,中序遍历,后序遍历
3
A,先序遍历(D L R)(前缀表示) D R 若二叉树非空 (1)访问根结点; (2)先序遍历左子树; D (3)先序遍历右子树; ; 例:先序遍历右图所示的二叉树
……
if (k== -1) T=NULL; else { } } // } // CrtBT
18
T=(BiTNode*)malloc(sizeof(BiTNode)); T->data = pre[ps]; if (k==is) T->Lchild = NULL; else CrtBT(T->Lchild, pre[], ino[], ps+1, is, k-is ); if (k=is+n-1) T->Rchild = NULL; else CrtBT(T->Rchild, pre[], ino[], ps+1+(k-is), k+1, n-(k-is)-1 );
2
2,对"二叉树"而言,可以有三条搜索路径: , 二叉树"而言,可以有三条搜索路径: 先上后下 先上后下的按层次遍历; 先左 先左(子树)后右 后右(子树)的遍历; 后右 先右 先右(子树)后左 后左(子树)的遍历. 后左
二叉树由根,左子树,右子树三部分组成 令: D:访问根结点 L:遍历左子树 R:遍历右子树 L D R
24
4,复制二叉树
(后序遍历) 后序遍历)
其基本操作为:生成一个结点. 其基本操作为:生成一个结点. T 根元素 左子树 左子树 右子树 右子树 左子树 NEWT 根元素 右子树
二叉树节点数与形态数
二叉树节点数与形态数1.引言1.1 概述引言是文章的开端,用来介绍文章的主题和目的。
在这篇文章中,我们将讨论二叉树的节点数和形态数,并探讨它们之间的关系。
二叉树是一种常见的树形结构,具有丰富的应用场景。
节点数是指二叉树中节点的总数,而形态数则是指二叉树的不同形态的总数。
在本文中,我们将首先介绍二叉树节点数的定义和计算方法。
节点数是指二叉树中所有节点的总数,包括根节点、内部节点和叶子节点。
我们将详细介绍如何计算不同类型的二叉树的节点数,并讨论其复杂度和算法特点。
接下来,我们将介绍二叉树形态数的定义和计算方法。
形态数是指二叉树的不同形态的总数,也可以理解为二叉树的种类数量。
我们将探讨如何计算二叉树的形态数,并分析影响形态数的因素,如节点的数量、结构和顺序等。
最后,我们将研究二叉树节点数和形态数之间的关系。
我们将讨论节点数对形态数的影响,以及通过增加或删除节点如何改变二叉树的形态数。
我们还将总结文章的主要观点和结论,以及对进一步研究的建议。
通过对二叉树节点数和形态数的深入研究,我们可以更好地理解和分析二叉树的特性和应用。
本文的目的是为读者提供一个全面的了解,并激发更多关于二叉树的研究和应用的思考。
让我们开始这个有趣而挑战性的探索之旅吧。
1.2文章结构1.2 文章结构本文将详细讨论二叉树节点数与形态数的定义、计算方法以及它们之间的关系。
整篇文章分为以下几个部分:2.1 二叉树节点数的定义和计算方法在这一部分,我们将首先对二叉树节点数的定义进行介绍。
然后,我们将详细说明如何计算给定二叉树的节点数。
我们将讨论两种主要的计算方法:递归计算和迭代计算。
我们将对每种方法进行分析,并比较它们的优缺点。
最后,我们将通过一些例子来说明如何应用这些计算方法。
2.2 二叉树形态数的定义和计算方法在这一部分,我们将对二叉树形态数的定义进行介绍。
形态数指的是不同形态的二叉树的数量。
我们将详细说明如何计算给定节点数的二叉树的形态数。
层次遍历算法
层次遍历算法简介是一种二叉树遍历方式,又称为广度优先算法,它是一种从上至下、从左至右的遍历方式,最常用于树形结构进行搜索或者遍历。
可以解决一些问题,例如求二叉树的最小深度、最大深度、它的节点数、它的叶子节点数、它的某个路径等问题。
实现的方法1.使用队列实现使用队列实现是一种常用的方法。
具体步骤如下:(1)将树的根节点入队,初始化队列。
(2)当队列非空时,进行下列操作:①取出队列中的一个节点,访问该节点。
②如果该节点的左子节点不为空,则将左子节点入队。
③如果该节点的右子节点不为空,则将右子节点入队。
实现代码如下:```pythondef level_order_traversal(root):queue = []result = []if root is None:return resultqueue.append(root)while queue:node = queue.pop(0)result.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)return result```2.使用递归实现使用递归实现一般需要借助队列,并且需要知道每个节点所在的层数。
具体步骤如下:- (1)使用递归遍历左子树,直到最底层。
在遍历左子树时,需要记录当前所在的层数。
- (2)使用递归遍历右子树,直到最底层。
在遍历右子树时,需要记录当前所在的层数。
- (3)将左子树和右子树的结果合并,即可得到二叉树的层次遍历结果。
实现代码如下:```pythondef level_order_traversal(root):queue = []result = []def dfs(node, level):if not node:returnif level == len(result):result.append([])result[level].append(node.val)dfs(node.left, level+1)dfs(node.right, level+1)dfs(root, 0)return result```的应用在二叉树中的应用是十分广泛的,可以用于如下几个问题的解决:1.求最小深度二叉树的最小深度是从根节点到最近的叶子节点的距离。
数据结构二叉树遍历说课
5 教学方法分析
教法
1、讲授法 2、讲解演示法 3、讨论法
学法
1、边学边练 2、举一反三,自主学习法
6 教学过程分析1 导入Fra bibliotek2 讲授
3 练习
4 拓展
方案: • 旧知识回顾 • 提出如何遍历
二叉树的问题
意义: 采用任务驱动 法,激发学生 的学习兴趣, 为新课的学习 埋下伏笔。
方案:
方案:
• 分散重难点,分 层次教学,逐步
授课对象:大一下学期的学生。 学生特点:具备独立思考能力,对新事物接受
能力较强。
能力状态:处于数据结构的起步学习阶段,无
明显的层次及优劣的区别。
授课 策略
适当调整课堂节奏 保证整体学生的学习效果
3 教学目标
知识目标
理解并掌握二叉 树的三种遍历方 法,能够准确的 对二叉树进行三 种遍历,并能够 根据给出的两种 遍历序列还原一 棵二叉树。
1. 教材分析 2. 学情分析 3. 教学目标 4. 教学重难点 5. 教学方法分析 6. 教学过程分析
1 教材分析
数据结构(C语言版)
清华大学出版社出版,严蔚敏和吴伟民主编。 第六章第三节内容“遍历二叉树”。 重点介绍了二叉树的遍历算法,
是基础的数据结构课程。
本节课起着承上启下的作用。
2 学情分析
递进。
• 进行典型例题 的操作
• 学会一种遍历后, 找学生讲解,教
师配合演示,导 出后两种方法。 意义:
意义:
强化对遍历二
使学生充分体验
研究性学习过程, 培养学生研究思 维与能力。
叉树遍历的三
种方法的运用 和操作。
方案:
• 分组讨论: 给出先序、中 序序列,还原 一棵二叉树。
二叉树的遍历
T->rchild= CreatBiTree(); /*构造右子树*/ 扩展先序遍历序列
}
2021/2/21
return (T) ;}
A B Φ D Φ Φ C Φ 17Φ
T
T
T
ch=B
ch=Φ
Λ
T
T= Λ, Creat(T)
ch=A T
A
B creat(T L)
ΛB 返回
creat(T L)
creat(T R)
A
p=p->RChild;
}
2021/2/21
}
top
A
B
C
D
top
B
top
A
A
top
D
A
top
A
top
C
13
top
中序遍历二叉树的非递归算法:
A
void InOrder(BiTree T)
{ InitStack(&S); 相当于top=-1;
p=T;
B
C
while(p!=NULL | | !IsEmpty(S)) 相当于top==-1;
}
后序遍历二叉树的递归算法:
void PostOrder (BiTree T)
{ if(T!=NULL)
{ PostOrder (T->lchild);
PostOrder (T->rchild);
printf(T->data); }
2021/2/21
15
}
先序遍历二叉树的递归算法: void PreOder (BiTree T) { if(T! =NULL){ printf (T->data); PreOrder (T->lchild); PreOrder (T->rchild); } }
指定节点在二叉树中的层次
指定节点在二叉树中的层次摘要:一、二叉树简介1.二叉树的定义2.二叉树的重要性质二、节点层次的概念1.节点的定义2.节点的层次三、如何计算节点在二叉树中的层次1.层次的计算方法2.计算示例四、节点层次的应用1.二叉搜索树的节点查找2.平衡二叉树的节点插入与删除正文:一、二叉树简介二叉树是一种非常常见的数据结构,它由若干个节点组成,每个节点最多只有两个子节点,分别称为左子节点和右子节点。
二叉树具有以下几个重要性质:1.每个节点的左子节点的层次都小于或等于该节点的层次。
2.每个节点的右子节点的层次都小于或等于该节点的层次。
3.任意节点的左、右子树也分别为二叉树。
二、节点层次的概念在二叉树中,节点有层次的概念,层次是指从根节点到某个节点的路径上,所经过的节点数量。
根节点位于第一层,它的子节点位于第二层,以此类推。
1.节点的定义一个二叉树中的节点,包含以下属性:- 数据:节点所存储的数据。
- 左子节点:指向左侧子树的指针。
- 右子节点:指向右侧子树的指针。
2.节点的层次对于一个二叉树中的任意节点,我们可以通过计算从根节点到该节点的路径上所经过的节点数量,来得到该节点的层次。
例如,对于一个深度为3 的节点,它从根节点到该节点的路径上,需要经过3 个节点。
三、如何计算节点在二叉树中的层次在二叉树中,计算节点在树中的层次,通常采用深度优先搜索(DFS)或广度优先搜索(BFS)算法。
1.层次的计算方法- DFS:从根节点开始,沿着左子树一直向下搜索,直到遇到叶子节点或者目标节点。
在搜索过程中,记录从根节点到目标节点所经过的节点数量,这个数量就是目标节点的层次。
- BFS:从根节点开始,逐层遍历二叉树的节点。
当遍历到目标节点时,记录当前遍历到的层数,这个层数就是目标节点的层次。
2.计算示例假设有一个二叉树如下:```1/2 3/4 5```对于节点4,使用DFS 方法计算其层次:- 从根节点1 开始,找到节点4,经过的节点数量为3,因此节点4 的层次为3。
高中信息技术学科二叉树遍历题型的教学思考
高中信息技术学科二叉树遍历题型的教学思考摘要:《数据与数据结构》是浙江省高中信息技术课程的新教材,“数据结构”对于高中生来讲,属于较难的知识模块,其中“数据结构”中的二叉树的遍历(前序遍历、中序遍历、后序遍历)对于学生来讲较难理解掌握,而提供前序遍历和中序遍历或后序遍历与中序遍历,求另一种遍历这类题型对于二叉树的遍历学习有较大帮助。
关键词:数据结构二叉树遍历数据结构(Data Structure)是相互之间存在一种或多种特定关系的数据元素的集合。
常见的数据结构有数组,链表,队列,栈,树,图等。
其中树,尤其是二叉树的遍历是高中信息技术教学中的一个重点和难点。
二叉树是一种特殊的树,是一个具有n个节点的有限集合,它的所有节点的度都小于或等于2。
当n等于0时,二叉树是一棵空树;当n不等于0时,它是一棵由根节点和两颗互不相交的,分别称作这个根节点的左子树和右子树的二叉树。
1遍历所谓遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次。
树的遍历是树的一种重要的运算,从二叉树的根节点出发,节点的遍历分为三个主要步骤:对当前节点进行访问操作、遍历左边子节点、遍历右边子节点。
根据对根节点、左子树、右子树访问的顺序可分为前序遍历、中序遍历和后序遍历。
前序遍历:访问顺序为先访问根节点(N),再访问左子树(L),最后访问右子树(R),顺序为NLR。
以一颗满二叉树层次遍历顺序为ABCDEFG为例,1、先访问根节点A;2、然后访问左子树BDE,左子树再遍历,先根节点B,然后访问左节点D,最后访问右节点E;3、访问右子树CFG,先访问根节点C,再访问左节点F,最后访问右节点G。
综上前序遍历结果为ABDECFG。
中序遍历:访问顺序为先访问左子树(L),再访问根节点(N),最后访问右子树(R),顺序为LNR。
以一颗满二叉树层次遍历顺序为ABCDEFG为例,1、先访问左子树BDE,左子树再遍历,先左节点D,再访问根节点B,最后访问右节点E。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构《实验3》实验报告实验项目3:二叉树层次遍历实验结果(运行结果界面及源程序,运行结果界面放在前面):四种程序遍历的结果#define STUDENT EType #include<iostream.h>#include <stdlib.h>#include<string.h>#include<math.h>#include<iomanip.h>//二叉树链式结构定义struct STUDENT{char place[10];char name[10];char number[12];char sex[3];int age;};struct BinaryTreeNode{EType data;BinaryTreeNode *LChild;BinaryTreeNode *RChild;};typedef BinaryTreeNode BinaryTree;//队列结构定义struct QType{BinaryTreeNode *ptr;};struct Queue{QType *element;int front;int rear;int maxsize;};void CreatQueue(Queue &Q,int MaxQueueSize){//构造一个最大容量为MaxQueueSize的队列Q Q.maxsize=MaxQueueSize;Q.element=new QType[Q.maxsize+1];Q.front=0;Q.rear=0;}bool IsEmpty(Queue &Q){//判断队列是否为空if(Q.front==Q.rear)return true;return false;}bool IsFull(Queue &Q){//判断队列是否为满if(Q.front==(Q.rear+1)%(Q.maxsize+1))return true;return false;}bool GetFront(Queue &Q,QType &result){//返回队列Q中队头元素if(IsEmpty(Q))return false;result=Q.element[(Q.front+1)%(Q.maxsize+1)];return true;}bool EnQueue(Queue &Q,QType &x){//x进Q队列,返回进入队列后的状态值if(IsFull(Q))return false;Q.rear=(Q.rear+1)%(Q.maxsize+1);Q.element[Q.rear]=x;return true;}bool DeQueue(Queue &Q,QType &result){//将Q队列队头的值取至result中,并移动指针front,返回出队列后的状态值if(IsEmpty(Q))return false;Q.front=(Q.front+1)%(Q.maxsize+1);result=Q.element[Q.front];return true;}struct Node_Ptr{BinaryTreeNode *ptr;} ;void DigitalToString(char str[],int n){char temp;char k=1;int i=0;while (n && i<80){k=n%10+48;n=n/10;str[i]=k;i++;}str[i]='\0';int len=strlen(str);for (i=0;i<len/2;i++){temp=str[i];str[i]=str[len-i-1];str[len-i-1]=temp;}}char *GetOuputInformationString(int WidthOfData, char *OutputInformation, char*outputstring){//将一个元素的字符串OutputInformation转换为宽度为WidthOfData的等长字符串outputstring//例如,姓名是由四个字符组成,而WidthOfData为8,则在姓名字符串的两边分别连接两个字符,形成8个长度的字符串int left_space,right_space;int i;char left_space_string[16]={""};char right_space_string[16]={""};int add_space;int len_OutputInformation=strlen(OutputInformation); //计算OutputInformation的字符个数add_space=WidthOfData - len_OutputInformation; //计算需要补充的字符个数left_space=add_space/2; //计算OutputInformation左边需要补充的字符个数right_space=add_space-left_space; //计算OutputInformation右边需要补充的字符个数for(i=1;i<=left_space;i++) //形成OutputInformation左边需要补充的空格字符串strcat(left_space_string," ");for(i=1;i<=right_space;i++) //形成OutputInformation右边需要补充的空格字符串strcat(right_space_string," ");//在OutputInformation左边和右边连接需要补充的空格字符串strcpy(outputstring,left_space_string);strcat(outputstring,OutputInformation);strcat(outputstring,right_space_string);return outputstring; //返回WidthOfData宽度的outputstring}char *GetOuputInformation(int item, int k, char *outputInformation, Node_Ptr*element){switch(item){case 1:{strcat(outputInformation,element[k].ptr->data.number);break;}case 2:{strcat(outputInformation,element[k].ptr->);break;}case 3:{strcat(outputInformation,element[k].ptr->data.sex);break;}case 4:{strcat(outputInformation,element[k].ptr->data.place);break;}case 5:{DigitalToString(outputInformation,element[k].ptr->data.age);break;}default: break;}return outputInformation;}void OutputBinaryTree(BinaryTreeNode *BT){Node_Ptr temp,*element;BinaryTreeNode *p;int MaxSize;int BinaryTreeHigh;int i,j,k;BinaryTreeHigh=5; //BinaryHeight(BT);MaxSize=(int) pow(2,BinaryTreeHigh);element = new Node_Ptr [MaxSize+1]; //定义一个用于存放二叉树结点指针的数组for (i=1;i<=MaxSize;i++) //对指针数组初始化,初值设为NULL element[i].ptr=NULL;p = BT;temp.ptr = p;if (p) element[1]=temp;for (i=1;i<=MaxSize;i++) //将二叉树中的每个结点指针以顺序存储结构存放到数组中{p=element[i].ptr;if (p){if (p->LChild){temp.ptr = p->LChild;element[2*i]=temp;}if (p->RChild){temp.ptr = p->RChild;element[2*i+1]=temp;}}}int WidthOfData=5;int IntervalOfData=3;// cout<<"WidthOfData="<<WidthOfData<<endl;// cout<<"IntervalOfData="<<IntervalOfData<<endl;// cout<<"BinaryTreeHigh="<<BinaryTreeHigh<<endl;int position_of_central[6][17]; //存放每一元素输出位置中心(距离屏幕左边界的字符数)int row,col; //二维数组的行列下标变量for(i=0;i<=BinaryTreeHigh;i++) //存放每一元素输出位置中心(距离屏幕左边界的字符数),初值为0for(j=0;j<=pow(2,BinaryTreeHigh-1);j++)position_of_central[i][j]=0;for(i=1;i<=pow(2,BinaryTreeHigh)-1;i++) //对深度为BinaryTreeHigh的满二叉树的所有结点计算每个结点输出的中心点位置{k=i*2; //k指向i的左子树根结点while (k<=pow(2,BinaryTreeHigh)-1) //k不断推进到i编号的结点左子树中最右子孙结点k=2*k+1;k=k/2; //k的值就是i编号的结点左子树中最右子孙结点的编号j=(int)(k-(pow(2,(BinaryTreeHigh-1))-1)); //由k编号的结点换算出该结点是底层中从左至右第j个结点右上方//即编号为k的结点中心点垂直线左边最底层上有j个结点row=(int)(log10(i)/log10(2)+1); //计算中心点值存放在position_of_central[row][col]中的rowcol=(int)(i-(pow(2,(row-1))-1)); //计算中心点值存放在position_of_central[row][col]中的colif(row==BinaryTreeHigh)//计算底层i结点距离左边界的字符数,左边无间隙position_of_central[row][col]= (j-1)*WidthOfData + (j-1)*IntervalOfData + (WidthOfData/2 +1);else//计算非底层i结点距离左边界的字符数,position_of_central[row][col]=j*WidthOfData + (j-1)*IntervalOfData + (IntervalOfData/2 +1);}char prespace[100];int m;int kk;int kkk;int item_max=5;cout<<endl;for(i=1;i<=BinaryTreeHigh;i++){kkk=(int)pow(2,i-1); //kkk是满二叉树中每一层第1个结点的编号for(int item=1;item<=item_max;item++) //输出每个数据元素多个item成员的值{int half_len_pre_value=0; //同一行前一个输出的元素值长度的一半,同一行第一个输出的元素值前没有值输出,初值为0int half_len_now_value=WidthOfData/2;//同一行当前输出的元素值长度的一半,其值始终为WidthOfData的一半kk=kkk; //kk是满二叉树中每一层结点的编号变化,从某层的最左边第一个结点编号kkk开始for(j=1;j<=pow(2,i-1);j++) //输出满二叉树中同一层次上的每个数据元素的同一个成员的值{char outputInformation[20]={""};char *OutputInformation;if (element[kk].ptr) //获取每个数据元素的一个成员的值OutputInformation,如姓名、年龄等OutputInformation=GetOuputInformation(item,kk,outputInformation,element);if (position_of_central[i][j]) //输出数据中点值存在时,position_of_central[i][j]非0{char outputstring[80]={""};char *OutputString;//下面语句将每个数据元素的一个成员的值OutputInformation,如姓名、年龄等,转换为等长WidthOfData的字符串OutputStringOutputString=GetOuputInformationString(WidthOfData,OutputInformation,outputstring);//生成两个孩子之前的空格串prespace//构成:<前导空格串>=<两个输出数据中心点之差> - <前一个输出元素值长度一半> - <当前输出元素值长度的一半>strcpy(prespace,"");m=(position_of_central[i][j]-position_of_central[i][j-1]-1-half_len_pre_value-half_len_now_ value);for(k=1;k<=m;k++)strcat(prespace," ");cout<<prespace;cout<<OutputString;half_len_pre_value=WidthOfData/2; //调整同一行前一个输出的元素值长度为WidthOfData的一半kk++;}// if (position_of_central[i][j])}//for(j=1;j<=pow(2,i-1);j++)cout<<endl;}//for(int item=1;item<=5;item++)char line[3]="─";char OutputLine[80];char midspace[80];int nodenumber;if(i==1) //对深度为BinaryTreeHigh的满二叉树从上至下,从左至右的编号,计算第i层上起始结点的编号nodenumbernodenumber=1;elsenodenumber=(int)((pow(2,i)-1)-(pow(2,i-1)-1)); //第i(i!=1)层上的第1个结点编号nodenumberfor(j=1;j<=pow(2,i-1);j++) //输出同一层次上的线条{if(i==BinaryTreeHigh) break; //最底层下面没有线条,所以break//生成两个数据元素之前的前导空格串prespacestrcpy(prespace,"");m=(position_of_central[i+1][j]-position_of_central[i+1][j-1]-1);for(k=1;k<=m;k++)strcat(prespace," ");//计算左右两个孩子之间一半的连线OutLine,由若干个line"─"构成//注意line是汉字字符,一个占两个字符位,m是左右两个孩子之间的line"─"数,所以m要除4strcpy(OutputLine,"");m=(position_of_central[i+1][j+1]-position_of_central[i+1][j]-1)/4;for(k=1;k<=m;k++)strcat(OutputLine,line);//计算左右两个孩子之间一半的空格字符的个数m,,所以要除2。