[转]数据结构 二叉树的遍历

/**********************************************************************
二叉树的基本操作
(1)二叉树的数据结构
(2)二叉树的构造
(3)二叉树遍历 :先序,中序,后序
************************************************************************/
#include <cstdio>
#include <cstdlib>
const int MAX=20;
//二叉树的结构 利用双链表实现
typedef struct Node
{
	char ch;				 // 数据域
	struct Node *plchild;    //左子树指针
	struct Node *prchild;	//右子树指针
}BiTreeNode;

//构造二叉树
//1.按照先序遍历法构造 利用递归构造
// ABD#G##EH##I##CF#J###
void CreateBiTree_PreOrder(BiTreeNode * &T) //注意这里传入的是指针的引用
{
	char ch;
	scanf("%c",&ch);
	if(‘#‘==ch)
		T=NULL;
	else {
		T=new BiTreeNode;
		if(NULL==T)
			exit(-1);
		T->ch=ch;
		CreateBiTree_PreOrder(T->plchild); // 构造左子树
		CreateBiTree_PreOrder(T->prchild); // 构造右子树
	}
}
//2.按照带括号的字符串创建二叉树结构
/*思路:a(b(c,d),e(f(,g),h(i)))
	‘(‘: 表明已创建的节点为双亲节点,入栈。将要创建左孩子节点,用flag=1标记
	‘,‘: 表明将要创建右孩子节点。用flag=2标记
	‘)‘: 表明左右孩子节点创建和链接完毕,父节点出栈。
	default: 创建节点,并且赋值,判断链接情况
 */
void CreateBiTree_ByString(BiTreeNode* &T, char str[])
{
	BiTreeNode* Stack[MAX];		// 栈用于存储父节点
	int top=0,flag=0;
	BiTreeNode* p=NULL;			//用于临时指针
	while(*str)
	{
		switch(*str)
		{
			case ‘(‘:
					Stack[top++]=p;
					flag=1;		//表示即将要创建的是 左孩子节点
					break;
			case ‘,‘:
					flag=2;  //表明将要创建	右孩子节点
					break;
			case ‘)‘:
					--top;	//将父节点出栈
					break;
			default:
				{
					p=new BiTreeNode;
					if(NULL==p)
						return  ;
					if(T==NULL)
						T=p;
					p->ch=*str;
					p->plchild=NULL;
					p->prchild=NULL;
					switch(flag) //此时 flag要初始化 不然非法访问
					{
						case 1:
							Stack[top-1]->plchild=p; //将父节点与左孩子节点链接
							break;
						case 2:
							Stack[top-1]->prchild=p; //将父节点与右孩子节点链接
							break;
					}
					break;
				}
		}
		++str;
	}
}
// 递归先序遍历
void PreOrderTraverse_Recur(BiTreeNode *T)
{
	if(T)
	{
		printf("%2c",T->ch);
		PreOrderTraverse_Recur(T->plchild);
		PreOrderTraverse_Recur(T->prchild);
	}
}
// 非递归先序遍历
/* 思路: 先访问父节点,打印。然后压入栈中,然后访问左孩子节点,访问打印压栈。
		将左孩子一个个压入栈中,直到NULL.然后在访问右孩子节点。同理按前
 */
void PreOrderTraverse_NoRecur(BiTreeNode *T)
{
	BiTreeNode* Stack[MAX]; //利用数组构造栈 先进后出
	int top=0;
	BiTreeNode *p=T;
	while( p || top >0)
	{
		while(p)
		{
			printf("%2c",p->ch);	//先访问
			Stack[top++]=p;		//将 父节点压栈
			p=p->plchild;		//访问左孩子节点
		}
		if(top>0)	//top 代表栈中有多个节点
		{ //开始访问 右孩子节点
			p=Stack[--top];		//如果某个父节点的左孩子节点为NULL 那么出栈该父节点。
			p=p->prchild;		//然后又跳入到 访问该右孩子的左子树
		}
	}
}
// 递归中序遍历
void InOrderTraverse_Recur(BiTreeNode *T)
{
	if(T)  //如果节点不为NULL
	{
		InOrderTraverse_Recur(T->plchild); //先放问 左孩子树
		printf("%2c",T->ch);		   //然后在 访问根节点
		InOrderTraverse_Recur(T->prchild); // 然后在访问 右孩子树
	}
}
// 非递归中序遍历
/* 思路:相比于先序而言(一直将父节点压栈,父节点出栈的时候就是要访问该节点的右孩子树)
		 所以中序遍历,一直压入左孩子节点,直到NULL.在出栈的时候打印父节点值。
 */
void InorderTraverse_NoRecur(BiTreeNode *T)
{
	BiTreeNode* Stack[MAX];
	int top=0;
	BiTreeNode *p=T;
	while( p || top>0 )
	{
		while(p)
		{
			Stack[top++]=p;  //直接将父节点入栈
			p=p->plchild;	// 然后访问左子树
		}
		if(top>0)
		{
			p=Stack[--top];		 //将父节点处栈
			printf("%2c",p->ch); //打印父节点值
			p=p->prchild;		 //访问右孩子子树
		}
	}
}
// 递归后序遍历
void AfterOrderTraverse_Recur(BiTreeNode *T)
{
	if(T)
	{
		AfterOrderTraverse_Recur(T->plchild);
		AfterOrderTraverse_Recur(T->prchild);
		printf("%2c",T->ch);
	}
}
// 非递归后序遍历
/*思路:依旧是将父节点依次压栈。直到左节点为NULL,此时不出栈父节点,而是直接访问右孩子节点
		同时设定q用于检测是否已经访问过右孩子节点。
 */
void AfterOrderTraverse_NoRecur(BiTreeNode *T)
{
	BiTreeNode* Stack[MAX];
	int top=0;
	BiTreeNode *p=T,*q=NULL; // q用于判断右节点是否访问过
	while(p || top>0)
	{
		while(p) //直到没有左孩子节点
		{
			Stack[top++]=p;
			p=p->plchild;
		}
		if(top>0)
		{
			p=Stack[top-1]; //不出栈 直接访问右子树
			if(p->prchild==NULL || p->prchild == q) //没有右节点或者右节点已经访问过
			{
				printf("%2c",p->ch);
				q=p;
				p=NULL;
				top--;
			}
			else //有右节点 且没被访问过
				p=p->prchild;
		}
	}

}
//销毁二叉树
void DestoryBiTree(BiTreeNode* &T)
{
	if(T)
	{
		if(T->plchild)
			DestoryBiTree(T->plchild);
		if(T->prchild)
			DestoryBiTree(T->prchild);
		delete T;
		T=NULL;
	}
}
int main()
{//ABD#G##EH##I##CF#J###
	BiTreeNode *T=NULL;
	CreateBiTree_PreOrder(T);
	puts("递归先序遍历:");
	PreOrderTraverse_Recur(T);
	puts("");
	puts("非递归先序遍历:");
	PreOrderTraverse_NoRecur(T);
	puts("");
	puts("递归中序遍历:");
	InOrderTraverse_Recur(T);
	puts("");
	puts("非递归中序遍历:");
	InorderTraverse_NoRecur(T);
	puts("");
	puts("递归后序遍历:");
	AfterOrderTraverse_Recur(T);
	puts("");
	puts("非递归后序遍历:");
	AfterOrderTraverse_NoRecur(T);
	puts("");
	DestoryBiTree(T);	//销毁二叉树
	puts("\n--按照带括号的字符串输入------------");
	BiTreeNode *T2=NULL;
	char str[]="a(b(c,d),e(f(,g),h(i)))";
	CreateBiTree_ByString(T2,str);
	puts("递归先序遍历:");
	PreOrderTraverse_Recur(T2);
	puts("");
	puts("非递归先序遍历:");
	PreOrderTraverse_NoRecur(T2);
	puts("");
	puts("递归中序遍历:");
	InOrderTraverse_Recur(T2);
	puts("");
	puts("非递归中序遍历:");
	InorderTraverse_NoRecur(T2);
	puts("");
	puts("递归后序遍历:");
	AfterOrderTraverse_Recur(T2);
	puts("");
	puts("非递归后序遍历:");
	AfterOrderTraverse_NoRecur(T2);
	puts("");
	//DestoryBiTree(T2);	//销毁二叉树
}

  

时间: 2024-10-11 13:28:13

[转]数据结构 二叉树的遍历的相关文章

Java数据结构-二叉树及其遍历

二叉树的定义:n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互相不相交的.分别称为根结点的左子树和右子树的二叉树组成. 二叉树的特点: 0<=度<=2: 左右子树是有顺序的,不能颠倒: 不论有几棵子树,也要区分它是左子树还是右子树. 二叉树的五种基本形态: 空二叉树: 只有一个根结点: 根结点只有左子树: 根结点只有右子树: 根结点既有左子树又有右子树. 举例3个结点的二叉树的形态有: 下面说一些特殊的二叉树. 斜树:所有的结点都只有左子树的二叉

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

"树"是一种重要的数据结构,本文浅谈二叉树的遍历问题,採用C语言描写叙述. 一.二叉树基础 1)定义:有且仅有一个根结点,除根节点外,每一个结点仅仅有一个父结点,最多含有两个子节点,子节点有左右之分. 2)存储结构 二叉树的存储结构能够採用顺序存储,也能够採用链式存储,当中链式存储更加灵活. 在链式存储结构中,与线性链表类似,二叉树的每一个结点採用结构体表示,结构体包括三个域:数据域.左指针.右指针. 二叉树在C语言中的定义例如以下: struct BiTreeNode{ int c;

数据结构 - 二叉树的遍历

中序遍历二叉树 1 递归算法 算法的递归定义是: 若二叉树为空,则遍历结束:否则 ⑴ 中序遍历左子树(递归调用本算法): ⑵ 访问根结点: ⑶ 中序遍历右子树(递归调用本算法). 中序遍历的递归算法 void InorderTraverse(BTNode *T) { if (T==NULL) return: InorderTraverse(T->Lchild) ; visit(T->data) ; /* 访问根结点 */ InorderTraverse(T->Rchild) ; } 2

数据结构-二叉树的遍历(类C语言描写叙述)

遍历概念 所谓遍历(Traversal)是指沿着某条搜索路线.依次对树中每一个结点均做一次且仅做一次訪问.訪问结点所做的操作依赖于详细的应用问题. 遍历是二叉树上最重要的运算之中的一个,是二叉树上进行其他运算之基础. 遍历方案 1.遍历方案 从二叉树的递归定义可知,一棵非空的二叉树由根结点及左.右子树这三个基本部分组成.因此.在任一给定结点上,能够按某种次序运行三个操作: (1)訪问结点本身(N), (2)遍历该结点的左子树(L), (3)遍历该结点的右子树(R). 以上三种操作有六种运行次序:

数据结构——二叉树层序遍历

层序遍历,即宽度优先遍历,在本算法中,我们还需要将每一层进行分开打印, 对于上图所示的二叉树,我们希望打印出的结果是: 1 2 3 4 5 6 7 8 首先,我们看一下二叉树节点是什么样的: class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } 具体实现中,我们采用last表示当前打印的行的最后一个元素的引用

数据结构——二叉树遍历之“递归与非递归遍历”

简述 二叉树的遍历分为先序遍历.中序遍历和后序遍历.如下图所示: 递归遍历 private void bianli1(List<Integer> list, TreeNode root) { // 先序遍历 if (root == null) { return; } list.add(root.val); bianli1(list, root.left); bianli1(list, root.right); } private void bianli2(List<Integer>

数据结构第三部分:树与树的表示、二叉树及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树、集合及其运算

参考:浙大数据结构(陈越.何钦铭)课件 1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找——方法一:顺序查找(时间复杂度O(n)) int

[数据结构]二叉树创建与遍历

实验报告:二叉树创建与遍历 一.问题描述 二叉树是一种实用范围很广的非线性结构,一棵非空二叉树有也只有一个根结点,每个结点最多有两个子树,我们称为左子树与右子树,当一个结点的左.右子树都是空的时,沃恩称此结点为叶子结点. 二叉树有一些很好的性质,这里不再赘述.考虑如何存储一棵树,本实验选择使用链式存储结构——二叉链表:如果事先知道需要存储的二叉树是满二叉树或者完全二叉树,则可以考虑使用顺序存储,否则将浪费大量的存储空间. 对于一棵既成的二叉树,有三种遍历方式——先序.中序与后序.可以证明,一棵形

数据结构二叉树——建立二叉树、中序递归遍历、非递归遍历、层次遍历

数据结构二叉树-- 编写函数实现:建立二叉树.中序递归遍历.借助栈实现中序非递归遍历.借助队列实现层次遍历.求高度.结点数.叶子数及交换左右子树. ("."表示空子树) #include<stdio.h> #include<stdlib.h> //***********二叉树链表节点结构 typedef char DataType; typedef struct Node {  DataType data;  struct Node*LChild;  struc