一道二叉排序題,之前想有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之間,所用內存比前兩個方法的代碼要多。