要求:以左右孩子表示法实现链式方式存储的二叉树(lson—rson),以菜单方式设计并完成功能任务:建立并存储树、输出前序遍历结果、输出中序遍历结果、输出后序遍历结果、交换左右子树、统计高度,其中对于中序、后序的遍历运算要求采用非递归的方式实现。

写在前面

二叉树向量存储的优势和弊端

  二叉树同样有两种存储方式,数组和链式存储,对于数组来说,我们利用二叉树的性质然后利用下标可以方便的找到一个节点的子节点和父节点。

    

  

二叉树的性质:
  1.二叉树的第i层上至多有2i-1个节点
  2.深度为K的二叉树至多有2k-1个节点
  3.任何一个二叉树中度数为2的节点的个数必度数为0的节点数目少1.
    说明:度数为0,为叶子节点。
  4.具有n个节点的完全二叉树的深度为|_Log2N_|+1
  5.若完全二叉树中的某节点编号为i,则若有左孩子编号为2i,若有右孩子编号为2i+1,母亲节点为i/2。

  结合第5条性质:

    若完全二叉树中的某节点编号为i,则若有左孩子编号为2i,若有右孩子编号为2i+1,母亲节点为i/2。

  可以在这种完全二叉树中十分方便的找到任何相关联(父子、兄弟等)的元素。

  但是由于顺序存储天生适配于完全二叉树,对于下面这种非完全二叉树并不合适,主要体现在空间上的浪费,所以我们需要用到另一种存储方式——链式存储。

   

 

二叉树的链表存储

  在链式存储中,每个节点的结构如下

  

结构描述:

  一个存储数据的变量与两个指向孩子的指针域。

  利用指针域我们便可以完美的存储非完全二叉树,如下:

   

代码分解:

1.定义结构体变量,其中的tag只会在后序遍历(非递归)过程中使用。

typedef struct node{
int tag; //在后序遍历过程中来标志一个结点是第一次访问(tag=0)还是第二次访问(tag=1)
int data;
struct node* lson;
struct node* rson;
}Bitree;
typedef Bitree* Bitpo;

2.创建二叉树。创建二叉树的方式有3种(前序、中序、后序),其过程与二叉树的遍历类似,这里我用前序来创建二叉树。

void create(Bitpo &T){                    //创建并存储二叉树,以先序顺序输入并存储(递归)
int x;
cin>>x;
if(x==0) //'0'表示空节点
T=NULL;
else{
T=(Bitpo)malloc(Len);
T->data=x;
create(T->lson);
create(T->rson);
}
}

3.前序遍历二叉树(递归)。

void pretraversal(Bitpo T){              //先序遍历(递归)
if(T){
cout<<T->data<<" ";
pretraversal(T->lson);
pretraversal(T->rson);
}
}

4.中序遍历二叉树(非递归)。这里用数组模拟栈,用一个整型变量模拟栈顶指针,需要回溯。

void intraversal(Bitpo T){               //中序遍历(非递归)
Bitpo stack[101]; //定义栈并初始化
Bitpo Q=T;
int p=0; //初始化栈顶指针
do{
while(Q!=NULL){ //遍历左子树
p++;
if(p==101){
cout<<"Error:stack is full!!";
return; //栈满,返回0
}
stack[p]=Q; //入栈,从下标1开始
Q=Q->lson;
}
if(p!=0){
Q=stack[p];
p--; //退栈
cout<<Q->data<<" "; //访问根节点
Q=Q->rson; //遍历右子树
}
}while(p!=0||Q!=NULL);
}

5.后序遍历二叉树(非递归)。同样的用数组模拟栈,用一个整型变量模拟栈顶指针,需要回溯和设立标志tag(已在结构体中定义),因为根节点最后一个访问,所以入栈时令tag=0入栈,第一次回溯出栈时令tag=1,重新入栈,第二次回溯出栈时才可以访问。

void posttraversal(Bitpo T){             //后序遍历(非递归)
Bitpo stack[101]; //定义栈并初始化
int p=0; //初始化栈顶指针
Bitpo Q=T;
do{
while(Q!=NULL){
p++;
if(p==101){ //栈满,退出
cout<<"Error:stack is full!!";
return;
}
Q->tag=0; //第一次入栈,tag=0
stack[p]=Q; //入栈
Q=Q->lson;
}
if(p!=0){
Q=stack[p];
p--; //退栈
if(Q->tag==0){ //第一次访问,令tag=1,重新入栈
Q->tag=1;
p++;
stack[p]=Q;
Q=Q->rson;//继续搜索Q的右子树
}
else{ //第二次入栈,访问Q结点,并且为了回溯,令Q=NULL
cout<<Q->data<<" ";
Q=NULL;
}
}
}while(p!=0||Q!=NULL);
}

6.交换左右子树(递归)。

void exchange(Bitpo T){                  //交换左右子树(递归)
if(T){
Bitpo x=T->lson;
T->lson=T->rson;
T->rson=x;
exchange(T->lson);
exchange(T->rson);
}
}

7.求二叉树的高度(递归)。

int height(Bitpo T){                     //求高度(递归)
if(T){
return 1+max(height(T->lson),height(T->rson));
}
else
return 0;
}

8.主函数如下。

int main(){
int q=1;
Bitpo root;
while(q){
cout<<"1.create and store binary tree!"<<endl;
cout<<"2.travel in preorder!"<<endl;
cout<<"3.travel in inorder!"<<endl;
cout<<"4.travel in postorder!"<<endl;
cout<<"5.change lson and rson!"<<endl;
cout<<"6.calculate the height of the tree!"<<endl;
cout<<"0.exit!"<<endl;
cin>>q;
switch(q){
case 0:
q=0;
break;
case 1:
create(root);
cout<<endl<<"create successfully!"<<endl<<endl;
break;
case 2:
cout<<"preorder:";
pretraversal(root);
cout<<endl<<endl;
break;
case 3:
cout<<"inorder:";
intraversal(root);
cout<<endl<<endl;
break;
case 4:
cout<<"postorder:";
posttraversal(root);
cout<<endl<<endl;
break;
case 5:
exchange(root);
cout<<"exchange successfully!!"<<endl<<endl;
break;
case 6:
cout<<"height:"<<height(root)<<endl<<endl;
break;
}
}
return 0;
}

二叉树的创建、遍历(递归和非递归实现)、交换左右子数、求高度(c++实现)的更多相关文章

  1. 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java

    前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序 ...

  2. C实现二叉树(模块化集成,遍历的递归与非递归实现)

    C实现二叉树模块化集成 实验源码介绍(源代码的总体介绍):header.h : 头文件链栈,循环队列,二叉树的结构声明和相关函数的声明.LinkStack.c : 链栈的相关操作函数定义.Queue. ...

  3. 二叉树3种递归和非递归遍历(Java)

    import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...

  4. JAVA递归、非递归遍历二叉树(转)

    原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { priva ...

  5. 二叉树前中后/层次遍历的递归与非递归形式(c++)

    /* 二叉树前中后/层次遍历的递归与非递归形式 */ //*************** void preOrder1(BinaryTreeNode* pRoot) { if(pRoot==NULL) ...

  6. Java实现二叉树的先序、中序、后序、层序遍历(递归和非递归)

    二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易 ...

  7. Java - 二叉树递归与非递归

    树的定义具有递归特性,因此用递归来遍历比较符合特性,但是用非递归方式就比较麻烦,主要是递归和栈的转换. import java.util.Stack; /** * @author 李文浩 * @ver ...

  8. 数据结构-树以及深度、广度优先遍历(递归和非递归,python实现)

    前面我们介绍了队列.堆栈.链表,你亲自动手实践了吗?今天我们来到了树的部分,树在数据结构中是非常重要的一部分,树的应用有很多很多,树的种类也有很多很多,今天我们就先来创建一个普通的树.其他各种各样的树 ...

  9. 数据结构作业——图的存储及遍历(邻接矩阵、邻接表+DFS递归、非递归+BFS)

    邻接矩阵存图 /* * @Author: WZY * @School: HPU * @Date: 2018-11-02 18:35:27 * @Last Modified by: WZY * @Las ...

  10. 二叉树之AVL树的平衡实现(递归与非递归)

    这篇文章用来复习AVL的平衡操作,分别会介绍其旋转操作的递归与非递归实现,但是最终带有插入示例的版本会以递归呈现. 下面这张图绘制了需要旋转操作的8种情况.(我要给做这张图的兄弟一个赞)后面会给出这八 ...

随机推荐

  1. bzoj4697: 猪

    Description 红学姐和黄学长是好朋友.红学姐有一只宠物,叫魔法猪.黄学长也有一只宠物,叫小奇.有 n 个猪圈排成一排 ,魔法猪藏在某个猪圈中.为了找到魔法猪,小奇会向你询问一些猪圈中猪的个数 ...

  2. linux Composer 安装

    Composer是一个管理PHP包依赖关系的工具.我们可以使用Composer方便地管理项目中一些第三方库和自己的库. 我们可以把Composer安装到当前目录或者特定目录甚至将它变成全局命令 *执行 ...

  3. Intellij IDEA 中如何查看maven项目中所有jar包的依赖关系图

    Maven 组件界面介绍 如上图标注 1 所示,为常用的 Maven 工具栏,其中最常用的有: 第一个按钮:Reimport All Maven Projects 表示根据 pom.xml 重新载入项 ...

  4. Dubbo与Zookeeper、Spring整合使用

    Dubbo与Zookeeper.Spring整合使用 Dubbo采用全spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spri ...

  5. 模拟估算器:scikit-learn Estimator

    转载:https://www.toutiao.com/i6606193174010397187/ 当一个数据科学项目刚刚开始时,关键是要尽可能快地走向一个最小可行的产品(MVP).这个MVP将包含最终 ...

  6. OpenCV:初试牛刀-显示图像-1

    OpenCV开发包提供了读取各种类型的图像文件.视频内容以及摄像机输入的功能.这些功能是OpenCV开发包所包含的HighGUI工具集的一部分. 先看两个小例子: #include"open ...

  7. ExtJS自定义事件

    1.开发ExtJS组件UI的时候,基本上对于一些操作,就是与后台交互之类的多数都是用户进行点击触发一个事件,在事件的处理器handler里面调具体的业务方法,完成业务数据的处理以及业务流程的流转机制, ...

  8. django路由初识

    静态文件配置 1.项目下面新建一个文件夹static settings.py中最后添加 STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static ...

  9. final修饰的类有什么特点

    变量定义为final,一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变. 方法定义为final,是为了防止任何继承类改变它. 类定义为final, ...

  10. 并发工具类(三)控制并发线程的数量 Semphore

    前言   JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Ph ...