POJ 2418 各种二叉排序树

  题意很明确,统计各个字符串所占总串数的百分比,暴力的话肯定超时,看了书上的题解后发现这题主要是用二叉排序树来做,下面附上n种树的代码。

  简单的二叉排序树,不作任何优化(C语言版的):

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h> 
 4 
 5 typedef struct node{
 6     char name[52];
 7     struct node *lchild, *rchild;
 8     int count;
 9 }node;
10 
11 node *root= NULL;
12 int n = 0;
13 
14 void insert(node **root, char *s){        //恶心的二级指针,以后还是用指针引用来替代吧 
15     if(*root==NULL)    {
16         node *p = (node*)malloc(sizeof(node));
17         strcpy(p->name,s);
18         p->lchild = p->rchild = NULL;
19         p->count = 1;
20         *root = p;        //切记这个不能漏了!! 
21     }
22     else {
23         int cmp= strcmp(s,((*root)->name));
24         if(cmp==0)    ((*root)->count)++;
25         else if(cmp<0)    insert(&((*root)->lchild),s);
26         else    insert(&((*root)->rchild),s);
27     }
28 }
29 
30 void midOrder(node *root){
31     if(root!=NULL){
32         midOrder(root->lchild);
33         printf("%s %.4f\n",root->name,((double)(root->count)/(double)n)*100);
34         midOrder(root->rchild);
35     }
36 }
37 
38 int main(){
39     char s[52];
40     while(gets(s)){
41         insert(&root,s);
42         ++n;
43     }
44     midOrder(root);
45     return 0;
46 }
View Code

  然后这是AVL(平衡二叉树),目前我只会插入的平衡,删除还不会,代码量还挺多的:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 struct AVL
  8 {
  9     char name[32];
 10     int count;
 11     AVL *left, *right;
 12     int height;
 13 };
 14 
 15 int n = 0;
 16 
 17 int Height(AVL *p)  {   return p== NULL? -1: p->height;  }
 18 
 19 AVL* LLRotate(AVL *p)
 20 {
 21     AVL *p2= p->left;
 22     p->left= p2->right;
 23     p2->right= p;
 24     p->height= max(Height(p->left), Height(p->right))+1;
 25     p2->height= max(Height(p->left), p->height)+1;
 26     return p2;
 27 }
 28 
 29 AVL* RRRotate(AVL *p)
 30 {
 31     AVL *p2= p->right;
 32     p->right= p2->left;
 33     p2->left= p;
 34     p->height= max(Height(p->left), Height(p->right))+1;
 35     p2->height= max(p->height, Height(p2->right))+1;
 36     return p2;
 37 }
 38 
 39 AVL* LRRotate(AVL *p)
 40 {
 41     p->left= RRRotate(p->left);
 42     return LLRotate(p);
 43 }
 44 
 45 AVL* RLRotate(AVL *p)
 46 {
 47     p->right= LLRotate(p->right);
 48     return RRRotate(p);
 49 }
 50 
 51 AVL* Insert(const char *s, AVL *p)
 52 {
 53     if(p==NULL){
 54         p= (AVL*)malloc(sizeof(AVL));
 55         strcpy(p->name, s);
 56         p->left= p->right= NULL;
 57         p->height= 0;
 58         p->count= 1;
 59     }
 60     else {
 61         int cmp= strcmp(s,p->name);
 62         if(cmp==0)  ++(p->count);
 63         else if(cmp<0){
 64             p->left= Insert(s,p->left);
 65             if(Height(p->left) - Height(p->right) == 2){
 66                 if(strcmp(s,p->left->name)<0)
 67                     p= LLRotate(p);
 68                 else    p= LRRotate(p);
 69             }
 70         }
 71         else if(cmp>0){
 72             p->right= Insert(s,p->right);
 73             if(Height(p->right) - Height(p->left) == 2){
 74                 if(strcmp(s,p->right->name)>0)
 75                     p= RRRotate(p);
 76                 else    p= RLRotate(p);
 77             }
 78         }
 79     }
 80     p->height= max(Height(p->left), Height(p->right))+1;
 81     return p;
 82 }
 83 
 84 void midOrder(AVL* p)
 85 {
 86     if(p){
 87         midOrder(p->left);
 88         printf("%s %.4f\n",p->name,double(p->count)/n*100);
 89         midOrder(p->right);
 90     }
 91 }
 92 
 93 int main()
 94 {
 95     AVL *root= NULL;
 96     char s[32];
 97     while(gets(s)){
 98         root= Insert(s,root);
 99         ++n;
100     }
101     midOrder(root);
102     return 0;
103 }
View Code

  以上两者都参考了书上的代码模板,想简单一点的话可以直接用STL中封装的很好的 map(红黑树):

 1 #include<cstdio>
 2 #include<map>
 3 #include<iterator>
 4 #include<string>
 5 #include<iostream>
 6 using namespace std;
 7 
 8 int main()
 9 {
10     int n =0;
11     string s;
12     map<string,int> tree;
13     while(getline(cin,s)){        //直接用cin的话空格会读不进去
14         ++tree[s];
15         ++n;
16     }
17     map<string,int>::iterator it;
18     for(it=tree.begin(); it!=tree.end(); ++it){
19     //    cout<<it->first;
20         printf("%s %.4f\n",it->first.c_str(), it->second*100.0/n);
21     }
22 }
View Code

  Treap树堆,通过随机确定的优先级来平衡二叉排序树,参考了刘汝佳大白书上的模板,旋转处的小技巧确实很巧妙:(如果单纯针对本题的话 remove 和 find 函数都可以不要,代码比AVL短一些)

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<ctime>
  4 #include<cstring>
  5 #include<algorithm>
  6 using namespace std;
  7 const int maxn= 32;
  8 
  9 struct node
 10 {
 11     node *ch[2];    //左右子树
 12     int r;      //优先级
 13     int s;      //结点总数
 14     char name[maxn];    //结点名称
 15     int num;        //结点出现次数
 16     node(char s2[])
 17     {
 18         strcpy(name,s2);
 19         num= 1;
 20         ch[0]= ch[1]= NULL;
 21         r= rand();
 22         s= 1;
 23     }
 24     bool operator <(const node &n2) const {  return r < n2.r;  }
 25     int cmp(char s2[]) const
 26     {
 27         int d= strcmp(name,s2);
 28         if(!d)  return -1;
 29         return  d<0? 0:1;
 30     }
 31     void maintain()
 32     {
 33         s= 1;
 34         if(ch[0]!=NULL)  s+= ch[0]->s;
 35         if(ch[1]!=NULL)  s+= ch[1]->s;
 36     }
 37 };
 38 
 39 node *treap= NULL;
 40 int n= 0;
 41 
 42 void rotate(node* &p, int d)
 43 {
 44     node* k= p->ch[d^1];
 45     p->ch[d^1]= k->ch[d];
 46     k->ch[d]= p;
 47     p->maintain();
 48     k->maintain();
 49     p= k;
 50 }
 51 
 52 void insert(node* &p, char s2[])
 53 {
 54     if(p==NULL)  p= new node(s2);
 55     else {
 56         int d= strcmp(s2,p->name);
 57         if(!d)  p->num++;
 58         else {
 59             d= d<0? 0:1;
 60             insert(p->ch[d],s2);
 61             if(p->ch[d]->r > p->r)  rotate(p,d^1);
 62         }
 63     }
 64     p->maintain();
 65 }
 66 
 67 void remove(node* &p, char s2[])
 68 {
 69     if(p==NULL){
 70         puts("该结点不存在,无法删除...");
 71         return ;
 72     }
 73     int d= p->cmp(s2);
 74     if(d==-1){
 75         node *u= p;
 76         if(p->ch[0]==NULL)  p= p->ch[1];
 77         else if(p->ch[1]==NULL)  p= p->ch[0];
 78         else {
 79             int d2= (p->ch[0]->r > p->ch[1]->r ? 1: 0);
 80             rotate(p,d2);
 81             remove(p->ch[d2],s2);
 82         }
 83         delete u;
 84     }
 85     else    remove(p->ch[d],s2);
 86     if(p!=NULL)   p->maintain();
 87 }
 88 
 89 bool find(node* p, char s2[])
 90 {
 91     while(p){
 92         int d= p->cmp(s2);
 93         if(d==-1)   return 1;
 94         else   p= p->ch[d];
 95     }
 96     return 0;
 97 }
 98 
 99 void midOrder(node *p)
100 {
101     if(p){
102         midOrder(p->ch[0]);
103         printf("%s %.4f\n",p->name,double(p->num)/n*100);
104         midOrder(p->ch[1]);
105     }
106 }
107 
108 int main()
109 {
110     char s[32];
111     srand(time(NULL));
112     while(gets(s)){
113         insert(treap,s);
114         ++n;
115     }
116     midOrder(treap);
117     return 0;
118 }
View Code

  实质上,这题也可以不用树来做,读入所有字符串并排序后,通过 lower_bound 和 upper_bound 函数的差值来依次求出每个字串的数量/百分比(这是从《挑战》书上学到的):

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<string>
 4 #include<algorithm>
 5 #include<iostream>
 6 #include<cstdlib>
 7 using namespace std;
 8 string str[1000006];
 9 
10 //这种方法可能相对会慢一点:2610ms,27640K,其余几种都是1000+ms
11 
12 int main()
13 {
14     int i= 0;
15     while(getline(cin,str[i++])) ;
16     sort(str,str+i);
17 
18     //因为最后的换行符也会读进去,所以ed要从1开始,而总数量是i-1而不是i
19     int st,ed= 1;
20     while(ed<i){
21         st= lower_bound(str+ed, str+i, str[ed]) - str;
22         ed= upper_bound(str+ed, str+i, str[ed]) - str;
23         printf("%s %.4f\n",str[st].c_str(), double(ed-st)/(i-1)*100);
24     }
25     return 0;
26 }
View Code

  这两天稍微看了看数据结构,感觉还是挺费脑子的,各种变式的二叉排序树,很容易混淆或者记不住,看来要加深理解才能熟练运用。

posted @ 2015-02-10 16:57  Newdawn_ALM  阅读(187)  评论(0编辑  收藏  举报