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