pku 2418 (二叉排序树)

一道二叉排序题,之前想有map或hash做,感觉比较复杂,在网上参考别人的方法,改有二叉排序树作。更方便。

code:

#include<stdio.h>
#include<string.h>

typedef struct binode
{
 char name[50];
 int count;
 struct binode *left,*right;
}Point;
Point node[10005],*root;
int k=0,num=0;
void Insert(char str[50])
{
 int j;
    if(root==NULL)
 {
  strcpy(node[num].name,str);
  node[num].count=1;
  node[num].left=0;
  node[num].right=0;
  root=node+0;
  num++;
  return ;
 }
 j=strcmp(root->name,str);
 if(j==0){root->count++;root=node;}
 else if(j<0)
 {     
     if(root->right==NULL)
     {
      root->right=node+num;
      root=NULL;
     }
     else root=root->right;
     Insert(str);
 }
 else
 {
     if(root->left==NULL)
     {
      root->left=node+num;
      root=NULL;
     }
     else root=root->left;
     Insert(str);
 }
    return ; 
}
int dfs(Point *p)
{
 if(p==NULL)return 0;
 dfs(p->left);
 printf("%s %.4lf/n",p->name,double(100.0)*p->count/k);
 dfs(p->right);
 p->count=0;
 p=NULL;
 return 1;
}
int main()
{
 char str[50];
 k=0;root=0;
 while(gets(str))
 {
   Insert(str);
   k++;
 }
 root=node;
 dfs(root);
 num=0;
 return 0;
}

一下贴的是网上其他方法,可以参考一下:

POJ 2418 Hardwood Species

2009年7月5日 creke 发表评论 阅读评论

本题在网上各个OJ很泛滥。分别是:POJ 2418、ZOJ 1899、天津大学OJ 1388、湖大OJ 10233、福建师范大学OJ 1601。

老子开始写的代码,在POJ和ZOJ,还有天津大学OJ都以2-3S的时间过了。就是湖大的OJ老是TLE。

然后我上网搜其它代码,用链表生成二叉查找树。结果湖大OJ神奇地0ms的AC。其它OJ均有差不多1s时间AC。

难道是偶的技术不行?

方法一:用map<string,int>映射

我又发现了另外一人用STL写的代码,在除湖大OJ外的其它OJ运行时是用链表写的2倍。很划算了。

#include<iostream>
#include<map>
#include<string>
using namespace std; string str;
map<string,int> mp;
map<string,int>::iterator iter,ed;
int main()
{
    int n=0;
    while(getline(cin,str))
    {
        mp[str]++;
        ++n;
    }
    iter = mp.begin();
    ed = mp.end();

    while(iter!=ed)
    {
        cout<<iter->first;
        printf(" %.4lf/n",100.000000*(iter->second)/(double)n);
        ++iter;
    }

    return 0;
}

以上这个版本的在湖大OJ运行,居然0msAC。下面是我写的。我写的代码在其它各大OJ上和以上版本AC时间相仿,兼容ZOJ,但在该死的湖大OJ却TLE……真是欲哭无泪。谁告诉我两份代码有什么质的区别?

感谢intheway指出错误,我在第二个getline()中加入了判断是否结束,就在湖大OJ上0msAC了(湖大OJ数据真弱)。

#include <iostream>
#include <string>
#include <map>

#define C 32
#define S 10003

using namespace std;

map <string,int> mymap;
map <string,int>::iterator it;
long total;
int counter=0;

int main()
{
    int i;
    long j,k;
    string name;
    double per;

    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);

    while(getline(cin,name,'/n'))
    {
        //初始化 
        total=0;
        mymap.clear();

        while(name!="")
        {
            mymap[name]++;//可以直接使用first的类型作为数组的ID哦! 
            total++;
            if(!getline(cin,name,'/n')) break;//这里也要判断是否输入结束
        }

        if(counter==0)
        {
            counter=1;
        }
        else
        {
            printf("/n");
        }
        for(it=mymap.begin();it!=mymap.end();it++)//是的,first元素的排列都是顺序的哦! 
        {
            name=it->first;
            j=it->second;
            per=(double)j/total*100;
            cout <<name;
            printf(" %.4lf/n",per);
        }
    }

    return 0;
}

以上是第一种方法:用map<string,int>将字符串映射为一个整数,这个整数记录该字符串出现的次数。

方法二:将字符串Hash为一个整数,就可以有对应关系了

据说,Hash的优劣顺序为:BKDRHash, APHash, DJBHash, JSHash, RSHash, SDBMHash, PJWHash, ELFHash。应该是从速度区分吧。因为BKDRHash最快(据说也最好背),ELFHash最准确(冲突率最低)。

#include <iostream>
#include <string>
#include <queue>

#define C 32
#define S 100030
//Hash起码要是原来的10倍或以上,有条件者最好到1000倍。这样课大大减低hash冲突率 
//BKDRHash最快,ELFHash最准确! 

using namespace std;

int sp;
long total;
long snum[S];
priority_queue <string,vector<string>,greater<string> > q;
int counter=0;

unsigned int BKDRHash(char *str) { // BKDR Hash Function 

     unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. 

     unsigned int hash = 0; 

     while (*str) { 

         hash = hash * seed + (*str++); 

     } 

     return (hash & 0x7FFFFFFF); 

} 

int main()
{
    int i;
    long j,k;
    string name;
    char ch[C];
    double per;

    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);

    while(getline(cin,name,'/n'))
    {
        //初始化 
        sp=0;
        total=0;
        for(i=0;i<S;i++)
        {
            snum[i]=0;
        }

        while(name!="")
        {
            strcpy(ch,name.c_str());//string转char
            k=BKDRHash(ch)%S;
            if(snum[k]==0)//没找到 
            {
                sp++;
                q.push(name);
                snum[k]++;
            }
            else
            {
                snum[k]++;
            }

            total++;

            if(!getline(cin,name,'/n')) break;//这里也要判断是否输入结束
        }

        if(counter==0)
        {
            counter=1;
        }
        else
        {
            printf("/n");
        }
        for(i=0;i<sp;i++)
        {
            name=q.top();
            q.pop();
            strcpy(ch,name.c_str());//string转char
            k=BKDRHash(ch)%S;
            j=snum[k];
            per=(double)j/total*100;
            printf("%s %.4lf/n",ch,per);
        }
    }

    return 0;
}

老子这份代码在除了湖大OJ外都AC了。哼!

同上,感谢intheway指出错误,我在第二个getline()中加入了判断是否结束,就在湖大OJ上0msAC了(湖大OJ数据真弱)

方法三:二叉搜索树(也称二叉排序树)

//From POJ 所用时间最少 
#include<stdio.h>
#include<malloc.h>
#define KIDS 128
#define NAMELONG 100

typedef struct node
{
    char abc;
    int num;
    struct node * pnode[KIDS];
}node;

void inwoods(char s[NAMELONG],node * root);
void outwoods(char pri[NAMELONG],int height,node * root,const int sum);
void destroyWoods(node * root);

int main()
{
    int i,sum=0;
    char s[NAMELONG];
    node * root;
    root=(node *)malloc(sizeof(node));
    root->abc='a';
    root->num=0;
    for(i=0;i<KIDS;i++)
        root->pnode[i]=NULL;
    while(gets(s))
    {
        inwoods(s,root);
        sum++;
    }
    outwoods(s,0,root,sum);
    destroyWoods(root);
    return 0;
}

void inwoods(char s[NAMELONG],node * root)
{
    int i,j;
    node * pmove=root;
    for(i=0;s[i]!='/0';i++)
    {
        if(pmove->pnode[s[i]]==NULL)
        {
            pmove->pnode[s[i]]=(node *)malloc(sizeof(node));
            pmove=pmove->pnode[s[i]];
            for(j=0;j<KIDS;j++)
                pmove->pnode[j]=NULL;
            pmove->abc=s[i];
            pmove->num=0;
        }
        else
            pmove=pmove->pnode[s[i]];
    }
    pmove->num=pmove->num+1;
}
void outwoods(char pri[NAMELONG],int height,node * root,const int sum)
{
    int i,j=0;
    if(root!=NULL)
    {
        if(height!=0)
        {
            pri[height-1]=root->abc;
            if(root->num!=0)
            {
                pri[height]='/0';
                while(pri[j]!='/0')
                {
                    printf("%c",pri[j]);
                    j++;
                }
                printf(" %.4f/n",((double)root->num/sum)*100);
            }
        }
        for(i=0;i<KIDS;i++)
            outwoods(pri,height+1,root->pnode[i],sum);
    }
}
void destroyWoods(node * root)
{
    int i;
    if(root!=NULL)
    {
        for(i=0;i<KIDS;i++)
            destroyWoods(root->pnode[i]);
        free(root);
    }
}

以上代码在湖大OJ以0ms,16k内存光荣AC。其它OJ的AC时间一般在几百ms之间,所用内存比前两个方法的代码要多。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值