POJ 1785:Binary Search Heap Construction ← 笛卡尔树的构造及中序遍历

【题目来源】
http://poj.org/problem?id=1785

【题目描述】
Read the statement of problem G for the definitions concerning trees. In the following we define the basic terminology of heaps. A heap is a tree whose internal nodes have each assigned a priority (a number) such that the priority of each internal node is less than the priority of its parent. As a consequence, the root has the greatest priority in the tree, which is one of the reasons why heaps can be used for the implementation of priority queues and for sorting. 

A binary tree in which each internal node has both a label and a priority, and which is both a binary search tree with respect to the labels and a heap with respect to the priorities, is called a treap. Your task is, given a set of label-priority-pairs, with unique labels and unique priorities, to construct a treap containing this data. 

【输入格式】
The input contains several test cases. Every test case starts with an integer n. You may assume that 1<=n<=50000. Then follow n pairs of strings and numbers l1/p1,...,ln/pn denoting the label and priority of each node. The strings are non-empty and composed of lower-case letters, and the numbers are non-negative integers. The last test case is followed by a zero.

【输出格式】
For each test case output on a single line a treap that contains the specified nodes. A treap is printed as (< left sub-treap >< label >/< priority >< right sub-treap >). The sub-treaps are printed recursively, and omitted if leafs.

【输入样例】
7 a/7 b/6 c/5 d/4 e/3 f/2 g/1
7 a/1 b/2 c/3 d/4 e/5 f/6 g/7
7 a/3 b/6 c/4 d/7 e/2 f/5 g/1
0

【输出样例】
(a/7(b/6(c/5(d/4(e/3(f/2(g/1)))))))
(((((((a/1)b/2)c/3)d/4)e/5)f/6)g/7)
(((a/3)b/6(c/4))d/7((e/2)f/5(g/1)))

【算法分析】
● 笛卡尔树
(1)笛卡尔树是由一系列不同数字构成的二叉树。
(2)笛卡尔树的结点有两个属性:键值
val、优先级 pri。其中,键值 val 预设,优先级 pri 随机或预设。笛卡尔树各个结点的键值 val 满足的性质(即根结点的键值 val 比它的左右子树中的结点的 val 值都大或都小),各个结点的优先级 pri 满足二叉搜索树(BST)的性质(即根结点的优先级 pri 比它的左子树中的结点的 pri 值都大,比它的右子树中的结点的 pri 值都小)。
(3)笛卡尔树可由数列构造,在
区间最值查询区间 topK 查询(range top k queries)等问题上有广泛应用。
(4)笛卡尔树结点键值
val 的中序遍历序列为构建其的原始序列。最小堆笛卡尔树表示满足小根堆性质的笛卡尔树。

● scanf 的高阶用法:
scanf("%[a-z]",ch);
语句 scanf("%[a-z]",ch); 表示只读入小写字母入字符串。包含任何非小写字母的字符串,将不能读入。
例如,运行下面代码,输入 abc,将输出 abc;输入 abcA,将无输出。

#include <bits/stdc++.h>
using namespace std;

int main() {
    char ch[100];
    scanf("%[a-z]",ch); //read only lowercase letters into string

    printf("%s\n",ch);

    return 0;
}

strcmp(a,b) 函数的用法
若 len(a)>len(b),则返回1。
若 len(a)==len(b),则返回0。
若 len(a)<len(b),则返回-1。

strcmp(a,b) 函数的用法代码一:

#include <bits/stdc++.h>
using namespace std;

int main() {
    char s1[]="abcdefg";
    char s2[]="abcdefg";
    char s3[]="abcde";
    
    printf("%d\n",strcmp(s1,s2)); //0
    printf("%d\n",strcmp(s1,s3)); //1
    printf("%d\n",strcmp(s3,s1)); //-1
    
    return 0;
}

strcmp(a,b) 函数的用法代码二:

#include <bits/stdc++.h>
using namespace std;

int main() {
    const char* s1="abcdefg";
    const char* s2="abcdefg";
    const char* s3="abcde";
    
    printf("%d\n",strcmp(s1,s2)); //0
    printf("%d\n",strcmp(s1,s3)); //1
    printf("%d\n",strcmp(s3,s1)); //-1
    
    return 0;
}


【算法代码】
注意:POJ 不支持万能头文件。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <stack>
using namespace std;

const int maxn=50005;
int lson[maxn<<1];
int rson[maxn<<1];
int n;

struct Node {
    char ch[100];
    int pri;
    int id;
} a[maxn<<1],ans[maxn<<1];

int up(Node x,Node y) {
    return strcmp(x.ch,y.ch)<0;
}

void buildCartesianTree() {
    stack<Node> ST; //Monotone stack
    for(int i=1; i<=n; i++) {
        Node u=a[i];
        Node t;
        int flag=0;
        while(!ST.empty() && ST.top().pri<u.pri) {
            t=ST.top();
            ST.pop();
            flag=1;
        }
        if(flag) lson[u.id]=t.id;
        if(!ST.empty()) rson[ST.top().id]=u.id;
        else rson[0]=u.id;

        ST.push(u);
    }
}

void dfs(int cur) {
    if(cur) printf("(");
    if(lson[cur]) dfs(lson[cur]);
    if(cur) printf("%s/%d",ans[cur].ch,ans[cur].pri);
    if(rson[cur]) dfs(rson[cur]);
    if(cur) printf(")");
}

int main() {
    while(scanf("%d",&n) && n) {
        for(int i=1; i<=n; i++) {
            scanf(" %[a-z]/%d",a[i].ch,&a[i].pri);
            strcpy(ans[i].ch,a[i].ch);
            ans[i].pri=a[i].pri;
            ans[i].id=a[i].id=i;
        }

        sort(a+1,a+1+n,up);
        buildCartesianTree();
        dfs(0);
        cout<<endl;

        memset(lson,0,sizeof(lson));
        memset(rson,0,sizeof(rson));
    }
    return 0;
}

/*
in:
7 a/7 b/6 c/5 d/4 e/3 f/2 g/1
7 a/1 b/2 c/3 d/4 e/5 f/6 g/7
7 a/3 b/6 c/4 d/7 e/2 f/5 g/1
0

out:
(a/7(b/6(c/5(d/4(e/3(f/2(g/1)))))))
(((((((a/1)b/2)c/3)d/4)e/5)f/6)g/7)
(((a/3)b/6(c/4))d/7((e/2)f/5(g/1)))
*/





【参考文献】
https://blog.csdn.net/2301_76618602/article/details/133135992
https://blog.csdn.net/hnjzsyjyj/article/details/138328588
https://blog.csdn.net/qq_33437973/article/details/97619793
https://www.cnblogs.com/rainydays/archive/2011/06/15/2081266.html





 

  • 24
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,这是一个关于二叉树遍历的问题。具体来说,给定二叉树的前序遍历和中序遍历,需要求出二叉树的后序遍历。 以下是一个Java实现的例子: ```java import java.util.Scanner; class Node { char value; Node left; Node right; public Node(char value) { this.value = value; } } public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int t = scanner.nextInt(); while (t-- > 0) { int n = scanner.nextInt(); String preOrder = scanner.next(); String inOrder = scanner.next(); Node root = buildTree(preOrder, inOrder); postOrder(root); System.out.println(); } scanner.close(); } private static Node buildTree(String preOrder, String inOrder) { if (preOrder.length() == 0) { return null; } char rootValue = preOrder.charAt(0); int rootIndex = inOrder.indexOf(rootValue); Node root = new Node(rootValue); root.left = buildTree(preOrder.substring(1, rootIndex + 1), inOrder.substring(0, rootIndex)); root.right = buildTree(preOrder.substring(rootIndex + 1), inOrder.substring(rootIndex + 1)); return root; } private static void postOrder(Node root) { if (root == null) { return; } postOrder(root.left); postOrder(root.right); System.out.print(root.value); } } ``` 这段代码首先读取输入的测试用例数量t,然后依次读取每个测试用例的节点数量n、前序遍历和中序遍历的字符串。接下来,通过递归构建二叉树,并使用后序遍历输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值