POJ 1785 Binary Search Heap Construction(裸笛卡尔树的构造)

笛卡尔树:

  每个节点有2个关键字key、value。从key的角度看,这是一颗二叉搜索树,每个节点的左子树的key都比它小,右子树都比它大;从value的角度看,这是一个堆。

题意:以字符串为关键字key,数字为关键字value,构造一个二叉搜索大堆,最后按要求中序遍历 笛卡尔树的构造。

 

建立笛卡尔树的O(n)的算法:

  从别人博客里拷贝过来的,这里给出链接:http://hi.baidu.com/yy17yy/item/cd4edcf963944f6a3d148553

  首先按key关键字进行排序,这样建树的时候从左下角往右下角建。根据定义可知,每个数组的末尾节点必是位于树的最右路上且不可能有右孩子。 在建立树的过程中每次加入一个元素A[X],则该节点一定位于此时的树的最右路上且无右孩子。所以只要沿着A[X-1]节点向上走, 找到比A[X]大的第一个节点A[K],则A[X]是A[K]的右孩子,且A[K]原来的右孩子此时将成为A[X]的左孩子。 若找不到A[K]则此时的树的根将作为A[X]的左孩子,A[X]将成为树的新的根节点。

  可以模拟一个虚根,其priority设为无穷,这样最后构造出来的树即为虚根的右子树,方便编写程序。

 

我原来排序时,是自己写了比较器,传给sort方法,969MS。后来在Node结构体中重载运算符<,625MS。

代码中scanf的用法,详见:http://blog.csdn.net/wesweeky/article/details/6439777

 

#include <iostream>
#include <cstdio>
#include <string.h>
#include <queue>
#include <algorithm>
#include <string>

using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1<<16;
int fa[maxn];  //存储父节点的编号
int son[maxn][2]; //son[i][0]存储i的左儿子编号,son[i][1]存储i的右儿子编号
int n;

struct Node{
    char s[110];  //字符串
    int p;  //优先级
    bool operator<(const Node tmp)const{
        return strcmp(s,tmp.s)<0;
    }
}node[maxn];
/*
bool cmp(const Node tmp1,const Node tmp2){
    if(strcmp(tmp1.s,tmp2.s)<0)
        return 1;
    else
        return 0;
}
*/
void treap(int i){
    int tmp=i-1;
    //直到找到一个tmp,使得tmp的优先级大于i
    while(node[tmp].p<node[i].p){
        tmp=fa[tmp];
    }
    //tmp的原先的右儿子即为i的左儿子,i成为tmp的右儿子
    son[i][0]=son[tmp][1];
    son[tmp][1]=i;
    fa[i]=tmp;
}
//中序遍历
void dfs(int i){
    if(i==0)
        return;
    printf("(");
    //递归左儿子
    dfs(son[i][0]);
    printf("%s/%d",node[i].s,node[i].p);
    //递归右儿子
    dfs(son[i][1]);
    printf(")");
}
int main()
{
    //这里为方便起见,设立了一个优先级很大的虚根,之后建的树为虚根的右子树
    node[0].p=INF;
    while(scanf("%d",&n),n){
        memset(son,0,sizeof(son));
        memset(fa,-1,sizeof(fa));
        for(int i=1;i<=n;i++){
            //[a-z]表示读取的字符串由a-z中的字符组成,其余的字符为定界符
            scanf(" %[a-z]/%d",node[i].s,&node[i].p);
        }
        //sort(node+1,node+n+1,cmp);
        sort(node+1,node+n+1);
        for(int i=1;i<=n;i++){
            treap(i);
        }
        //从虚根的右儿子开始dfs
        dfs(son[0][1]);
        printf("\n");
    }
    return 0;
}

 

 

posted @ 2013-10-06 21:13  辰曦~文若  阅读(629)  评论(0)    收藏  举报