二叉树的建立、三种(递归、非递归)遍历方法

二叉树定义:

1.有且仅有一个特定的称之为根root的结点

2.当n>1时,除根结点之外的其余结点分为两个互不相交的子集。他们称为二叉树的左子树和右子树。

二叉树的一种建立方法:

若对有n个结点的完全二叉树进行顺序编号(1<=i<=n),那么,对于编号为i(i>=1)的结点。

当i=1时,该结点为根,它无双亲结点;

当i>1时,该节点的双亲编号为[i/2];

若2i<=n,该结点为编号为2i的左孩子,否则没有左孩子

当2i+1<=n,该结点有编号为2i+1的右孩子,否则没有右孩子

利用上个性质,对任意二叉树,先按满二叉树对其所有结点进行编号。

注意:由于此树并非完全树,所以结点的编号并不连续。

遍历二叉树:

遍历二叉树是指以一定的次序访问二叉树中的每个结点,并且每个结点仅被访问一次,访问结点是指进行各种操作的简称。3种遍历次序:中根遍历二叉树、先根遍历二叉树、后根遍历二叉树。

递归算法:

先根遍历:如果根不为空,1.访问根结点2.按先根次序遍历左子树,3.按先根次序遍历右子树,否则返回。

中根遍历:如果根不为空,1.按中根次序遍历左子树,2.访问根结点,3.按中根次序遍历右子树,否则返回。

后根遍历:如果根不为空,1.按后根次序遍历左子树,2.按后根次序遍历右子树,3.访问根结点,否则返回。

中根遍历非递归算法:

需要人为设置一个栈来存放所经过的根结点的指针(栈我图简单,直接调用STL标准库的),第一次遇到根结点并不访问,而是如栈,然后中根遍历左子树。左子树遍历结束后,第二次遇到根结点,退栈并访问该结点。然后遍历右子树。

先根遍历非递归算法:同中根遍历非递归算法,只是把输出位置提前

后根遍历非递归算法:

后根遍历在搜索线第一次经过根结点时不访问进行如栈,在遍历左子树之后,搜索线第二次经过根结点时也不能访问,继续遍历右子树,直到搜索线第三次经过根结点时,退栈并且访问根结点。因此,另设一个辅助栈用来记录经过某个结点的次数。

废话少说,上代码......

BinaryTree.h

#ifndef BINARYTREE_H_
#define BINARYTREE_H_
typedef int T;
struct Node
{
	T data;
	Node *lch;
	Node *rch;
};
class BinaryTree
{
protected:
	Node *root;
public:
	BinaryTree();
	~BinaryTree();
	void Create();
	void preorder();
	void Preorder()
	{
		Preorder(root);
	}
	void inorder();
	void Inorder()
	{
		Inorder(root);
	}
	void postorder();
	void Postorder()
	{
		Postorder(root);
	}
private:
	void Inorder(Node *p);
	void Preorder(Node *p);
	void Postorder(Node *p);
	void Destroy(Node *p);
};

#endif

BinaryTree.cpp

#include "BinaryTree.h"
#include <iostream>
#include <stack>
using namespace std;
BinaryTree::BinaryTree()
{
	root=NULL;
}
BinaryTree::~BinaryTree()
{
	Destroy(root);
	root=NULL;
}
void BinaryTree::Inorder(Node *p)
{
	if(p!=NULL)
	{
		Inorder(p->lch);
		cout<<p->data<<" ";
		Inorder(p->rch);
	}
}
//非递归法实现中根遍历
void BinaryTree::inorder()
{
	Node *p=root;
	Node *q;
	stack<Node *> S;
	do
	{
		while(p!=NULL)
		{
			S.push(p);
			p=p->lch;
		}
		p=S.top();
		S.pop();
		cout<<p->data<<" ";
		p=p->rch;
	}while(!(S.empty() && p==NULL));
}
//先根遍历,用递归法
void BinaryTree::Preorder(Node *p)
{
	if(p!=NULL)
	{
		cout<<p->data<<" ";
		Preorder(p->lch);
		Preorder(p->rch);
	}
}
//先根遍历的非递归算法
void BinaryTree::preorder()
{
	Node *p=root;
	stack<Node *> S;
	do
	{
		while(p!=NULL)
		{
			S.push(p);
			cout<<p->data<<" ";
			p=p->lch;
		}
		p=S.top();
		p=p->rch;
		S.pop();
	}while(!(S.empty() && p==NULL));
}
//后根
void BinaryTree::Postorder(Node *p)
{
	if(p!=NULL)
	{
		Postorder(p->lch);
		Postorder(p->rch);
		cout<<p->data<<" ";
	}
}
//非递归法实现后根遍历
void BinaryTree::postorder()
{
	stack<Node *>S;
	stack<int> s;
	Node *p=root;
	int t=0;
	do
	{
		while(p!=NULL)
		{
			s.push(1);
			S.push(p);
			p=p->lch;
		}
		t=s.top();
		if(t==2)
		{
			p=S.top();
			S.pop();
			s.pop();
			cout<<p->data<<" ";
			p=NULL;
		}
		if(!s.empty())
		{
			t=s.top();
		}
		if(t==1)
		{
			p=S.top();
			p=p->rch;
			s.pop();
			s.push(2);
		}

	}while(!(S.empty() && p==NULL));
}
void BinaryTree::Destroy(Node *p)
{
	if(p!=NULL)
	{
		Destroy(p->lch);
		Destroy(p->rch);
		delete p;
	}
}

void BinaryTree::Create()
{
	Node *q, *s[20]; T x; int i,j;
	cout<<"请按照二叉树的层序,自上而下自左至右的顺序组织数据"<<endl;
	cout<<"每次输入结点的序号和数据,假设根结点值为11;"<<endl;
	cout<<"那么输入应是:1 11,若两者都输入0,则输入结束。"<<endl;
	root=NULL;
	cout<<"i,x = "; cin>>i>>x;
	while((i!=0)&&(x!=0))
	{
		q=new Node;
		q->data=x;
		q->lch=NULL;
		q->rch=NULL;
		s[i]=q;
		if(i==1)
		{
			root=q;
		}
		else
		{
			j=i/2;
			if(i%2==0)
			{
				s[j]->lch=s[i];
			}
			else
			{
				s[j]->rch=s[i];
			}
		}
		cout<<"i,x = "; cin>>i>>x;
	}
	cout<<"二叉树建立完毕!"<<endl;
}

main.cpp

//直接调用STL库中的栈吧,不在
#include "BinaryTree.h"
#include <iostream>

using namespace std;

int main()
{
	/*cout<<"hello,world"<<endl;*/
	BinaryTree BT;
	BT.Create();
	cout<<"先根遍历二叉树:"<<endl;
	BT.Preorder();
	cout<<endl<<"先根非递归遍历二叉树:"<<endl;
	BT.preorder();
	cout<<endl<<"中根遍历二叉树:"<<endl;
	BT.Inorder();
	cout<<endl<<"中根非递归遍历二叉树:"<<endl;
	BT.inorder();
	cout<<endl<<"后根遍历二叉树:"<<endl;
	BT.Postorder();
	cout<<endl<<"后根非递归遍历二叉树:"<<endl;
	BT.postorder();
	cout<<endl;
	system("pause");
	return 0;
}

结果:

时间: 2024-08-09 19:53:40

二叉树的建立、三种(递归、非递归)遍历方法的相关文章

二叉树总结—建树和4种遍历方式(递归&amp;&amp;非递归)

今天总结一下二叉树,要考离散了,求不挂!二叉树最重要的就是 建立.4种遍历方式,简单应用,如何判断两颗二叉树是否相似 二叉树分为 :1.完全二叉树  2.满二叉树 结构性质: 1).满二叉树 高度为h ,节点数则为 2^h - 1,且叶子节点全在最下层,且叶子节点数为2^(n-1)个{n代表二叉树层数,也叫深度} 2).n个节点的 完全二叉树 深度为 int(log2n)(以2为底n的对数)+ 1: 3).非空二叉树 叶子节点个数==双分支节点数+1 4).非空二叉树 某节点编号 n  若有左孩

【算法导论】二叉树的前中后序非递归遍历实现

二叉树的递归遍历实现起来比较简单,而且代码简洁:而非递归遍历则不那么简单,我们需要利用另一种数据结构---栈来实现.二叉树的遍历又可以分为前序.中序和后序三种,它们是按照根结点在遍历时的位置划分的,前序遍历则根结点先被遍历,中序则根结点在左右叶子节点之间被遍历,后序则是根结点最后被遍历.三种非递归遍历中,前序和中序都不是太复制,而后序遍历则相对较难. 一.前序遍历 我们这里前序遍历按照"根-左-右"的顺序来遍历.这里按照"递归--非递归"的次序来研究,之后的几种亦是

二叉树基础(创建方法,遍历方法(前序/中序/后序/层序、递归/非递归)

二叉树的创建及遍历是很多二叉树问题的基础,递归遍历逻辑清晰,代码简约漂亮,然则效率低下(所有递归方案的通病,非不得已不用递归): 非递归遍历高效,却不是能信手写出来的,特别是后续非递归遍历,相信很多资深码工也有这样的经历: 5年前学习了二叉树的非递归遍历,一个月前复习了并达到能熟练写出的程度,在不参考任何资料的情况下,今天却怎样也写不出来. 如果你也有过这种经历,恭喜你,这说明你是一个正常人…… 另一方面市面上有些国人写的教材,各种语法.逻辑错误层出不起,不知祸害了多少未来的码工,深感痛心. 印

快速排序递归非递归队列堆栈实现

递归实现 #include<iostream> using namespace std; template <class T> void QuickSort(T A[],int left,int right) { if(left<right) { int i=left; int j=right+1; do { do i++;while(A[i]<A[left]); do j--;while(A[j]>A[left]); if(i<j) Swap(A[i],A

【算法拾遗】二分查找递归非递归实现

转载请注明出处:http://blog.csdn.net/ns_code/article/details/33747953 本篇博文没太多要说的,二分查找很简单,也是常见常考的查找算法,以下是递归非递归的实现. 非递归实现: /* 非递归实现,返回对应的序号 */ int BinarySearch(int *arr,int len,int key) { if(arr==NULL || len<1) return -1; int low = 0; int high = len-1; while(l

hadoop搭建杂记:Linux下JDK环境变量的设置(三种配置环境变量的方法)

Linux下JDK环境变量的设置(三种配置环境变量的方法) Linux下JDK环境变量的设置(三种配置环境变量的方法) ①修改/etc/profile文件 如果你的计算机仅仅作为开发使用时推荐使用这种方法,因为所有用户的shell都有权使用这些环境变量,可能会给系统带来安全性问题. vi /etc/profile 在profile文件末尾加入: JAVA_HOME=/usr/share/jdk1.5.0_05PATH=$JAVA_HOME/bin:$PATHCLASSPATH=.:$JAVA_H

三种创建XMLHttpRequest对象的方法

XMLHttpRequest对象,也就是Ajax交互的核心对象. 这里列举三种创建Ajax对象的方法. 第一种: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Examples&

三种Div高度自适应的方法

让DIV高度自适应,这是在网页设计中常遇到的问题,为了给大家提供参考,这里提供3种div高度自适应的方法:一是JS法.二是背景图填充法.三是"补丁大法"(比较变态). 1.JS法 代码如下.原理:用JS判断左右DIV的高度,若不一致则设为一致.框架资源分享 Java代码   <div style="width:500px;background:#cccccc;height:0px;"> <div id="right" style

web三种跨域请求数据方法

web三种跨域请求数据方法 以下测试代码使用php,浏览器测试使用IE9,chrome,firefox,safari <!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.

三种微信爆粉的方法,一天加满5000好友

2018年,朋友圈或各种社交场合总时不时冒出"某某做微信爆粉,一天加满5000好友"的说法.这确实是存在的,但严重违规.突破每日添加好友数量上限的双向爆粉,必须使用修改微信底层协议的第三方软件才能实现.今天,无极颜汐教你三种微信爆粉的方法,一天加满5000好友. 微信爆粉的原理是什么?识别微信号ID有很多类型,如:微信号.手机号.QQ号.二维码等,但这些只是肉眼可见的表面数据.实际上,微信的服务器里还有一套识别每个微信号的内部代码数据,如:v1v2数据与wxid.v1v2数据可以理解为