要求:以左右孩子表示法实现链式方式存储的二叉树(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. 【比特币】SPV是如何工作的

    SPV是如何工作的 SPV, Bloom 过滤器和检查点 这是一篇技术文章,获取比特币的工作知识. 一个完整的节点,比如比特币核心,知道以下几点: 每一个当前正在围绕网络广播事务处理 每一个曾经被送到 ...

  2. 学习笔记之C/C++指针使用常见的坑

    https://mp.weixin.qq.com/s/kEHQjmhNtSmV3MgHzw6YeQ 避免内存泄露 不再用到的内存没有释放,就叫做内存泄露 在C/C++中,通过动态内存分配函数(如mal ...

  3. 【精】Linux磁盘I/O性能监控之iostat详解

    [精]Linux磁盘I/O性能监控之iostat详解 Linux命令详解----iostat 使用iostat分析IO性能

  4. 【转载】Linux内存中buffer和 cached的比较

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多? 在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是linux内存管理的一个优秀特性,在 ...

  5. 从Tomcat无法正常关闭讲讲Java线程关闭问题【转载】

    正常情况下,会优先采用catalina.sh stop来停止Tomcat实例,这样可以让服务有机会处理完请求,并做好善后工作. 但如果通过catalina.sh stop命令无法关闭Tomcat实例, ...

  6. VMware仅主机模式访问外网

    原文转载至:https://blog.csdn.net/eussi/article/details/79054622 保证VMware Network Adapter VMnet1是启用状态  将可以 ...

  7. BatchNormalization批量归一化

    动机: 防止隐层分布多次改变,BN让每个隐层节点的激活输入分布缩小到-1和1之间. 好处: 缩小输入空间,从而降低调参难度:防止梯度爆炸/消失,从而加速网络收敛. BN计算公式: keras.laye ...

  8. 给iOS开发新手送点福利,简述UIPikerView的属性和用法

    1.   numberOfComponents:返回UIPickerView当前的列数 NSInteger num = _pickerView.numberOfComponents; NSLog( @ ...

  9. 编写一个函数,在页面上输出一个N行M列的表格,表格内容填充0~100的随机数字

    function print(n,m){     document.write("<table>");     for(var i=0; i<n; i++){   ...

  10. 逆地址解析协议RARP

    解决的问题 一般系统启动时,从引导磁盘中获取ip 有些机器没有引导磁盘,如X终端或无盘工作站,则需要采用其他方法来获得IP地址 解决的过程 无盘系统依据RARP协议 从接口卡上读取唯一的硬件地址,然后 ...