要求:以左右孩子表示法实现链式方式存储的二叉树(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. bzoj1825: [JSOI2010]蔬菜庆典

    Description Input Output 对于每组数据,输出一行.若蔬菜的总价能无限制增大,输出"+inf"(不含引号).否则输出一个整数,表示所有蔬菜的最大总价.   首 ...

  2. Java堆外内存之三:堆外内存回收方法

    一.JVM内存的分配及垃圾回收 对于JVM的内存规则,应该是老生常谈的东西了,这里我就简单的说下: 新生代:一般来说新创建的对象都分配在这里. 年老代:经过几次垃圾回收,新生代的对象就会放在年老代里面 ...

  3. table边框

    border-collapse 语法 border-collapse:separate | collapse | inherit 默认值:separate 取值 separate: 默认值.边框会被分 ...

  4. sklearn 线性模型使用入门

    LinearRegression fits a linear model with coefficients  to minimize the residual sum of squares betw ...

  5. 解决不能正常访问workerman的问题

    问题描述: 在阿里云ECS上部署了workerman的应用(ECS是专有网络),在ECS安全组里已经允许workerman需要的全部端口,但是外网一直不能正常打开(注,其他服务,比80端口外部是可以用 ...

  6. Swift里的CAP理论和NWR策略应用

    http://blog.sina.com.cn/s/blog_57f61b490101a8ca.html 最近有人讨论到swift副本数是否能够调整,3副本成本过高,如果改成2副本怎么样?多聊了几句以 ...

  7. 知识picture

  8. 图片水平垂直居中(兼容IE6,IE7,firefox,opera,safari,其中图片可以是任何块元素)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. spring 的 切片Aspect

    语法:  <aop:config> <!-- 配置多个切点,&& || ! --> <aop:pointcut id="pc" exp ...

  10. vue深入了解组件——动态组件&异步组件

    一.在动态组件上使用 keep-alive 我们之前曾经在一个多标签的界面中使用 is 特性来切换不同的组件: <component v-bind:is="currentTabComp ...