【PAT】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;
}
运行结果

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

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
1. 创建二叉树二叉树是一种树形结构,其中每个节点最多有两个子节点,我们可以通过递归的方式来创建一个二叉树。具体步骤如下: 首先,我们需要定义二叉树节点的结构体: ``` struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; ``` 然后,我们可以通过递归方式创建二叉树,示例代码如下: ``` TreeNode* createTree() { int val; cin >> val; // 输入节点的 if (val == -1) { // 如果为-1,表示该节点为空 return NULL; } TreeNode* root = new TreeNode(val); root->left = createTree(); // 递归创建左子树 root->right = createTree(); // 递归创建右子树 return root; } ``` 2. 先序遍历二叉树先序遍历是指先访问节点本身,再遍历其左子树和右子树。示例代码如下: ``` void preorderTraversal(TreeNode* root) { if (root == NULL) { return; } cout << root->val << " "; // 访问节点本身 preorderTraversal(root->left); // 遍历左子树 preorderTraversal(root->right); // 遍历右子树 } ``` 3. 中序遍历二叉树1: 中序遍历是指先遍历左子树,再访问节点本身,最后遍历右子树。示例代码如下: ``` void inorderTraversal1(TreeNode* root) { if (root == NULL) { return; } inorderTraversal1(root->left); // 遍历左子树 cout << root->val << " "; // 访问节点本身 inorderTraversal1(root->right); // 遍历右子树 } ``` 4. 中序遍历二叉树2: 与中序遍历1不同,这里给出一种非递归的中序遍历方法,需要使用到栈。示例代码如下: ``` void inorderTraversal2(TreeNode* root) { stack<TreeNode*> st; TreeNode* p = root; while (p != NULL || !st.empty()) { while (p != NULL) { st.push(p); p = p->left; } p = st.top(); st.pop(); cout << p->val << " "; p = p->right; } } ``` 5. 后序遍历二叉树: 后序遍历是指先遍历左子树,再遍历右子树,最后访问节点本身。示例代码如下: ``` void postorderTraversal(TreeNode* root) { if (root == NULL) { return; } postorderTraversal(root->left); // 遍历左子树 postorderTraversal(root->right); // 遍历右子树 cout << root->val << " "; // 访问节点本身 } ``` 6. 层序遍历二叉树层序遍历是指按照从上到下、从左到右的顺序遍历每个节点。需要使用到队列。示例代码如下: ``` void levelOrderTraversal(TreeNode* root) { if (root == NULL) { return; } queue<TreeNode*> q; q.push(root); while (!q.empty()) { TreeNode* node = q.front(); q.pop(); cout << node->val << " "; if (node->left != NULL) { q.push(node->left); } if (node->right != NULL) { q.push(node->right); } } } ``` 7. 二叉树的深度: 二叉树的深度是指从根节点到最远叶子节点的最长路径上的节点数。可以使用递归方式解。示例代码如下: ``` int maxDepth(TreeNode* root) { if (root == NULL) { return 0; } int leftDepth = maxDepth(root->left); int rightDepth = maxDepth(root->right); return max(leftDepth, rightDepth) + 1; } ``` 8. 退出
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Juicy B

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值