《算法笔记》第9章 提高篇(2)---数据结构专题 9.2 二叉树的遍历

这篇博客详细介绍了二叉树的四种遍历方式:先序遍历、中序遍历、后序遍历和层序遍历。在讲解过程中,重点阐述了中序遍历的性质、后序遍历的实现和序列性质,以及如何根据先序和中序遍历序列重建二叉树。还特别提到了在创建二叉树时避免段错误的注意事项。
摘要由CSDN通过智能技术生成

在这里插入图片描述

9.2.1 先序遍历:

在这里插入图片描述

void preorder(node *root)
{
    if(root==NULL)   //到达空树,递归边界
        return ;
    cout << root->data;   //读出root结点的数据,相当于访问根结点
    preorder(root->lchild);   //访问左子树
    preorder(root->rchild);    //访问右子树
}

在这里插入图片描述

9.2.2 中序遍历:

在这里插入图片描述

void preorder(node *root)
{
    if(root==NULL)   //到达空树,递归边界
        return ;
    preorder(root->lchild);   //访问左子树
    cout << root->data;   //相当于访问根结点
    preorder(root->rchild);    //访问右子树
}

在这里插入图片描述

2.中序遍历的性质:

在这里插入图片描述

9.2.3 后序遍历:

1.后序遍历的实现:

在这里插入图片描述

void preorder(node *root)
{
    if(root==NULL)   //到达空树,递归边界
        return ;
    preorder(root->lchild);   //访问左子树
    preorder(root->rchild);    //访问右子树
    cout << root->data;   //相当于访问根结点
}

在这里插入图片描述

2.后序遍历序列的性质:

在这里插入图片描述

9.2.4 层序遍历:

在这里插入图片描述

void LayerOrder(node *root)
{
    queue<node*> q;   //注意队列存放的是地址
    q.push(root);       //将根结点入队
    while(!q.empty())
    {
        node *top;
        top=q.front();   //取出队首元素
        q.pop();
        cout << top.data;
        if(top->lchild!=NULL)   //如果左孩子不为空,则将左孩子放到队列中
            q.push(top->lchild);
        if(top->rchild!=NULL)       //如果右孩子不为空,则将右孩子放到队列中 
            q.push(top->rchild);
    }
    return ;
}

在这里插入图片描述

统计每个结点所处的层次

在这里插入图片描述

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

在这里插入图片描述

//层序遍历法:
void LayerOrder(node *root)
{
    queue<node*> q;  //存放队列地址
    root->layer=1;    //root是一结构类型的指针,所以访问其中成员的话用->
    q.push(root);  //将根结点入队
    while(!q.empty())
    {
        node *now=q.front();   //取出队首元素
        q.pop();
        cout << now->data;     //访问队首元素
        if(now->lchild!=NULL)  //如果左子树不为空,则遍历左子树
        {
            now->lchild->layer=now->layer+1;   //左子树的层号为当前层号+1
            q.push(now->lchild);
        }
        if(now->rchild!=NULL)   //如果右子树非空
        {
            now->rchild->layer=now->layer+1;  //右子树层号为当前层号+1
            q.push(now->rchild);
        }
    }
}

给定一颗二叉树的先序遍历和中序遍历序列,重建这个二叉树:

在这里插入图片描述

给出下面一个具体的例子:

在这里插入图片描述

node *create(int preL, int preR, int inL, int inR)  //当前先序序列的区间为[preL,preR],中序序列的区间为[inL,inR]
{
    if(preL>preR)   //先序长度小于0时,则递归结束
        return NULL;
    node *root=new node;   //创建一个新的结点,用来存放当前二叉树的新结点
    root->data=pre[preL];    //新结点的数据域为根结点的数据域
    int k;
    for(k=inL; k<=inR; k++)
    {
        if(pre[preL]==in[k])   //在中序序列中找到先序序列中根结点的数值,就退出循环
        {
            break;
        }
    }
    int numLeft=k-inL;  //左子树的结点数为k-inL
    
    //左子树的先序区间是[preL+1,preL+numLeft],左子树的中序区间是[inL,k-1],返回左子树的根结点,赋值给root的左指针
    root->lchild=create(preL+1,preL+numLeft,inL,k-1);
    
    //右子树的先序区间是[preL+numLeft+1,preR],右子树的中序区间是[k+1,inR],返回右子树的根结点,赋值给root的右指针
    root->rchild=create(preL+numLeft+1,preR,k+1,inR);
    
    return root;  //返回结点地址
}

在这里插入图片描述

pat A1020

解题思路:

在这里插入图片描述

参考代码:

#include<iostream>
#include<queue>
using namespace std;

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

/*
    1.按照后序和中序找到二叉树
    2.按照层序输出

*/
int n,num=0;

const int maxn=31;

int houxu[maxn],zhongxu[maxn];

node *create(int PostL, int PostR, int inL, int inR)
{
    if(PostL>PostR)
        return NULL;
    node *root=new node;
    root->data=houxu[PostR];

    int k;
    for(k=inL; k<=inR; k++)
    {
        if(zhongxu[k]==houxu[PostR])
        {
            break;
        }
    }
    int numl=k-inL;
    root->lchild=create(PostL,PostL+numl-1,inL,k-1);
    root->rchild=create(PostL+numl,PostR-1,k+1,inR);
    return root;
}


void layer(node *root)
{
    queue<node*> q;
    q.push(root);
    while(!q.empty())
    {
        node *top=q.front();
        q.pop();
        //num表示当前的个数,先输入一个数字,然后num++,如果num不超过n,则输出一个空格,当num为最后一个数字时,就不用再输入空格了
        cout << top->data;
        num++;
        if(num<n)
            cout << " ";
        //注意不能是if-else语句,本身的含义是分别判断左右子树是否为空,若为空,则不加入队列中,否则加入到队列中
        if(top->lchild!=NULL)
            q.push(top->lchild);
        if(top->rchild!=NULL)
            q.push(top->rchild);
    }
}


int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
        cin >> houxu[i];
    for(int i=0; i<n; i++)
        cin >> zhongxu[i];
    node *root;
    root=create(0,n-1,0,n-1);
    layer(root);
    return 0;
}

注意事项:

在create函数中,如果最后没有返回root,则会出现段错误,因为函数不结束,就会溢出

9.2.5二叉树的静态实现:

在这里插入图片描述

struct node
{
    typename data;   //数据域
    int lchild;      //左子树
    int rchild;     //右子树
}Node[maxn];     //结点数组,maxn为结点上限个数
//查找,root为根结点在数组中的下标
void search(int root, int x, int newdata)
{
    if(root=-1)   //用-1来代替NULL
        return ;    //空树,死胡同(递归边界)
    if(Node[root].data==x)   //找到数据域为x的结点,把它修改成newdata
        Node[root].data=newdata;
    search(Node[root].lchild, x, newdata);   //往左子树搜索x
    search(Node[root].rchild, x, newdata);   //往右子树搜索x
}

//插入,root为根结点在数组中的下标
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,x);   //往右子树搜索
    }
}

//二叉树的建立,函数返回根结点root的下标
int Create(int data[], int n)
{
    int root=-1;    //新建根结点,将root值设为-1
    for(int i=0; i<n; i++)
    {
        insert(root,data[i]);      //将data[0]~data[n-1]插入二叉树中  
    }
    return root;     //返回二叉树根结点下标
}

//关于二叉树的先序遍历,中序遍历,后序遍历,层序遍历也做相应的转换

//先序遍历
void preorder(int root)
{
    if(root==-1)
        return ;   //到达空树,递归边界
    //访问根结点root,将数据域,例如将其数据域输出
    printf("%d\n",Node[root].data);    
    //访问左子树
    preorder(Node[root].lchild);
    //访问右子树
    preorder(Node[root].rchild);
}

//中序遍历
void inorder(int root)
{
    if(root==-1)
        return ;   //到达空树,递归边界
    //访问左子树
    inorder(Node[root].lchild); 
    printf("%d\n",Node[root].data);   //输出数字   
    //访问右子树
    inorder(Node[root].rchild);
}

//后序遍历
void postorder(int root)
{
    if(root=-1)
        return ;
    printf("%d\n",Node[root].data);     //输出 
    postorder(Node[root].lchild);
    postorder(Node[root].rchild);
}

//层序遍历
void LayerOrder(int root)
{
    queue<int> q;   //此处队列里存放结点下标
    q.push(root);    //将根结点地址入队
    while(!q.empty())
    {
        int now=q.front();   //取出队首元素
        q.pop();      //弹出    
        printf("%d ", Node[now].data);        //访问队首元素
        if(Node[now].lchild!=-1)         //左子树非空
            q.push(Node[now].lchild);   //将左子树压入队列
        if(Node[now].rchild!=-1)        //右子树非空
            q.push(Node[now].rchild);       //将右子树压入队列
    }
}

类似于图中走迷宫,只要遇到岔路口就继续深入下去,一直到遍历完所有的岔路口,不碰到死胡同不回头

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值