[数据结构笔记] 二叉树(二)

本文详细介绍了二叉树的四种遍历方法:前序、中序、后序和层序遍历,以及对应的遍历序列。同时,讨论了二叉树的顺序存储结构和二叉链表存储结构,包括其特点和空间效率。在顺序存储中,重点讲解了完全二叉树和满二叉树的存储方式,而在链表存储中,提到了非递归算法实现前序遍历的关键步骤。
摘要由CSDN通过智能技术生成

(二)二叉树的遍历操作

一、前序(根)遍历

若二叉树为空,则空操作返回;否则:

①访问根结点;

前序遍历结点的左子树;

前序遍历结点的右子树。

前序遍历序列:A B D G C E F

二、中序(根)遍历

若二叉树为空,则空操作返回;否则:

中序遍历结点的左子树;

②访问根结点;

中序遍历结点的右子树。

中序遍历序列:D G B A E C F

三、后序(根)遍历

若二叉树为空,则空操作返回;否则:

后序遍历结点的左子树;

后序遍历结点的右子树。

③访问根结点;

后序遍历序列:G D B E F C A

四、层序遍历

二叉树的层次遍历是指从二叉树的第一层(即根结点)开始,从上至下逐层遍历,在同一层中,则按从左到右的顺序对结点逐个访问。

层序遍历序列:A B C D E F G

(三)二叉树的存储结构及实现

顺序存储结构

二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且结点的存储位(下标)应能体现结点之间的逻辑关系——父子关系。

完全二叉树满二叉树中结点的序号可以唯一地反映出结点之间的逻辑关系

二叉树的顺序存储:

前序遍历:

void Preorder(int root, char data[]){
	if(data[root]!='\0'){
		cout<<data[root] ;			
		Preorder(2*root,data);
		Preorder(2*root+1,data);

	}
	return;
}

中序遍历:

void InOrder(int root, char data[]){
	if(data[root]!='\0'){
		InOrder(2*root,data);
		cout<<data[root] ;			
		 InOrder(2*root+1,data);	
	}
	return;
}

后序遍历:

void PostOrder(int root, char data[]){
	if(data[root]!='\0'){
		 PostOrder(2*root,data);
		 PostOrder(2*root+1,data);
		cout<<data[root] ;			
	}
	return;
}

建树:

void create(char preorder[],char inorder[],int start_p, int end_p,int start_i,int end_i, char data[],int root){
	if(start_p>end_p)
		return ;
	else{
		int k;
		for(int i=start_i;i<=end_i;i++){
			if(inorder[i]==preorder[start_p]){
				k=i;
				break;
			}
		}
		data[root]=preorder[start_p];
		create(preorder,inorder,start_p+1,start_p+k-start_i,start_i,k-1,data, 2*root);
		create(preorder,inorder,start_p+k-start_i+1,end_p,k+1,end_i,data,2*root+1);
	}
	return ;
}

二叉树的顺序存储在一些特殊情况会造成空间浪费。(举例:斜树)

一般用二叉树的顺序存储结构来存储完全二叉树。

二叉链表

基本思想:令二叉树的每个结点对应一个链表结点,链表结点除了存放与二叉树结点有关的数据信息外,还要设置指示左右孩子的指针。

结点结构:

其中,data:数据域,存放该结点的数据信息;

            lchild左指针域,存放指向左孩子的指针;

            rchild右指针域,存放指向右孩子的指针。

template <class T>
struct BiNode
{
    T data;
    BiNode<T> *lchild, *rchild;
};

具有n个结点的二叉链表有n+1个空指针。

二叉链表存储结构的类声明

template <class T>
class BiTree
{    
  public:
       BiTree(); 
        ~BiTree( );            
        void PreOrder(){PreOrder(root);} 
        void InOrder() {InOrder(root);} 
        void PostOrder() {PostOrder(root);} 
        void LevelOrder(){LeverOrder(root)};
  private:
        BiNode<T> *root; 
        BiNode<T> * Creat( ); 
        void Release(BiNode<T> *root);
        void PreOrder(BiNode<T> *root); 
        void InOrder(BiNode<T> *root); 
        void PostOrder(BiNode<T> *root); 
        void LevelOrder(BiNode<T> *root);
 };

前序遍历——递归算法

template   <class T>
void   BiTree::PreOrder(BiNode<T> *root) 
{
        if (root ==NULL)  return;     
        else {
            cout<<root->data;         
            PreOrder(root->lchild);    
            PreOrder(root->rchild);    
        }
 }

前序遍历——非递归算法

二叉树前序遍历的非递归算法的关键

在前序遍历过某结点的整个左子树后,如何找到该结点的右子树的根指针。

解决办法:在访问完该结点后,将该结点的指针保存在中,以便以后能通过它找到该结点的右子树。

思想:

遇到一个结点,就访问该结点,并把此结点推入栈中,然后遍历它的左子树;

遍历完它的左子树后,从栈顶托出这个结点,并按照它的右链接指示的地址再去遍历该结点的右子树结构。

伪代码:

1.s初始化(空栈);

2.循环直到root为空且栈s为空

 2.1 root不空时循环

  2.1.1 输出root->data;

     2.1.2 将指针root的值保存到栈中;

     2.1.3 继续遍历root的左子树(root=root->lchild

 2.2 如果栈s不空,则

  2.2.1 将栈顶元素弹出至rootroot=s.pop());

  2.2.2 准备遍历root的右子树(root=root->rchild)

template <class T>
void BiTree::PreOrder(BiNode<T> *root) {
  SeqStack<BiNode<T> *>  s;
     while (root!=NULL | | !s.empty()) {
         while (root!= NULL)  {
             cout<<root->data;
             s.push(root);
             root=root->lchild;  
         }
         if (!s.empty()) { 
             root=s.pop();
             root=root->rchild;  
         }
     }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值