码迷,mamicode.com
首页 > 其他好文 > 详细

数据结构——二叉树的遍历

时间:2014-08-01 13:47:41      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:二叉树   前序遍历   中序遍历   后序遍历   层序遍历   

            二叉树主要有三种遍历方式:前序遍历、中序遍历和后序遍历,每种方式都有递归和非递归两种方法。递归的方法简单明了,但是会比较耗时,非递归的方法效率相对较高,但是算法也比较晦涩。本文就这三种遍历方式做简单的介绍。

数据结构:

struct BTree{
        int data;
	BTree *lchild;
	BTree *rchild;
};

一、 前序遍历

1.  递归的算法:

前序遍历每次先访问根结点,然后访问左子树,接着是右子树。用递归的方法很容易写出递归的算法:

void preTraverse(BTree *t)
{
	cout<<t->data<<" ";
	if(t->lchild)
		preTraverse(t->lchild);
	if(t->rchild)
		preTraverse(t->rchild);
}

         先访问根节点,然后递归访问左子树,接着是右子树。

2. 非递归算法:

由于函数的递归调用归根到底使用的是栈保存相关的变量,我们可以按照递归调用的过程,借助于栈将递归的算法改成非递归的算法。

void preOrder(BTree *t)
{
	stack<BTree *> stk;
	stk.push(t);
	while(!stk.empty())
	{
		BTree *q = stk.top();
		stk.pop();
		cout<<q->data<<" ";
		if(q->rchild)
			stk.push(q->rchild);
		if(q->lchild)
			stk.push(q->lchild);
	}
	cout<<endl;
}
  这里我们采用一个栈保存访问过的节点,先访问根节点,然后将右子树根节点入栈,接着是左子树根节点。之所以先右后左,因为栈是后进先出的数据结构,我们要先访问左子树后访问右子树,所以要先将右子树根节点入栈再将左子树根节点入栈。

二、 中序遍历

1. 递归算法:

       中序遍历先访问左子树,然后访问根节点,接着访问右子树。递归的算法如下:

void inTraverse(BTree *t)
{
	if(t->lchild)
		inTraverse(t->lchild);
	cout<<t->data<<" ";
	if(t->rchild)
		inTraverse(t->rchild);
}

2. 非递归算法:

       中序遍历的时候,先访问左子树,再访问根节点,接着是右子树,那么我们需要用栈保存未访问的节点。当节点的左子树已经被访问之后,就将节点出栈,进行访问,然后将右子树根节点入栈。

void inOrder(BTree *t)
{
	stack<BTree *> stk;
	BTree *p = t;
	while(!stk.empty() || p)
	{
		while(p)
		{
			stk.push(p);
			p = p->lchild;
		}
		p = stk.top();
		cout<<p->data<<" ";
		stk.pop();
		p = p->rchild;
	}
	cout<<endl;
}

对于每个节点,都向左走到尽头,直至没有左孩子的时候,就访问这个节点,接着访问其右孩子。如果没有右孩子或者右孩子已经访问,就继续回溯。


三、 后序遍历

1. 递归算法: 

         后序遍历的时候先访问左子树,然后是右子树,最后才访问根节点。递归算法如下:

void postTraverse(BTree *t)
{
	if(t->lchild)
		postTraverse(t->lchild);
	if(t->rchild)
		postTraverse(t->rchild);
	cout<<t->data<<" ";
}

2. 非递归算法:

          后序遍历的非递归算法较复杂,因为后续遍历需要确认左右子树都访问之后才访问根节点,因此,不仅需要栈保存节点,而且需要有状态指示其左子树和右子树都已经被访问过了,这个时候才可以访问根节点。

void postOrder(BTree *t)
{
	stack<BTree *> stk;
	vector<int> tag;
	int k = -1;
	BTree *p = t;
	while(!stk.empty() || p)
	{
		while(p)
		{
			stk.push(p);
			tag.push_back(1);
			++k;
			p = p->lchild;
		}
		while(!stk.empty() && tag.back() == 2){
			p = stk.top();
			cout<<p->data<<" ";
			stk.pop();
			tag.pop_back();
			--k;
		}
		if(stk.empty())
			break;
		p = stk.top();
		tag[k] = 2;
		p = p->rchild;
		
	}
	cout<<endl;
}

         以上用一个tag来存储访问的状态,1表示访问了左孩子,2表示访问了右孩子。当节点的tag为2 的时候,表示其左右孩子都已经被访问过了,这个时候就可以访问这个节点。


四、 层序遍历

二叉树的层序遍历有点类似于图的广度优先搜索算法,先访问根节点,接着将临近的每个节点都入队列,按照入队列/出队列的顺序访问每个元素。

//层序遍历---非递归---借助于队列
void levelOrder(BTree *t)
{
	queue<BTree *> Q;
	Q.push(t);
	while(!Q.empty())
	{
		BTree *q = Q.front();
		Q.pop();
		cout<<q->data<<" ";
		if(q->lchild)
			Q.push(q->lchild);
		if(q->rchild)
			Q.push(q->rchild);
	}
	cout<<endl;
}

五、 总的代码:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <stack>
#include <queue>

using namespace std;

struct BTree{
	int data;
	BTree *lchild;
	BTree *rchild;
	BTree(){
		this->data = 0;
		this->lchild = NULL;
		this->rchild = NULL;
	}
	BTree(int d){
		this->data = d;
		this->lchild = NULL;
		this->rchild = NULL;
	}
};

BTree* buildNode(int a[], int k);
void PrintTree(BTree *p);
void preTraverse(BTree *t);
void inTraverse(BTree *t);
void postTraverse(BTree *t);
void levelOrder(BTree *t);
void preOrder(BTree *t);
void inOrder(BTree *t);
void postOrder(BTree *t);

int main(int argc, char* argv[])
{
	int n;
	while(cin>>n)
	{
		int *a = new int[n+1];
		a[0] = n;
		for(int k = 1; k <= n; ++k)
			cin>>a[k];
		BTree *t = buildNode(a, 1);
		PrintTree(t);
		
		cout<<"**************levelOrder--non-recursive********"<<endl;
		levelOrder(t);
		cout<<"*************************************************"<<endl;

		cout<<"--------------preTraverse--recursive-------------"<<endl;
		preTraverse(t);
		cout<<endl<<"-------------------------------------------------"<<endl;

		cout<<"**************preOrder--non-recursive********"<<endl;
		preOrder(t);
		cout<<"*************************************************"<<endl;

		cout<<"--------------inTraverse--recursive-------------"<<endl;
		inTraverse(t);
		cout<<endl<<"-------------------------------------------------"<<endl;

		cout<<"**************inOrder--non-recursive********"<<endl;
		inOrder(t);
		cout<<"*************************************************"<<endl;

		cout<<"--------------postTraverse--recursive-------------"<<endl;
		postTraverse(t);
		cout<<endl<<"-------------------------------------------------"<<endl;

		cout<<"**************postOrder--non-recursive********"<<endl;
		postOrder(t);
		cout<<"*************************************************"<<endl;
	}
	
	return 0;
}
//后续遍历---非递归
void postOrder(BTree *t)
{
	stack<BTree *> stk;
	vector<int> tag;
	int k = -1;
	BTree *p = t;
	while(!stk.empty() || p)
	{
		while(p)
		{
			stk.push(p);
			tag.push_back(1);
			++k;
			p = p->lchild;
		}
		while(!stk.empty() && tag.back() == 2){
			p = stk.top();
			cout<<p->data<<" ";
			stk.pop();
			tag.pop_back();
			--k;
		}
		if(stk.empty())
			break;
		p = stk.top();
		tag[k] = 2;
		p = p->rchild;
		
	}
	cout<<endl;
}

//中序遍历---非递归
void inOrder(BTree *t)
{
	stack<BTree *> stk;
	BTree *p = t;
	while(!stk.empty() || p)
	{
		while(p)
		{
			stk.push(p);
			p = p->lchild;
		}
		p = stk.top();
		cout<<p->data<<" ";
		stk.pop();
		p = p->rchild;
	}
	cout<<endl;
}

//先序遍历---非递归----借助于栈
void preOrder(BTree *t)
{
	stack<BTree *> stk;
	stk.push(t);
	while(!stk.empty())
	{
		BTree *q = stk.top();
		stk.pop();
		cout<<q->data<<" ";
		if(q->rchild)
			stk.push(q->rchild);
		if(q->lchild)
			stk.push(q->lchild);
	}
	cout<<endl;
}

//层序遍历---非递归---借助于队列
void levelOrder(BTree *t)
{
	queue<BTree *> Q;
	Q.push(t);
	while(!Q.empty())
	{
		BTree *q = Q.front();
		Q.pop();
		cout<<q->data<<" ";
		if(q->lchild)
			Q.push(q->lchild);
		if(q->rchild)
			Q.push(q->rchild);
	}
	cout<<endl;
}


//后序遍历
void postTraverse(BTree *t)
{
	if(t->lchild)
		postTraverse(t->lchild);
	if(t->rchild)
		postTraverse(t->rchild);
	cout<<t->data<<" ";
}


//中序遍历
void inTraverse(BTree *t)
{
	if(t->lchild)
		inTraverse(t->lchild);
	cout<<t->data<<" ";
	if(t->rchild)
		inTraverse(t->rchild);
}

//pre-order
void preTraverse(BTree *t)
{
	cout<<t->data<<" ";
	if(t->lchild)
		preTraverse(t->lchild);
	if(t->rchild)
		preTraverse(t->rchild);
}

BTree* buildNode(int a[], int k){//构建第k个Node
	if(k > a[0] || a[k] == -1)
		return NULL;
	BTree *p = new BTree(a[k]);
	p->lchild = buildNode(a, 2*k);
	p->rchild = buildNode(a, 2*k+1);
	return p;
}

void PrintTree(BTree *p)
{
	int k = 1, cnt = 0;
	queue<BTree *> que;
	que.push(p);
	while(!que.empty())
	{
		BTree *q = que.front();
		que.pop();
		if(q->lchild != NULL)
			que.push(q->lchild);
		if(q->rchild != NULL)
			que.push(q->rchild);
		cout<<q->data<<" ";
		++cnt;
		if(cnt == k){
			cout<<endl;
			k = 2*k;
			cnt = 0;
		}
	}
	if(cnt != 0)
		cout<<endl;
}




数据结构——二叉树的遍历,布布扣,bubuko.com

数据结构——二叉树的遍历

标签:二叉树   前序遍历   中序遍历   后序遍历   层序遍历   

原文地址:http://blog.csdn.net/uilotus/article/details/38332701

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!