pku 2418 (二叉排序树)

来源:互联网 发布:热血江湖武勋阶段数据 编辑:程序博客网 时间:2024/06/07 19:04

一道二叉排序题,之前想有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 10003using 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 100typedef 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之间,所用内存比前两个方法的代码要多。