线性结构之——二叉树的遍历

1.遍历
所谓二叉树的遍历,是指按某条搜索路径访问树中的每个结点,使得每个结点均被访问一次,而且仅被访问一次。
由二叉树的递归定义可知,遍历一棵二叉树便要决定对根结点N、左子树L和右子树R的访问顺序。按照先遍历左子树再遍历右子树的原则,常见的遍历次序有先序(NLR)、中序(LNR)和后序(LRN)三种遍历算法,其中,序指的是根节点在何时被访问。除了上述三种遍历,还有层次遍历,前三种一般使用深度优先搜索(DFS)实现,而层次遍历一般用广度优先搜索(BFS)实现。

2.先序遍历
二叉树的递归定义中的递归边界是二叉树是一棵空树,即在递归访问子树时,如果碰到子树为空,那么就说明到达了边界。
先序遍历的操作过程:
如果二叉树为空,什么也不做,否则
(1)访问根节点
(2)先序遍历左子树
(3)先序遍历右子树
先序遍历递归的代码如下:

struct node{
	int data;    //数据域 
	node* lchild;   //左指针域 
	node* rchild;   //右指针域 
};

void preorder(node* root){
	if(root == NULL) return;
	
	visit(root->data );  //访问根节点 
	preorder(root->lchild ); //递归访问左子树
 	preorder(root->rchild ); //递归访问右子树
} 

3.中序遍历
中序遍历的操作过程为:
如果二叉树为空,什么也不做,否则:
(1)中序遍历左子树
(2)访问根节点
(3)中序遍历右子树
中序遍历递归代码如下:

void inorder(node* root){
	if(root == NULL) return;
	
	inorder(root->lchild ); //递归访问左子树
	visit(root->data );  //访问根节点 
 	inorder(root->rchild ); //递归访问右子树
} 

4.后序遍历
后序遍历的操作过程为:
如果二叉树为空,什么也不做,否则:
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根节点
后序遍历递归代码如下:

void postorder(node* root){
	if(root == NULL) return;
	
	postorder(root->lchild ); //递归访问左子树
 	postorder(root->rchild ); //递归访问右子树
	
	visit(root->data );  //访问根节点 	
} 

5.层次遍历
层次遍历是指按层次的顺序从根节点向下逐层进行遍历,且对同一层的结点为从左到右遍历。层次遍历就相当于对二叉树从根节点开始的广度优先搜索,基本思路如下:
(1)将根节点root加入队列q
(2)取出队首结点,访问它
(3)如果该结点有左孩子结点,将左孩子入队
(4)如果该结点有右孩子,将右孩子入队
(5)返回(2),直到队列为空。
代码如下:

void Layerorder(node* root){
	queue<node*> q;  //队列里存入地址
	q.push(root);  //将根节点地址入队
	while(!=q.empty()){
		node* now = q.front();  //取出队首地址
		q.pop();  //将队首地址出队
		printf("%d",root->data );//访问队首元素
		
		if(root->lchild != NULL)  q.push(root->lchild);  
		if(root->rchild != NULL)  q.push(root->rchild); 
	} 
}

6.二叉树的静态实现
静态二叉链表是指,结点的左右指针域使用int型代替,用来表示左右子树的根节点在数组中的下标。为此需要建立一个大小为结点上限个数node型数组,所有动态生成的结点都直接使用数组中的结点,所有对指针的操作都改为对数组下标的访问。结点node的定义如下:

struct node{
	int data;  //数据域
	int lchild;//指向左子树的指针域 
	int rchild; // 指向右子树的指针域 
}Node[maxn];  //结点数组,maxn为结点上限个数 

结点的动态生成就可以转变为如下的静态指定:


int index = 0;
int newNode(int v){
	Node[index].data = v;//   数据域为v
	Node[index].lchild = -1;
	Node[index].rchild = -1;//以-1或maxn表示空 
} 

//查找,root为根节点在数组中的下标
void search(int root, int x, int newdata){
	if(root == -1)   return;  //递归边界
	
	if(Node[root].data = x){
		Node[root].data = newdata;  //找到数据域为x的结点,修改数据域
		 
	} 
	
	search (root->lchild, x, newdata);
	search(root->rchild, x, newdata); 
} 
//插入 
void insert(int &root, int x){  //记得加引用 
	if(root == -1)  {
		root = newNode(x);  //给root赋以新值 
		return;
	} 
	if(由二叉树的性质x应该插在左子树){
	insert(Node[root].lchild, x) 
	}
	else{
		insert(Node[root].rchild);
	}
	return root;  //返回二叉树的根节点下标 
}

//建立二叉树,函数返回根节点root的下标
int Create(int data[], int n) {
	int root = -1;  //新建根节点
	for(int i=0; i<n; i++){
		insert(root, data[i]);
	} 
	return root;//返回根节点下标 
}
//先序遍历
void preorder(int root){
	if(root == 1)  return;
	
	visit(root->data);
	preorder(Node[root].lchild);
	preorder(Node[root].rchild );	
} 

//中序遍历
void inorder(int root){
	if(root == 1)  return;
	
	inorder(Node[root].lchild);
	visit(root->data);
	inorder(Node[root].rchild );	
}

//后序遍历
void postorder(int root){
	if(root == 1)  return;
	
	postorder(Node[root].lchild);
	postorder(Node[root].rchild );
	visit(root->data);
}	

//层次遍历
void Layerorder(int root){
	queue<int> q;  //队列存放结点下标
	q.push(root);
	while(!q.empty()){
		int now = q.front();
		q.pop();
		printf("%d", Node[root].data );
		
		if(Node[root].lchild != -1)  q.push(Node[root].lchild );
		if(Node[root].rchild != -1)  q.push(Node[root].rchild );
	} 
} 

非递归算法遍历

猜你喜欢

转载自blog.csdn.net/xiaoyong5854/article/details/106419586