pku 2418 (二叉排序樹)

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

發佈了12 篇原創文章 · 獲贊 5 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章