PAT A1020.(改编)给定二叉树的先序和中序遍历序列,求层序遍历序列

(此题在原题PAT A1020的基础上进行了适当的改编,原题请点击此链接:PAT A1020. Tree Traversals

问题

给出一棵二叉树的先序遍历序列和中序遍历序列,求这颗二叉树的层序遍历序列(假设这棵二叉树的每一个结点数值均不相同)。

思路

如果要用先序遍历的方法来遍历一棵二叉树,那么总是先访问根结点,再访问左子树和右子树,因此根结点一定位于先序遍历序列的第一位,只要给定先序遍历序列,我们就能直接找到根结点。但是,如果只给出先序遍历序列,那么我们仅仅能够确定根结点,左右子树是没办法区分开的。要唯一确定一棵二叉树,还需要给定中序遍历序列。
对于中序遍历来说,总是先访问左子树,再访问根结点,最后访问右子树。因此,在二叉树的每一个结点数值均不同的情况下,只要遍历中序遍历序列,找到与先序遍历序列的第一位(即根结点)数值相同的结点,就可以确定该结点为根结点,进而中序遍历序列中区分出左子树和右子树。

代码

(买一送一,顺便附上后序遍历)

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

const int maxn = 10000;

//声明node结构
struct node
{
    int data;      //结点数据
    node* ltree;   //结点的左子树根结点的指针
    node* rtree;   //结点的右子树根结点的指针
};

//分别为先序遍历序列、中序遍历序列和后序遍历序列
int pre[maxn], mid[maxn], pos[maxn];        

/*通过先序序列和中序序列构建二叉树,并返回根节点地址。
 各参数分别为:
 先序序列第一个元素的索引、先序序列最后一个元素的索引、
 中序序列第一个元素的索引、中序序列最后一个元素的索引、
*/
node* create1(int pre_l, int pre_r, int mid_l, int mid_r)
{
	//先序序列长度不大于0时,直接返回
    if(pre_l > pre_r)
        return NULL;   
    //动态申请一个新的结点,并赋值为先序序列的第一个元素,作为当前根节点
    node* root = new node;
    root->data = pre[pre_l];
    //遍历中序序列的索引
    int k;
    //找到根节点时,跳出循环,k就是根节点在中序序列中的索引
    for(k = mid_l; k <= mid_r; k++)
    {
        if(mid[k] == root->data)
            break;
    }
    //左子树的长度
    int num_l = k - mid_l;
    //递归创建当前根节点的左子树
    root->ltree = create1(pre_l + 1, pre_l + num_l, mid_l, k - 1);
    //递归创建当前根节点的右子树
    root->rtree = create1(pre_l + num_l + 1, pre_r, k + 1, mid_r);
    //返回当前根节点的地址
    return root;
}

/*
//通过后序序列和中序序列构建二叉树,并返回根节点地址
node* create2(int pos_l, int pos_r, int mid_l, int mid_r)
{
    if(pos_l > pos_r)
    {
        return NULL;
    }
    node* root = new node;
    root->data = pos[pos_r];
    int k;
    for(k = mid_l; k <= mid_r; k++ )
    {
        if(mid[k] == root->data)
            break;
    }
    int num_l = k - mid_l;
    int num_r = mid_r - k;
    root->ltree = create2( pos_l, pos_l + num_l - 1, mid_l, k - 1 );
    root->rtree = create2(pos_l + num_l, pos_r - 1, k + 1, mid_r );
    return root;
}
*/


int n, num = 0;    //通过num控制结尾不输出空格

//层序遍历,采用广度优先探索的方法
void level_traversal(node* root)
{
	//声明存放结点地址的队列
    queue<node*> q;
    //先把根节点送进队列,可以保证第一次判断不为空
    q.push(root); 
    while(!q.empty())
    {
    	//暂存队列首元素
        node* tmp_node = q.front();
        //输出队列首元素的值
        cout<<tmp_node->data;
        num++;
        if(num < n)
            cout<<" ";
        //队列首元素读取完之后要弹出队列
        q.pop();
        //如果左子树的根节点不为空,则将左子树的根节点插入队列
        if(tmp_node -> ltree != NULL)
            q.push(tmp_node->ltree);
        //如果右子树的根节点不为空,则将右子树的根节点插入队列
        if(tmp_node -> rtree != NULL)
            q.push(tmp_node->rtree);
    }
}

int main()
{
	//输入树的结点个数
    cout<<"Input the number of nodes:";
    cin>>n;

	//输入先序遍历序列
    cout<<"Input the preorder:";
    for(int i = 0; i < n; i++)
    {
        cin>>pre[i];
    }
    
    /*
	//输入后序遍历序列
    cout<<"Input the postorder:";
    for(int i = 0; i < n; i++)
    {
        cin>>pos[i];
    }
	*/
	
	//输入中序遍历序列
    cout<<"Input the inorder:";
    for(int i = 0; i < n; i++)
    {
        cin>>mid[i];
    }

    node* root1 = create1(0, n - 1, 0, n - 1);
    //输出层序遍历序列
    cout<<"Level order:";
    level_traversal(root1);

//    node* root2 = create2(0, n - 1, 0, n - 1);
//    BFS(root2);

    return 0;
}
运行结果

假设有如一颗二叉树如下图所示:
在这里插入图片描述
输入该树的前序遍历序列和中序遍历序列,输出层序遍历序列结果如下:
在这里插入图片描述
程序运行结果正确。

发布了13 篇原创文章 · 获赞 43 · 访问量 2767

猜你喜欢

转载自blog.csdn.net/qq_42554780/article/details/104343185