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 }

  然后这是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 }

  以上两者都参考了书上的代码模板,想简单一点的话可以直接用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 }

  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 }

  实质上,这题也可以不用树来做,读入所有字符串并排序后,通过 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 }

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

时间: 2024-10-27 17:01:03

POJ 2418 各种二叉排序树的相关文章

[字典树] poj 2418 Hardwood Species

题目链接: http://poj.org/problem?id=2418 Hardwood Species Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 17511   Accepted: 6949 Description Hardwoods are the botanical group of trees that have broad leaves, produce a fruit or nut, and gene

POJ - 2418 代码

使用Trie树完成.比STL map 快很多. 输出时DFS,用一个字符数组记录当前字符串. 走到是字符串的结点就输出. 代码如下. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <cstdlib> using namespace std; const int MaxL =

poj 2418 Hardwood Species (trie树)

poj   2418   Hardwood Species http://poj.org/problem?id=2418 trie树+dfs 题意: 给你多个单词,问每个单词出现的频率. 方法:通过字典树,将所有单词放入树中,通过dfs遍历(题目要求按ASSIC码顺序输出单词及其频率),dfs可满足 注意:单词中不一定只出现26个英文字母,ASSIC码表共有256个字符 1 #include <stdio.h> 2 #include <string.h> 3 #include &l

POJ 2418 Hardwood Species(字典树)

题目链接:POJ 2418 Hardwood Species [题意]给出一大串树的名字,可能有重复,然后按字典序输出名字和百分比. [思路]我已开始偷懒用了map来做,这道题给的时间是10s,用map的8s也还是水过了,真是神奇啊,后来还是写了一下字典树,700ms+就过了,效率提升显著啊.这里要注意的是建字典树的ChildSize是256,题目输入不只有字母,还有一些其它字符. 下面贴上代码,先是map的: 1 /* 2 ** POJ 2418 Hardwood Species 3 ** C

POJ 2418 Hardwood Species(STL中map的应用)

题目地址:POJ 2418 通过这个题查了大量资料..知道了很多以前不知道的东西.... 在代码中注释说明吧. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue&

POJ 2418 Hardwood Species Trie解法

计算一个字符串数组中有多少个重复字符串出现. 如果直接使用map容器,那么这条题就很简单了,一下就AC了,因为map已经处理好一切了: 不过时间超过1532ms,有点慢. 如下: int main() { map<string, int> msi; int total = 0; char treeName[40]; while (gets(treeName)) { msi[treeName]++; total++; } for (map<string, int>::iterator

poj 2418 Hardwood Species (trie 树)

链接:poj 2418 题意:给定一些树的种类名,求每种树所占的百分比,并按字典序输出 分析:实质就是统计每种树的数量n,和所有树的数量m, 百分比就为 n*100./m 由于数据达到一百万,直接用数组查找肯定超时, 可以用trie树,空间换取时间 注:这题树的品种名除了包括大写字母,小写字母和空格外,还有其他字符, 所以要注意trie树的子结点的个数 #include<cstdio> #include<cstdlib> #include<cstring> #inclu

poj 2418 Hardwood Species(二叉排序树)

Hardwood Species Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 19428 Accepted: 7658 http://poj.org/problem?id=2418 Description Hardwoods are the botanical group of trees that have broad leaves, produce a fruit or nut, and generally go d

poj 2418 Hardwood Species

原题链接:http://poj.org/problem?id=2418 简单题.. 平衡树,写了个模板..动态分配内存确实很慢... 1 #include<algorithm> 2 #include<iostream> 3 #include<string> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cstdio> 7 using std::string; 8 template