二叉树前序或中序或后序遍历
二叉树知识点总结

二叉树知识点总结1. 二叉树的性质1.1 二叉树的性质一:二叉树的深度二叉树的深度是指从根节点到叶子节点的最长路径长度。
对于一个空树而言,它的深度为0;对于只有一个根节点的树而言,它的深度为1。
根据定义可知,深度为k的二叉树中,叶子节点的深度值为k。
由此可知,二叉树的深度为所有叶子节点深度的最大值。
1.2 二叉树的性质二:二叉树的高度二叉树的高度是指从根节点到叶子节点的最短路径长度。
对于一个空树而言,它的高度为0;对于只有一个根节点的树而言,它的高度为1。
由此可知,二叉树的高度总是比深度大一。
1.3 二叉树的性质三:二叉树的节点数量对于一个深度为k的二叉树而言,它最多包含2^k - 1个节点。
而对于一个拥有n个节点的二叉树而言,它的深度最多为log2(n+1)。
1.4 二叉树的性质四:满二叉树满二叉树是一种特殊类型的二叉树,它的每个节点要么是叶子节点,要么拥有两个子节点。
满二叉树的性质是:对于深度为k的满二叉树而言,它的节点数量一定是2^k - 1。
1.5 二叉树的性质五:完全二叉树完全二叉树是一种特殊类型的二叉树,它的所有叶子节点都集中在树的最低两层,并且最后一层的叶子节点从左到右依次排列。
对于一个深度为k的完全二叉树而言,它的节点数量一定在2^(k-1)和2^k之间。
2. 二叉树的遍历二叉树的遍历是指按照一定的顺序访问二叉树的所有节点。
二叉树的遍历主要包括前序遍历、中序遍历和后序遍历三种。
2.1 前序遍历(Pre-order traversal)前序遍历的顺序是:根节点 -> 左子树 -> 右子树。
对于一个二叉树而言,前序遍历的结果就是按照“根-左-右”的顺序访问所有节点。
2.2 中序遍历(In-order traversal)中序遍历的顺序是:左子树 -> 根节点 -> 右子树。
对于一个二叉树而言,中序遍历的结果就是按照“左-根-右”的顺序访问所有节点。
2.3 后序遍历(Post-order traversal)后序遍历的顺序是:左子树 -> 右子树 -> 根节点。
二叉树,树,森林遍历之间的对应关系

二叉树,树,森林遍历之间的对应关系一、引言在计算机科学中,数据结构是非常重要的知识点之一。
而树这一数据结构,作为基础的数据结构之一,在软件开发中有着广泛的应用。
本文将重点探讨二叉树、树和森林遍历之间的对应关系,帮助读者更加全面地理解这些概念。
二、二叉树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。
第⼀部分即直接訪问之,之后在推断左⼦树是否为空,不为空时即反复上⾯的步骤,直到其为空。
若为空。
则须要訪问右⼦树。
注意。
在訪问过左孩⼦之后。
《数据结构及其应用》笔记含答案 第五章_树和二叉树

第5章树和二叉树一、填空题1、指向结点前驱和后继的指针称为线索。
二、判断题1、二叉树是树的特殊形式。
()2、完全二叉树中,若一个结点没有左孩子,则它必是叶子。
()3、对于有N个结点的二叉树,其高度为。
()4、满二叉树一定是完全二叉树,反之未必。
()5、完全二叉树可采用顺序存储结构实现存储,非完全二叉树则不能。
()6、若一个结点是某二叉树子树的中序遍历序列中的第一个结点,则它必是该子树的后序遍历序列中的第一个结点。
()7、不使用递归也可实现二叉树的先序、中序和后序遍历。
()8、先序遍历二叉树的序列中,任何结点的子树的所有结点不一定跟在该结点之后。
()9、赫夫曼树是带权路径长度最短的树,路径上权值较大的结点离根较近。
()110、在赫夫曼编码中,出现频率相同的字符编码长度也一定相同。
()三、单项选择题1、把一棵树转换为二叉树后,这棵二叉树的形态是(A)。
A.唯一的B.有多种C.有多种,但根结点都没有左孩子D.有多种,但根结点都没有右孩子解释:因为二叉树有左孩子、右孩子之分,故一棵树转换为二叉树后,这棵二叉树的形态是唯一的。
2、由3个结点可以构造出多少种不同的二叉树?(D)A.2 B.3 C.4 D.5解释:五种情况如下:3、一棵完全二叉树上有1001个结点,其中叶子结点的个数是(D)。
A.250 B. 500 C.254 D.501解释:设度为0结点(叶子结点)个数为A,度为1的结点个数为B,度为2的结点个数为C,有A=C+1,A+B+C=1001,可得2C+B=1000,由完全二叉树的性质可得B=0或1,又因为C为整数,所以B=0,C=500,A=501,即有501个叶子结点。
4、一个具有1025个结点的二叉树的高h为(C)。
A.11 B.10 C.11至1025之间 D.10至1024之间解释:若每层仅有一个结点,则树高h为1025;且其最小树高为⎣log21025⎦ + 1=11,即h在11至1025之间。
二叉树基本知识

二叉树基本知识:
1.二叉树的定义:二叉树是每个结点最多有两个子树的树结构,它有五种基本形态:
二叉树可以是空集;根可以有空的左子树或右子树;或者左、右子树皆为空。
2.二叉树的性质:若规定根结点的层数为1,则一颗非空二叉树的第i层上最多有2^(i-1)
(i>0)个结点。
若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结
点数是2^K -1 (k >= 0)个。
对任何一颗二叉树,如果其叶子结点个数为n0,度为2的非叶子结点个数为n2,则有n0=n2+1。
3.二叉树的分类:二叉树有两大类,一是普通二叉树,二是特殊二叉树。
普通二叉树
是指除了满二叉树和完全二叉树之外的二叉树,特殊二叉树包括满二叉树和完全二叉树。
满二叉树是指所有层都完全填满的二叉树,而完全二叉树是指只有最下面两层结点度数可以小于2,并且最下面一层的叶子结点都位于本层中间位置的二叉树。
4.二叉树的遍历:二叉树的遍历主要有三种方法,分别是前序遍历、中序遍历和后序
遍历。
前序遍历是先访问根结点,然后遍历左子树,最后遍历右子树;中序遍历是先遍历左子树,然后访问根结点,最后遍历右子树;后序遍历是先遍历左子树,然后遍历右子树,最后访问根结点。
二叉树遍历(前中后序遍历,三种方式)

⼆叉树遍历(前中后序遍历,三种⽅式)⽬录刷题中碰到⼆叉树的遍历,就查找了⼆叉树遍历的⼏种思路,在此做个总结。
对应的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)的空间复杂度。
前序后序中序详细讲解

前序后序中序详细讲解1.引言1.1 概述在数据结构与算法中,前序、中序和后序是遍历二叉树的三种基本方式之一。
它们是一种递归和迭代算法,用于按照特定的顺序访问二叉树的所有节点。
通过遍历二叉树,我们可以获取有关树的结构和节点之间关系的重要信息。
前序遍历是指先访问根节点,然后递归地访问左子树,最后递归地访问右子树。
中序遍历是指先递归地访问左子树,然后访问根节点,最后递归地访问右子树。
后序遍历是指先递归地访问左子树,然后递归地访问右子树,最后访问根节点。
它们的不同之处在于访问根节点的时机不同。
前序遍历可以帮助我们构建二叉树的镜像,查找特定节点,或者获取树的深度等信息。
中序遍历可以帮助我们按照节点的大小顺序输出树的节点,或者查找二叉搜索树中的某个节点。
后序遍历常用于删除二叉树或者释放二叉树的内存空间。
在实际应用中,前序、中序和后序遍历算法有着广泛的应用。
它们可以用于解决树相关的问题,例如在Web开发中,树结构的遍历算法可以用于生成网页导航栏或者搜索树结构中的某个节点。
在图像处理中,前序遍历可以用于图像压缩或者图像识别。
另外,前序和后序遍历算法还可以用于表达式求值和编译原理中的语法分析等领域。
综上所述,前序、中序和后序遍历算法是遍历二叉树的重要方式,它们在解决各种与树有关的问题中扮演着关键的角色。
通过深入理解和应用这些遍历算法,我们可以更好地理解和利用二叉树的结构特性,并且能够解决更加复杂的问题。
1.2文章结构文章结构是指文章中各个部分的布局和组织方式。
一个良好的文章结构可以使读者更好地理解和理解文章的内容。
本文将详细讲解前序、中序和后序三个部分的内容和应用。
首先,本文将在引言部分概述整篇文章的内容,并介绍文章的结构和目的。
接下来,正文部分将分为三个小节,分别对前序、中序和后序进行详细讲解。
在前序讲解部分,我们将定义和解释前序的意义,并介绍前序在实际应用中的场景。
通过详细的解释和实例,读者将能更好地理解前序的概念和用途。
前序序列和后续序列确定二叉树

前序序列和后续序列确定⼆叉树⼆叉树:已知前序与后序建树那么我们换⼀种思考⽅式,我们先来看看先序与后序序列的排布规律。
以下⾯这棵树来举例:其先序序列为: 1 2 3 4 6 7 5后序序列为:2 6 7 4 5 3 1⾸先我们要知道:先序序列遍历顺序是:根结点-左⼦树-右⼦树后序序列遍历顺序是:左⼦树-右⼦树-根结点很明显,我们可以看出结点在先、后序列中的排布有以下这些特征:【1】、在先序序列中,根结点在⼦树中的结点前⾯,在后序序列中,根结点在⼦树中的结点后⾯。
【2】、以任⼀节点为根结点时,其⼦树在先序后序序列中排布都是先左⼦树后右⼦树,⽽根结点排在最后。
那么,反过来思考,已知这个先序与后序序列所确定的树是唯⼀的吗?进⼀步推⼴:怎么通过先序与后序序列判断是否存在唯⼀的树呢?现在,我们来⼀步步分析已知先序与后序的建树过程:①、根据特征【1】可知:根结点为先序序列第⼀个节点以及后序序列最后⼀个结点,因此根结点为1。
②、先序序列中第⼆个结点为2,其在后序序列中的位置是第⼀个,那么根据特征【2】我们可以知道结点2是没有⼦树的,⽽且结点2要么在根结点的左⼦树,要么在右⼦树。
假设结点2在右⼦树,那么由特征【2】可知根结点1没有左⼦树,⽽且先序序列中结点2后⾯的结点全部为结点2的⼦树上的结点。
再看后序序列,由特征【2】可知,结点2后⾯的结点不可能是其⼦树上的结点。
因此,假设显然与已知⽭盾。
这样,我们⼜知道结点2是结点1的左孩⼦,且结点2没有⼦结点。
③、先序序列第三个位置上的结点为3,该结点在后序序列中排倒数第⼆个。
由②可知,结点3必然是根结点1的右孩⼦。
④、先序序列第四个位置上的结点为4,该结点在后序序列中排第四个。
因为结点4在先序序列中排在结点3后⾯,⼜因为结点3是根结点1的右孩⼦,所以结点4只可能在结点3的⼦树上。
结点3的⼦树可能出现的情况是:只有左⼦树,只有右⼦树,左右⼦树都有。
因为在后序序列中,结点4左边是结点6、7,右边是结点5。
二叉树的三种遍历方法

二叉树的三种遍历方法
二叉树是一种常见的数据结构,它由节点和边组成,每个节点最多有两个子节点,分别称为左子节点和右子节点。
二叉树的遍历是指按照一定的顺序依次访问二叉树中的所有节点。
常见的二叉树遍历方法有三种,分别是前序遍历、中序遍历和后序遍历。
一、前序遍历
前序遍历是指先访问根节点,再依次访问左子树和右子树。
具体步骤如下:
1. 访问根节点。
2. 前序遍历左子树。
3. 前序遍历右子树。
二、中序遍历
中序遍历是指先访问左子树,再访问根节点,最后访问右子树。
具体步骤如下:
1. 中序遍历左子树。
2. 访问根节点。
3. 中序遍历右子树。
三、后序遍历
后序遍历是指先访问左子树,再访问右子树,最后访问根节点。
具体步骤如下:
1. 后序遍历左子树。
2. 后序遍历右子树。
3. 访问根节点。
以上三种遍历方法都是深度优先遍历,因为它们都是先访问一个节点的所有子节点,再依次访问子节点的子节点。
在实际应用中,不同的遍历方法有不同的应用场景,例如前序遍历可以用于复制一棵二叉树,中序遍历可以用于排序,后序遍历可以用于计算表达式的值。
二叉树的遍历(前序、中序、后序、已知前中序求后序、已知中后序求前序)

⼆叉树的遍历(前序、中序、后序、已知前中序求后序、已知中后序求前序)之前的⼀篇随笔()只对⼆叉树的遍历进⾏了笼统的描述,这篇随笔重点对前、中、后序的遍历顺序进⾏分析⼆叉树的遍历⼆叉树的深度优先遍历可细分为前序遍历、中序遍历、后序遍历,这三种遍历可以⽤递归实现(本篇随笔主要分析递归实现),也可使⽤⾮递归实现的前序遍历:根节点->左⼦树->右⼦树(根->左->右)中序遍历:左⼦树->根节点->右⼦树(左->根->右)后序遍历:左⼦树->右⼦树->根节点(左->右->根)在进⾏已知两种遍历顺序求另⼀种遍历顺序前,先看⼀下不同遍历顺序对应的代码前序遍历1/* 以递归⽅式前序遍历⼆叉树 */2void PreOrderTraverse(BiTree t, int level)3 {4if (t == NULL)5 {6return ;7 }8 printf("data = %c level = %d\n ", t->data, level);9 PreOrderTraverse(t->lchild, level + 1);10 PreOrderTraverse(t->rchild, level + 1);11 }中序遍历1/* 以递归⽅式中序遍历⼆叉树 */2void PreOrderTraverse(BiTree t, int level)3 {4if (t == NULL)5 {6return ;7 }8 PreOrderTraverse(t->lchild, level + 1);9 printf("data = %c level = %d\n ", t->data, level);10 PreOrderTraverse(t->rchild, level + 1);11 }后序遍历1/* 以递归⽅式后序遍历⼆叉树 */2void PreOrderTraverse(BiTree t, int level)3 {4if (t == NULL)5 {6return ;7 }8 PreOrderTraverse(t->lchild, level + 1);9 PreOrderTraverse(t->rchild, level + 1);10 printf("data = %c level = %d\n ", t->data, level);11 }三种遍历⽅式对应的代码⼏乎相同,只是⼀条语句的位置发⽣了变化printf("data = %c level = %d\n ", t->data, level);只看⽂字和代码来理解遍历的过程是⽐较困难的,建议读者亲⾃去遍历,为了理清遍历的过程下⾯上题(图⽚来源:)前序遍历前序的遍历的特点,根节点->左⼦树->右⼦树,注意看前序的遍历的代码printf语句是放在两条递归语句之前的,所以先访问根节点G,打印G,然后访问左⼦树D,此时左⼦树D⼜作为根节点,打印D,再访问D的左⼦树AA⼜作为根节点,打印A,A没有左⼦树或者右⼦树,函数调⽤结束返回到D节点(此时已经打印出来的有:GDA)D节点的左⼦树已经递归完成,现在递归访问右⼦树F,F作为根节点,打印F,F有左⼦树访问左⼦树E,E作为根节点,打印E,(此时已经打印出来的有:GDAFE),E没有左⼦树和右⼦树,函数递归结束返回F节点,F的左⼦树已经递归完成了,但没有右⼦树,所以函数递归结束,返回D节点,D节点的左⼦树和右⼦树递归全部完成,函数递归结束返回G节点,访问G节点的右⼦树M,M作为根节点,打印M,访问M的左⼦树H,H作为根节点,打印H,(此时已经打印出来的有:GDAFEMH)H没有左⼦树和右⼦树,函数递归结束,返回M节点,M节点的左⼦树已经递归完成,访问右⼦树Z,Z作为根节点,打印Z,Z没有左⼦树和右⼦树,函数递归结束,返回M节点,M节点的左⼦树右⼦树递归全部完成,函数递归结束,返回G节点,G节点的左右⼦树递归全部完成,整个⼆叉树的遍历就结束了(MGJ,终于打完了··)前序遍历结果:GDAFEMHZ总结⼀下前序遍历步骤第⼀步:打印该节点(再三考虑还是把访问根节点这句话去掉了)第⼆步:访问左⼦树,返回到第⼀步(注意:返回到第⼀步的意思是将根节点的左⼦树作为新的根节点,就好⽐图中D是G的左⼦树但是D也是A节点和F节点的根节点)第三步:访问右⼦树,返回到第⼀步第四步:结束递归,返回到上⼀个节点前序遍历的另⼀种表述:(1)访问根节点(2)前序遍历左⼦树(3)前序遍历右⼦树(在完成第2,3步的时候,也是要按照前序遍历⼆叉树的规则完成)前序遍历结果:GDAFEMHZ中序遍历(详细遍历过程就不再赘述了,(┬_┬))中序遍历步骤第⼀步:访问该节点左⼦树第⼆步:若该节点有左⼦树,则返回第⼀步,否则打印该节点第三步:若该节点有右⼦树,则返回第⼀步,否则结束递归并返回上⼀节点(按我⾃⼰理解的中序就是:先左到底,左到不能在左了就停下来并打印该节点,然后返回到该节点的上⼀节点,并打印该节点,然后再访问该节点的右⼦树,再左到不能再左了就停下来)中序遍历的另⼀种表述:(1)中序遍历左⼦树(2)访问根节点(3)中序遍历右⼦树(在完成第1,3步的时候,要按照中序遍历的规则来完成)所以该图的中序遍历为:ADEFGHMZ后序遍历步骤第⼀步:访问左⼦树第⼆步:若该节点有左⼦树,返回第⼀步第三步:若该节点有右⼦树,返回第⼀步,否则打印该节点并返回上⼀节点后序遍历的另⼀种表述:(1)后序遍历左⼦树(2)后序遍历右⼦树(3)访问根节点(在完成1,2步的时候,依然要按照后序遍历的规则来完成)该图的后序遍历为:AEFDHZMG(读者如果在纸上遍历⼆叉树的时候,仍然容易将顺序搞错建议再回去看⼀下三种不同遍历对应的代码)进⼊正题,已知两种遍历结果求另⼀种遍历结果(其实就是重构⼆叉树)第⼀种:已知前序遍历、中序遍历求后序遍历前序遍历:ABCDEF中序遍历:CBDAEF在进⾏分析前读者需要知道不同遍历结果的特点1、前序遍历的第⼀元素是整个⼆叉树的根节点2、中序遍历中根节点的左边的元素是左⼦树,根节点右边的元素是右⼦树3、后序遍历的最后⼀个元素是整个⼆叉树的根节点(如果读者不明⽩上述三个特点,建议再回去看⼀下三种不同遍历对应的代码,并在纸上写出⼀个简单的⼆叉树的三种不同的遍历结果,以加深对三种不同遍历的理解)⽤上⾯这些特点来分析遍历结果,第⼀步:先看前序遍历A肯定是根节点第⼆步:确认了根节点,再来看中序遍历,中序遍历中根节点A的左边是CBD,右边是EF,所有可以确定⼆叉树既有左⼦树⼜有右⼦树第三步:先来分析左⼦树CBD,那么CBD谁来做A的左⼦树呢?这个时候不能直接⽤中序遍历的特点(左->根->右)得出左⼦树应该是这个样⼦因为有两种情况都满⾜中序遍历为CBD⽆法直接根据中序遍历来直接得出左⼦树的结构,这个时候就要返回到前序遍历中去观察前序遍历ABCDEF,左⼦树CBD在前序遍历中的顺序是BCD,意味着B是左⼦树的根节点(这么说可能不太好理解,换个说法就是B是A的左⼦树),得出这个结果是因为如果⼀个⼆叉树的根节点有左⼦树,那么这个左⼦树⼀定在前序遍历中⼀定紧跟着根节点(这个是⽤前序遍历的特点(根->左->右)得出的),到这⾥就可以确认B是左⼦树的根节点第四步:再观察中序遍历CBDAEF,B元素左边是C右边是D,说明B节点既有左⼦树⼜有右⼦树,左右⼦树只有⼀个元素就可以直接确定了,不⽤再返回去观察前序遍历第五步:到这⾥左⼦树的重建就已经完成了,现在重建右⼦树,因为重建右⼦树的过程和左⼦树的过程⼀模⼀样,步骤就不像上⾯写这么细了((┬_┬)),观察中序遍历右⼦树为EF,再观察前序遍历ABCDEF中右⼦树的顺序为EF,所以E为A的右⼦树,再观察中序便利中E只有右边有F,所有F为E的右⼦树,最后得到的⼆叉树是这个样⼦的所有求得的后序遍历为:CDBFEA总结⼀下上述步骤:先观察前序遍历找到根节点->观察中序遍历将根节点左边归为左⼦树元素,右边归为右⼦树元素(可能会出现只有左⼦树或者右⼦树的情况)->观察前序遍历中左\右⼦树⼏个元素的顺序,最靠前的为左\右⼦树的根节点->重复前⾯的步骤第⼆种:已知中序遍历、后序遍历求前序遍历(题还是上⾯这道)中序遍历:CBDAEF后序遍历为:CDBFEA仍然是根据不同遍历⽅式结果的特点来重构⼆叉树,过程很相似这⾥就不详细说了,后序遍历的最后⼀个元素A是根节点,在中序遍历中以根节点A作为分界将元素分为左⼦树(CBD)和右⼦树(EF),再观察后序遍历中左⼦树的顺序是CDB,可以判断出B是左⼦树的根节点(因为后序遍历是:左->右->根),再观察中序遍历,B元素左边是C右边是D,说明B节点既有左⼦树⼜有右⼦树,左右⼦树只有⼀个元素就可以直接确定了,不⽤再返回去观察后序遍历,左⼦树重建完成,现在来看右⼦树,右⼦树有两个元素EF,观察后序遍历E在F的后⾯,所以E是右⼦树的根节点,然后看中序遍历中E只有右边⼀个F元素了,即F是E的右⼦树,此时整个⼆叉树重构完成总结⼀下上述步骤:先观察后序遍历找到根节点->观察中序遍历将根节点左边归为左⼦树元素,右边归为右⼦树元素(可能会出现只有左⼦树或者右⼦树的情况)->观察后序遍历中左\右⼦树⼏个元素的顺序,最靠后的为左\右⼦树的根节点->重复前⾯的步骤注意:已知前序遍历、后序遍历⽆法求出中序遍历(因为由前序后序重构出来的⼆叉树不⽌⼀种)举个栗⼦左图这两种⼆叉树前序(BEFA)和后序(AFEB)⼀样,但对应的中序遍历结果不⼀样(左边的是AFEB右边的是BEFA),所以仅靠前序后序是重构出唯⼀的⼆叉树。
树的前序遍历、中序遍历、后序遍历详解

树的前序遍历、中序遍历、后序遍历详解1.前序遍历图1对于当前节点,先输出该节点,然后输出他的左孩⼦,最后输出他的右孩⼦。
以上图为例,递归的过程如下:(1):输出 1,接着左孩⼦;(2):输出 2,接着左孩⼦;(3):输出 4,左孩⼦为空,再接着右孩⼦;(4):输出 6,左孩⼦为空,再接着右孩⼦;(5):输出 7,左右孩⼦都为空,此时 2 的左⼦树全部输出,2 的右⼦树为空,此时 1 的左⼦树全部输出,接着 1 的右⼦树;(6):输出 3,接着左孩⼦;(7):输出 5,左右孩⼦为空,此时 3 的左⼦树全部输出,3 的右⼦树为空,⾄此 1 的右⼦树全部输出,结束。
2.中序遍历对于当前结点,先输出它的左孩⼦,然后输出该结点,最后输出它的右孩⼦。
以上图为例:(1):1-->2-->4,4 的左孩⼦为空,输出 4,接着右孩⼦;(2):6 的左孩⼦为空,输出 6,接着右孩⼦;(3):7 的左孩⼦为空,输出 7,右孩⼦也为空,此时 2 的左⼦树全部输出,输出 2,2 的右孩⼦为空,此时 1 的左⼦树全部输出,输出1,接着 1 的右孩⼦;(4):3-->5,5 左孩⼦为空,输出 5,右孩⼦也为空,此时 3 的左⼦树全部输出,⽽ 3 的右孩⼦为空,⾄此 1 的右⼦树全部输出,结束。
3.后序遍历对于当前结点,先输出它的左孩⼦,然后输出它的右孩⼦,最后输出该结点。
依旧以上图为例:(1):1->2->4->6->7,7 ⽆左孩⼦,也⽆右孩⼦,输出 7,此时 6 ⽆左孩⼦,⽽ 6 的右⼦树也全部输出,输出 6,此时 4 ⽆左⼦树,⽽ 4的右⼦树全部输出,输出 4,此时 2 的左⼦树全部输出,且 2 ⽆右⼦树,输出 2,此时 1 的左⼦树全部输出,接着转向右⼦树;(2):3->5,5 ⽆左孩⼦,也⽆右孩⼦,输出 5,此时 3 的左⼦树全部输出,且 3 ⽆右孩⼦,输出 3,此时 1 的右⼦树全部输出,输出 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,失败。
前序遍历和中序遍历唯一确定一颗二叉树

前序遍历和中序遍历唯⼀确定⼀颗⼆叉树---恢复内容开始---问题描述如果给出了遍历⼆叉树的前序序列和中序序列,则可以构造出唯⼀的⼀颗⼆叉树。
基本要求已知⼀棵⼆叉树的前序序列和中序序列,试设计完成下列任务的⼀个算法:(1).构造⼀颗⼆叉树(2).证明构造正确(即分拨⼉以前序和中序遍历该树,将得到的结果与给出的序列进⾏⽐较)(3).对该⼆叉树进⾏后序遍历,输出后序遍历序列(4).⽤凹⼊法输出该⼆叉树测试数据前序序列为ABDEGCFHIJ,中序序列为DBGEAHFIJC代码思路1.确定树的根节点,树根是当前树中所有元素在前序遍历中最先出现的元素。
2.求解树的⼦树,找出根节点在中序遍历中的位置,根左边的所有元素就是左⼦树,根右边的所有元素就是右⼦树。
若根节点左边或右边为空,则该⽅向⼦树为空;若根节点左边和右边都为空,则根节点已经为叶⼦节点。
3.递归求解树,将左⼦树和右⼦树分别看成⼀棵⼆叉树,重复1、2、3步,直到所有的节点完成定位。
源代码/*1.确定树的根节点,树根是当前树中所有元素在前序遍历中最先出现的元素。
2.求解树的⼦树,找出根节点在中序遍历中的位置,根左边的所有元素就是左⼦树,根右边的所有元素就是右⼦树。
若根节点左边或右边为空,则该⽅向⼦树为空;若根节点左边和右边都为空,则根节点已经为叶⼦节点。
3.递归求解树,将左⼦树和右⼦树分别看成⼀棵⼆叉树,重复1、2、3步,直到所有的节点完成定位。
*/#include<iostream>#include<algorithm>#include<string>#include<cstring>using namespace std;const int maxint = 10000;char ch1[maxint], ch2[maxint]; //前序序列,中序序列int length; //⼆叉树结点的个数struct tree {char name;struct tree *leftchild;struct tree *rightchild;};//访问函数void vis(char name) {cout << name;}//初始化void init(struct tree **root){*root = (struct tree *)malloc(sizeof(struct tree));(*root)->leftchild = NULL;(*root)->rightchild = NULL;}//创建左⼦树struct tree *build_ltree(struct tree *h,char name) {struct tree *p, *t;if (h == NULL) return NULL;t = h->leftchild;p= (struct tree*)malloc(sizeof(struct tree));p->name = name;p->leftchild = t;p->rightchild = NULL;h->leftchild = p;return h->leftchild;}//创建右⼦树struct tree *build_rtree(struct tree *h, char name) {struct tree *p, *t;if (h == NULL) return NULL;t = h->rightchild;p = (struct tree*)malloc(sizeof(struct tree));p->name = name;p->leftchild = NULL;p->rightchild = t;h->rightchild = p;return h->rightchild;}void print_tree(struct tree *t, int n) {if (t == NULL) return;print_tree(t->rightchild, n + 1);for (int i = 0; i < n - 1; i++) cout << "";if (n > 0) {cout<<"***";cout << t->name << endl;}print_tree(t->leftchild, n + 1);}//前序遍历void preorder(struct tree *t, void vis(char name)) {if (t != NULL) {vis(t->name);preorder(t->leftchild, vis);preorder(t->rightchild, vis);}}//中序遍历void inorder(struct tree *t, void vis(char name)) {if (t != NULL) {inorder(t->leftchild, vis);vis(t->name);inorder(t->rightchild, vis);}}//后序遍历void postorder(struct tree *t, void vis(char name)) {if (t != NULL) {postorder(t->leftchild, vis);postorder(t->rightchild, vis);vis(t->name);}}//寻找对应中序序列中和前序序列相对应的结点的位置int bfs(char ch[],char name) {int i(0);while (ch[i] != name) ++i;return i;}//找到左⼦树的位置int seek_left(int flag[], int t){int temp;temp = t;while (flag[temp] != 1 && temp >= 0)temp--;if (flag[temp] == 1)return temp;else return -1;}//找到右⼦树的位置int seek_right(int flag[], int t){int temp;temp = t;while (flag[temp] != 1 && temp <= 10000)temp++;if (flag[temp] == 1)return temp;else return -1;}int main() {while (1) {cout << " ***************唯⼀确定⼀颗⼆叉树***************" << endl;cout << " * *" << endl;cout << " * 给定前序序列和中序序列唯⼀确定⼀颗⼆叉树 *" << endl; cout << " * *" << endl;cout << " ************************************************" << endl;struct tree *root; //定义根节点init(&root); //创建根节点struct tree *node_tree[maxint]; //⼆叉树中的结点int flag[maxint]; //标记数组int left, right;memset(flag, 0, sizeof flag); //标记数组全部赋值为0cout << "请输⼊前序序列:";cin >> ch1;cout << "请输⼊中序序列:";cin >> ch2;length = strlen(ch1);char node; //前序序列中的结点int num; //中序序列中对应前序序列结点的位置for (int i = 0; i < length; ++i) {node = ch1[i];num = bfs(ch2, node);left = seek_left(flag, num); //找到左⼦树位置right = seek_right(flag, num); //找到右⼦树位置if (left == -1 && right == -1) { //第⼀次的时候肯定会执⾏这个条件后⾯的语句 node_tree[num] = build_ltree(root, node);flag[num] = 1;}else if (left != -1 && node_tree[left]->rightchild == NULL) {node_tree[num] = build_rtree(node_tree[left], node);flag[num] = 1;}else if (right != -1 && node_tree[right]->leftchild == NULL) {node_tree[num] = build_ltree(node_tree[right], node);}}cout << "此⼆叉树的结构是:" << endl << endl;print_tree(root, 0);cout << "此⼆叉树的前序序列为:";preorder(root->leftchild, vis);cout << endl;cout << "此⼆叉树的中序序列为:";inorder(root->leftchild, vis);cout << endl;cout << "此⼆叉树的后序序列为:";postorder(root->leftchild, vis);cout << endl << endl << endl;}return0;}效果图总结断更⼀个⽉后,重新写博。
二叉树的遍历及例题

⼆叉树的遍历及例题⼆叉树的遍历及例题前序遍历就是根在前,中序是根在根在中,前序遍历根 --> 左 --> 右中序遍历左 --> 根 --> 右后序遍历左 --> 右 --> 根如图是⼀颗⼆叉树前序(根左右),中序(左根右),后序(左右根)它的前序遍历结果为: A B D F G H I E C 代表的含义为A( B ( D ( F ,G( H ,I ) ) ,E ) , C )所以第⼀个点⼀定是根节点它的中序遍历结果为: F D H G I B E A C它代表的含义,A(已知它不是叶⼦节点)在中间说明A的左边是左⼉⼦,A的右边是他的右⼉⼦它的后序遍历结果为:F H I G D E B C A解题:如果有前序和中序或者中序和后序可以得到⼆叉树,从⽽得到后序。
如果有前序和后序⽆法的得到⼆叉树。
1.已知前序、中序遍历求后序遍历例:前序遍历:A B G D E C F H中序遍历:G B E D A F C H构建⼆叉树的步骤:1.根据前序遍历特点,得到根节点A2.观察中序遍历结果:根节点左边节点为G B E D,根节点的右边节点为 F C H。
同时,两段也是左右⼦树的中序遍历的结果。
B G D E也是左⼦树前序遍历的结果。
C F H也是右⼦树前序遍历的结果。
3.重复 1 2的步骤,直到找到叶⼦结点就可以得到最后的⼆叉树。
例题:题意:给出中序遍历和前序遍历,让你找到后序遍历的结果。
#include <iostream>using namespace std;const int maxn = 105;int pre[maxn],in[maxn],pos[maxn];int infind(int root,int l,int r){//在中序遍历中找到当前根节点的位置for(int i=l;i<r;i++){if(in[i]==root){return i;}}}int cnt;void posorder(int prel,int prer,int inl,int inr){if(prel==prer) return ;int root=infind(pre[prel],inl,inr);//找当前的根的位置int len=root-inl;posorder(prel+1,prel+1+len,inl,inl+len);//prel的位置是root的位置,删去posorder(prel+1+len,prer,inl+1+len,inr);//inl+len+1的位置是root的位置,删去//进⾏完左边和右边的遍历之后,进⾏赋值。
二叉树的顺序存储结构代码

二叉树的顺序存储结构代码介绍二叉树是一种常用的数据结构,它由节点组成,每个节点最多有两个子节点。
在计算机中,我们通常使用顺序存储结构来表示二叉树。
顺序存储结构是将二叉树的节点按照从上到下、从左到右的顺序依次存储在一个数组中。
本文将详细介绍二叉树的顺序存储结构代码,包括初始化、插入节点、删除节点以及遍历等操作。
二叉树的顺序存储结构代码实现初始化二叉树首先,我们需要定义一个数组来存储二叉树的节点。
假设数组的大小为n,则二叉树的最大节点数量为n-1。
# 初始化二叉树,将数组中所有元素置为空def init_binary_tree(n):binary_tree = [None] * nreturn binary_tree插入节点在二叉树的顺序存储结构中,节点的插入操作需要保持二叉树的特性,即左子节点小于父节点,右子节点大于父节点。
插入节点的算法如下:1.找到待插入位置的父节点索引parent_index。
2.如果待插入节点小于父节点,将其插入到父节点的左子节点位置,即数组索引2*parent_index+1处。
3.如果待插入节点大于父节点,将其插入到父节点的右子节点位置,即数组索引2*parent_index+2处。
# 插入节点def insert_node(binary_tree, node):index = 0 # 当前节点的索引值,初始值为根节点的索引值while binary_tree[index] is not None:if node < binary_tree[index]:index = 2 * index + 1 # 插入到左子节点else:index = 2 * index + 2 # 插入到右子节点binary_tree[index] = node删除节点删除节点需要保持二叉树的特性,即在删除节点后,仍然满足左子节点小于父节点,右子节点大于父节点的条件。
删除节点的算法如下:1.找到待删除节点的索引delete_index。
二叉树的遍历

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); } }
二级公共基础知识2-数据结构与算法2(二叉树)

起泡排序 快速排序 简单选择排序 堆排序 直接插入排序 折半插入排序 希尔排序
选择排序 排序方法 插入排序
归并排序等
1.8.2 插入排序
直接插入、折半插入
1、直接插入排序: • 基本思想:从数组的第2号元素开始, 顺序从数组中取出元素,并将该元素插 入到其左端已排好序的数组的适当位置 上。 • 在最坏情况下需要n(n-1)/2次比较
E
F
0
0
0
0
2h-1= 24-1 = 15 若父结点在数组中i下标处,其左孩子在2*i处,右孩子在2*i+1处。 一般二叉树必须按完全二叉树的形式存储,将造成存储的浪费。
North China Electric Power University
(2).二叉树的链式存储结构(二叉链表)
链结点的构造为
(2) 二叉树的基本性质
A、 二叉树的第i层上至多有2 i-1(i 1)个结点。
1
2 3
4 8 9
10
5
11 12
6
13 14
7
15
第三层上(i=3),有23-1=4个节点。
第四层上(i=4),有24-1=8个节点。
(2) 二叉树的基本性质
A、 二叉树的第i层上至多有2 i-1(i 1)个结点。 B、 深度为h的二叉树中至多含有2h-1个结点。
组 成 原 理 试 验 室
管 理 信 息 系 统 研 究 室
知 识 工 程 研 究 室
微 机 应 用 研 究 室
A
树中的基本术语:
B C F
D
H I
1.结点、结点的度、树的度 P32中 E
2.叶子结点、分支结点 3.孩子、双亲、兄弟、 堂兄弟、祖先、子孙 4.结点的层次、树的深度 5.有序树和无序树
由前序跟中序遍历序求后序遍历序的设计与实现

(中文)由前序跟中序遍历序求后序遍历序的设计与实现(英文)The design and implementation of getting postorder traversal according to preorderand inorder traversal of a binary tree蔡智聪摘要:树的遍历问题在应用开发过程中是一个很经典且常遇到的问题,在实际工程中,经常可能需要进行某种遍历充的求解。
本文介绍如何由一棵二叉树的前序遍历序和中序遍历序来后序遍历序的设计思路与具体C++实现。
首先根据前序遍历序和中序遍历序来建立(还原)出二叉树的原型,文中详细介绍了建立(还原)树的算法及原理。
然后再用后后序遍历算法求后序遍历序(一串字符串序列)。
关键字:二叉树前序遍历序中序遍历序后序遍历序Binary –Tree ,Preorder traversal, inorder traversal, postorder traversal正文:几个术语的介绍:二叉树:在计算机科学中,二叉树是每个结点最多有两个子树的有序树。
通常子树的根被称作“左子树”(left subtree)和“右子树”(right subtree)。
前序遍历序:在对一个树进行前序遍历而得到的一个访问结点的序列。
遍历的顺序是:先父结点,然后左子树,然后右子树。
中序遍历序:在对一个树进行中序遍历而得到的一个访问结点的序列。
遍历的顺序是:先左子树,然后父结点,然后右子树。
前序遍历序:在对一个树进行前序遍历而得到的一个访问结点的序列。
遍历的顺序是:先左子树,然后右子树,然后父结点。
引言:树的遍历问题在应用开发过程中是一个很经典且常遇到的问题,在实际工程中,经常可能需要进行某种遍历充的求解。
为了描述和实现的简化,本文中以二叉树来代替为例,并将二叉树的结点抽象成一个字符来代替,在实现运用中可以自己加以灵活变通。
问题的引出:那么对于一棵给定的二叉树,如何根据前序遍历序和中序遍历序来求出后序遍历序呢?如图A:这样的一棵树的前序遍历序为:ABDGHCEIFJ中序遍历序为:GDHBAEICFJ那么如何求出后序遍历序(GHDBIEJFCA)呢?算法原理及分析:1.先建立还原二叉树。
根据前序中序写后序(正确写法)

根据前序中序写后序(正确写法)题⽬描述已知⼆叉树的前序和中序遍历,输出该⼆叉树的后序遍历。
例如下⾯⼆叉树的前序和中序遍历为ABDC、DBAC,后序遍历为DBCA。
A/ \/ \B C//D输⼊包括多组测试数据。
每组1⾏,包含两个字符串,分别为叉树的前序和中序遍历。
输出⼆叉树的后序遍历。
样例输⼊ABDC DBACBCAD CBAD样例输出DBCACDAB-----------------------------------------------------------------------------------------------举个栗⼦前序:ABCDEFG中序:CBEDAFG思想:⼀步⼀步划分,将其存⼊两个数组中;从第⼀个根开始划分;;;;看图:--------------------------------------------------------------------------------------------left = 1 CBEDAFG right = 7↓left = 1 CBED right = 4 A left = 6 FG right = 7↓↓C B ED left = 6 right = 6↓↓left = 1 right = 1 left = 3, right = 4↓left = 3, right = 31.如果left < right 那么继续递归2,如果left == right 说明它是⼀个叶⼦节点,则T->lchild = T->right = null;3,如果 left > right 说明它是⼀个null, T=null;----------------------------------------------------------------------------------------------#include <cstdio>#include <cstdlib>#include <cstring>//#define _OJ_typedef struct tree1{char data;struct tree1 *lchild;struct tree1 *rchild;} tree1, *tree;treecreat_tree(tree T, int len, int left, int right, char *t1, char *t2){if(left < right) {int i = 1;T = (tree) malloc (sizeof(tree1)); T->data = t1[len];while (t1[len] != t2[i])i++;T->lchild = creat_tree(T->lchild, len + 1, left, i - 1, t1, t2);// 递归遍历左⼦树 left不变, i - 1;T->rchild = creat_tree(T->rchild, len + i + 1 - left, i + 1, right, t1, t2); // 递归遍历左⼦树 right 不变, i + 1;len + i + 1 - left,}//难点在于参数的传递else if(left == right) {T = (tree) malloc (sizeof(tree1)); T->data = t1[len];T->lchild = T->rchild = NULL;}else if(left > right) T = NULL;return T;}voidtravers(tree T)//递归遍历⼀棵树{if(T) {travers(T->lchild);travers(T->rchild);printf("%c", T->data);}}int main(int argc, char const *argv[]) {#ifndef _OJ_ //ONLINE_JUDGEfreopen("input.txt", "r", stdin);#endiftree T;char t1[20], t2[20];int i, len;while(scanf("%s", t1) != EOF) {scanf("%s", t2);len = strlen(t1);//0号位不⽤for(i = len;i >= 0; i--) {t1[i + 1] = t1[i];t2[i + 1] = t2[i];}T = creat_tree(T, 1, 1, len, t1, t2);travers(T);printf("\n");}return 0;}-----------------------------------------------------------------------------------------------------------------------通过举⼀反三我们可以同理可得通过中序和后序写前序#include <cstdio>#include <cstdlib>#include <cstring>//#define _OJ_typedef struct tree1{char data;struct tree1 *lchild;struct tree1 *rchild;} tree1, *tree;treecreat_tree(tree T, int len, int left, int right, char *t1, char *t2){if(left < right) {int i = 1;T = (tree) malloc (sizeof(tree1)); T->data = t2[len];while (t2[len] != t1[i])i++;//对于右⼦树,i+ 1 , right不变T->rchild = creat_tree(T->rchild, len - 1, i + 1, right, t1, t2);T->lchild = creat_tree(T->lchild, len + i - 1 - right, left, i - 1, t1, t2);}//对于左⼦树left不变, i - 1, 特别注意参数len + i - 1 - rightelse if(left == right) {T = (tree) malloc (sizeof(tree1)); T->data = t2[len];T->lchild = T->rchild = NULL;}else if(left > right)T = NULL;return T;}voidtravers(tree T)//递归遍历⼀棵树{if(T) {printf("%c", T->data);travers(T->lchild);travers(T->rchild);}}int main(int argc, char const *argv[]) {#ifndef _OJ_ //ONLINE_JUDGEfreopen("input.txt", "r", stdin);#endiftree T;char t1[20], t2[20];int i, len;while(scanf("%s", t1) != EOF) {scanf("%s", t2);len = strlen(t1);//0号位不⽤for(i = len;i >= 0; i--) {t1[i + 1] = t1[i];t2[i + 1] = t2[i];}T = creat_tree(T, len, 1, 7, t1, t2);travers(T);printf("\n");}return 0;}// 中序:CBEDAFG// 后序:CEDBGFA// 前序:ABCDEFG----------------------------------------------------------------------------------------------------------------------len + 1+ i - left;;;;;; len - 1 +i -right;;;;;;其实⽆论怎么写代码,看别⼈的代码也好,,⼀定要有⾃⼰的想法也许别⼈的代码很渣。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数学与计算机学院计算机系实验报告课程名称: 数据结构年级:2010 实验成绩: 指导教师: 黄襄念姓名: 实验教室:6A-413 实验名称:二叉树前序或中序或后序遍历学号: 实验日期:2012/6/10 实验序号:实验3实验时间:8:00—11:40 实验学时:4 一、实验目的1. 熟悉的掌握树的创建,和树的前序、中序、后序遍历。
二、实验环境1. 操作系统:Windows72. 开发软件:Microsoft Visual C++ 6.0三、实验内容● 程序功能本程序完成了以下功能:1. 前序遍历2. 中序遍历3. 后序遍历● 数据结构本程序中使用的数据结构(若有多个,逐个说明):1. 它的优缺点1) 可以快速的查找数据。
2) 让数据层次更加清晰。
2. 逻辑结构图3. 存储结构图、、、、、、、、、、、、、、、、、、、、4.存储结构的C/C++ 语言描述typedef struct node {DataType data;struct node *lchild;struct node *rchild;} BiTNode, *BiTree;typedef BiTree type;●算法描述本程序中采用的算法1.算法名称:递归2.算法原理或思想是通过访问结点的左右孩子来进行循环查找的方法,拿中序遍历来说明:先从头结点开始,再去访问头结点的右孩子如果为空就访问头结点的左孩子,依次进行访问当结点的左右孩子都为空时,就访问上一级,到了最后。
3.算法特点它能将查找进行2分,体现出了更高效快捷的特点,并且层次很清晰。
●程序说明1.2.1)前序遍历模块:将树进行从头结点开始再左孩子再右孩子。
代码:void InOrder(BiTree root){Stack S(100);initStack(S);BiTNode *p = root;do{while(p != NULL){Push(S, p);p = p->lchild;}if(!isEmpty(S)){Pop(S, p);cout << p->data << " ";p = p->rchild;}} while(p != NULL || !isEmpty(S));cout << endl;}2)后序遍历模块:将树进行从左孩子开始再右孩子再头结点。
代码:void PostOrder(BiTree root){Stack S(100);Stack SS(100);initStack(S);initStack(SS);BiTNode *p = root;do{while(p != NULL){Push(S, p);Push(SS, p);p = p->rchild;}if(!isEmpty(S)){Pop(S, p);p = p->lchild;}} while(p != NULL || !isEmpty(S));while(!isEmpty(SS)){Pop(SS, p);cout << p->data << " ";}cout << endl;}3)中序遍历模块:将树进行从左孩子开始再头结点再右孩子。
代码:void PreOrder(BiTree root){Stack S(100);initStack(S);BiTNode *p = root;do{while(p != NULL){Push(S, p);cout << p->data << " ";p = p->lchild;}if(!isEmpty(S)){Pop(S, p);p = p->rchild;}} while(p != NULL || !isEmpty(S));cout << endl;}四、调试与运行1. 程序调试本程序开发过程中,采用的调试方法或手段如下:1)方法1:在程序执行的终止的函数中加一条输出语句cout<<”*******”<<endl;进行错误的定位,调试了指针没有正确使用的错误。
2)方法2:输出一些树中的数据,看能不能正确的输出,调试了其左右孩子是不是正确。
2. 运行结果本次实验多个功能需分别截图,逐个说明。
运行结果图1……五、实验总结1. 结果分析:本程序完成了树的前序遍历、中序遍历、后序遍历功能;但是还是存在不完善的地方,没有对结点进行删除增加等操作,没有将树的结构给输出。
2. 心得体会:通过这个实验我更熟练的掌握了二叉树的结构同时也更了解了递归算法,觉得数据结构是一个很不错的一门课程。
代码:#include <iostream>#include <stack>using namespace std;using std::cout;using std::endl;typedef char DataType;typedef struct node {DataType data;struct node *lchild;struct node *rchild;} BiTNode, *BiTree;typedef BiTree type;class Stack{friend void initStack(Stack &S);friend bool isEmpty(Stack &S);friend bool Push(Stack &S, type x);friend bool Pop(Stack &S, type &x);friend bool getTop(Stack &S, type &x);public:Stack(int maxSize){if(maxSize < 0){throw std::exception("argument maxSize is illegal.");}this->maxSize = maxSize;this->s = NULL;}virtual ~Stack(){if(this->s != NULL){delete this->s;this->s = NULL;}}protected:int maxSize;std::stack<type> *s;};void initStack(Stack &S){if(S.s != NULL){delete S.s;S.s = NULL;}S.s = new std::stack<type>();}bool isEmpty(Stack &S){return S.s->empty();}bool Push(Stack &S, type x){if(S.s->size() == S.maxSize){return false;}S.s->push(x);return true;}bool Pop(Stack &S, type &x){if(S.s->empty()){return false;}x = S.s->top();S.s->pop();return true;}bool getTop(Stack &S, type &x){if(S.s->empty()){return false;}x = S.s->top();return true;}void PreOrder(BiTree root){Stack S(100);initStack(S);BiTNode *p = root;do{while(p != NULL){Push(S, p);cout << p->data << " ";p = p->lchild;}if(!isEmpty(S)){Pop(S, p);p = p->rchild;}} while(p != NULL || !isEmpty(S));cout << endl;}void InOrder(BiTree root){Stack S(100);initStack(S);BiTNode *p = root;do{while(p != NULL){Push(S, p);p = p->lchild;}if(!isEmpty(S)){Pop(S, p);cout << p->data << " ";p = p->rchild;}} while(p != NULL || !isEmpty(S));cout << endl;}void PostOrder(BiTree root){Stack S(100);Stack SS(100);initStack(S);initStack(SS);BiTNode *p = root;do{while(p != NULL){Push(S, p);Push(SS, p);p = p->rchild;}if(!isEmpty(S)){Pop(S, p);p = p->lchild;}} while(p != NULL || !isEmpty(S));while(!isEmpty(SS)){Pop(SS, p);cout << p->data << " ";}cout << endl;}void menu(){cout<<"**************************************"<<endl;cout<<"***** 1.中序遍历*****"<<endl;cout<<"***** 2.前序遍历*****"<<endl;cout<<"***** 3.后序遍历*****"<<endl;cout<<"***** 0.退出程序*****"<<endl;cout<<"**************************************"<<endl; }int main(int argc, char* argv[]){BiTNode nodes[7];int i;nodes[0].data = 'A';nodes[0].lchild = &nodes[1];nodes[0].rchild = NULL;nodes[1].data = 'B';nodes[1].lchild = &nodes[2];nodes[1].rchild = &nodes[3];nodes[2].data = 'C';nodes[2].lchild = NULL;nodes[2].rchild = NULL;nodes[3].data = 'D';nodes[3].lchild = &nodes[4];nodes[3].rchild = &nodes[5];nodes[4].data = 'E';nodes[4].lchild = NULL;nodes[4].rchild = &nodes[6];nodes[5].data = 'F';nodes[5].lchild = NULL;nodes[5].rchild = NULL;nodes[6].data = 'G';nodes[6].lchild = NULL;nodes[6].rchild = NULL;try{menu();cout<<"树已经生成了!"<<endl;while(1){cout<<"请输入你的选择:"<<endl;cin>>i;switch(i){case 1:PreOrder(nodes);break;case 2:InOrder(nodes);break;case 3:PostOrder(nodes);break;case 0:exit(0);}}}catch(std::exception &e){cout << e.what();}return 0;}。