ハッシュ・テーブルの例


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define Size 11
typedef struct{
 char name[30];
    char address[20];
 //float  num;
 char num[30];
 int c;//      
}record;
typedef struct{
 record data[Size];
 int count;
 int size;
}Hashtable;
void init(Hashtable &h)
{
 for(int i=0;i<Size;i++)
 {h.data[i].num[0]=0;
 h.data[i].c=0;}//!
 h.size=Size;
 h.count=0;
}
int exchange(char str[])
{
 int i,n,sum=0;
 n=strlen(str);
 for(i=0;i<n;i++)
  sum=sum+str[i]-'0';
 return sum;
}
int HashSearch1(Hashtable &h,char *str,int &p) //    
{
 int i,j,k=exchange(str);
 j=k%Size;
 if(strcmp(str,h.data[j].num)==0)
 {
  return j;
  h.data[j].c++;//!
 }//      ,        
 if(h.data[j].num[0]==0)
 {
  p=j;
  return 0;
 }
 else
 {
  h.data[j].c++;//!
  i=(j+1)%Size;// 1     
  while(h.data[i].num[0]!=0&&i!=j) 
  {   
   if(strcmp(str,h.data[i].num)==0)
   {
    h.data[j].c++;//!
    return i;
   }//    ,         
   i=(i+1)%Size;    //        
  }
  if (i==j)
   printf("  
"); else { p=i; h.data[j].c++;//! return 0;// } } } int HashSearch2(Hashtable &h,char *str,int &p) { int i,j,t=1,d=1; int k=exchange(str); j=k%Size; if(strcmp(str,h.data[j].num)==0) { h.data[j].c++;//! return j; } // , if(h.data[j].num[0]==0) { p=j; return 0; } else { i=(j+d)%Size;// 1 while(h.data[i].num[0]!=0&&i!=j) { if(strcmp(str,h.data[i].num)==0) { h.data[j].c++;//! return i; } if(t>0) t=-1*d*d; else { d=d+1; t=-1*d*d ; } i=(j+t+Size)%Size; // while(i<0) { h.data[j].c++;//! i=(i+Size)%Size; } } if (i==j) printf("
"); else { p=i; h.data[j].c++;//! return 0;// } } } void disp(Hashtable h) { printf(" :
"); for(int i=0;i<Size;i++) { if(h.data[i].num[0]) printf("-.%7s s %s
",i,h.data[i].name,h.data[i].address,h.data[i].num); } } // int compasl(Hashtable h) { int sum=0; for(int i=0;i<Size;i++) sum+=h.data[i].c; return sum; } int menu() { int num; while(1) { system("cls"); printf("
--------- ( )---------
"); printf("
**********************************************
"); printf("
0. 1.
"); printf("
2. 1 3. 2
"); printf("
4. 1 5. 2
"); printf("
6. 1 ASL 7. 2 ASL
"); printf("
**********************************************
"); printf("
----------------------------------------------
"); printf("
(0--7):
"); scanf("%d",&num); if(num<0||num>7) printf(" , !
"); break; } return num; } void main() { Hashtable h1,h2; int i,j,n,a,m,flag=1; char num[30]; char name[30],address[50]; init(h1);init(h2); while(1) { j=menu(); switch(j){ case 0:printf("(@ @) , ! (^ ^)
"); exit(0); getch(); break; case 1: if(flag){ FILE *fp; if((fp=fopen("1234.txt","r+"))==NULL) { puts(" !"); exit(0); } fscanf(fp,"%d",&n); for(i=0;i<n;i++) { fscanf(fp,"%s%s%s",name,address,num); HashSearch1(h1,num,a); strcpy(h1.data[a].num,num); strcpy(h1.data[a].address,address); strcpy(h1.data[a].name,name); h1.count++; } puts("\t 1!"); disp(h1); fclose(fp); if((fp=fopen("1234.txt","r+"))==NULL) { puts(" "); exit(0); } fscanf(fp,"%d",&n); for(i=0;i<n;i++) { fscanf(fp,"%s%s%s",name,address,num); HashSearch2(h2,num,a); strcpy(h2.data[a].num,num); strcpy(h2.data[a].address,address); strcpy(h2.data[a].name,name); h2.count++; } puts("\t 2!"); disp(h2); fclose(fp); printf(" !
"); getch();} flag=0; break; case 2: printf(" 1:
"); printf(" :
"); scanf("%d",&n); for(i=0;i<n;i++) { printf(" %d 、 ( )
",i+1); scanf("%s%s%s",name,address,num); if(HashSearch1(h1,num,a)) { printf(" "); i--; } else { strcpy(h1.data[a].num,num); strcpy(h1.data[a].address,address); strcpy(h1.data[a].name,name); h1.count++; } } disp(h1); printf(" !
"); getch(); break; case 3:printf(" 2:
"); printf("
"); scanf("%d",&n); for(i=0;i<n;i++) { printf(" %d 、 ( )
",i+1); scanf("%s%s%s",name,address,num); if(HashSearch2(h2,num,a)) { printf(" "); i--; } else { strcpy(h2.data[a].num,num); strcpy(h2.data[a].address,address); strcpy(h2.data[a].name,name); h2.count++; } } disp(h2); printf(" !
"); getch(); break; case 4:disp(h1); printf(" 1 :
"); scanf("%s",num); printf("
"); if(m=HashSearch1(h1,num,a)) { printf(" :
"); printf(" 、 :
%s,%s,%s
",h1.data[m].name,h1.data[m].address,h1.data[m].num); } else printf(" , !
"); printf(" !
"); getch(); break; case 5:disp(h2); printf(" 2 :
"); scanf("%s",num); printf("
"); if(m=HashSearch2(h2,num,a)) { printf(" :
"); printf(" 、 :
%s,%s,%s
",h2.data[m].name,h2.data[m].address,h2.data[m].num); } else printf(" , !
"); printf(" !
"); getch(); break; case 6:printf(" 1 ASL :
"); printf("%d %d
",compasl(h1),h1.count); printf(" !
"); getch(); break; case 7:printf(" 2 ASL :
"); printf("%d %d
",compasl(h2),h2.count); printf(" !
"); getch(); break; } } }

以下は、カリキュラム設計のレポートです.
一、カリキュラム設計の目的と要求
    1. 目的:データ構造とアルゴリズムを応用して相応のプログラムを設計し、学生問題解決モジュールのフレームワーク設計と詳細設計、関連プログラムの実現とデバッグ能力を育成し、革新能力と実践能力の訓練を完成する.
    2. 要求:高級プログラムで言語Cコードを設計し、VC++開発プラットフォームでデバッグする.
二、設計本文
(一)カリキュラム設計テーマ
ハッシュテーブルを設計して電話番号照会システムを実現する
(二)需要分析
各記録には以下のデータ項目がある:電話番号、ユーザー名、住所;
(1)データ導入(ファイルから各レコードを読み出し、それぞれ電話番号をキーワードにハッシュテーブルを作成する);
(2)キーボードからレコードを読み取り、ハッシュテーブルに挿入する.
(3)所定の電話番号の記録を検索して表示する.
(4)電話番号記録をファイルに保存する.
(5)衝突を種々の異なるタイプで処理する方法を試み,平均ルックアップ長の変化を考察する.
分析:テーマは電話番号をキーワードとして表を作ることが要求されるため、電話番号の長さが異なることを考慮して、直接電話番号を表す文字列をキーワードにすれば、一定の面倒をもたらす可能性がある.したがって、電話番号を表す文字列を1つの関数で対応する数字に変換し、これらの数字の和をキーワードとして上記トラブルを解消することができる.
(三)概要設計
上記のプログラムの機能を実現するには、以下の抽象データ型を定義する必要があります.
     ADT hashtable {
データ・オブジェクト:ハッシュ・テーブルに格納された電話レコード.
データ関係:表中の隣接要素の間に前と後の関係がある.
基本操作:
            init(Hashtable &h)
操作結果:ハッシュテーブルを初期化しました.
        int exchange(char str[])
操作結果:ボールはキーワードを取ります;
        int HashSearch1(Hashtable &h,char *str,int &p)
操作結果:テーブル内でデータを線形に検出し、データの挿入位置を返す.
int HashSearch2(Hashtable &h,char *str,int &p)
操作結果:テーブル内でデータを二次的に検出し、データの挿入位置を返す.
void disp(Hashtable h)
操作結果:ハッシュテーブルに格納された電話記録を表示する.
}ADT hashtable
電話番号、ユーザー名、アドレスを含む各個人の情報を1つのレコードとして記録し、衝突の回数を記録するための整数変数もあり、ASLの計算を容易にし、ハッシュテーブルは記録配列、表現メモリ、容量から構成され、具体的なデータ型は以下の通りである.
typedef struct {
   char name[30];
    char address[20];
   char num[30];
 }record;
 
typedef struct{
   record data[Size];
   int count;
   int size;
}Hashtable;
   
キーワード処理---電話番号を表す文字列を1つの関数で対応する数字に変換し、その数字の和をキーワードとします.具体的な関数は次のとおりです.
 int exchange(char str[])
 {
   int i,n,sum=0;
   n=strlen(str);
   for(i=0;i       sum=sum+str[i]-'0';
   return sum;
 }
最後に,衝突をそれぞれ線形と二次プローブ法で処理する2つの方法でテーブルを構築した.
このプログラムのすべての関数リスト:
 void init(Hashtable &h);//ハッシュテーブルの初期化
 int exchange(char str[]);//キーワードを求める
 int HashSearch1(Hashtable &h,char *str,int &p);//せんけいプローブしょりコンフリクト
 int HashSearch2(Hashtable &h,char *str,int &p);//二次検出処理の競合
 void disp(Hashtable h);//ハッシュ表の表示
 int menu();//メインメニュー
 void main();//しゅかんすう
各関数間の呼び出し関係は次のとおりです.
 
メイン関数main()
      
 
 
 
メニュー関数menu()
 
 
 
 
 
 
 
 
 
 
 
 
線形プローブ衝突解決hashserch 1()
ユーザーの検索
考察ASL 1
二次プローブ衝突解決hashsearch 2()
ユーザーの検索
考察ASL
電話帳dispを表示()
 
(四)詳細設計
1)上記プログラムの機能を実現するためには、以下のデータ型を定義する必要がある.
   typedef struct{
   char name[30];
    char address[20];
   //float  num;
   char num[30];
   int c;//統計比較回数
 }record;//記録
 
 typedef struct{
   record data[Size];
   int count;
   int size;
 }Hashtable;//ハッシュ表
2)主な関数:
int exchange(char str[])/キーワード処理関数
 {
   int i,n,sum=0;
   n=strlen(str);
   for(i=0;i       sum=sum+str[i]-'0';
   return sum;
 }
int HashSearch 1(Hashtable&h,char*str,int&p)//リニアプローブ
 {
   int i,j,k=exchange(str);
   j=k%Size;
   if(strcmp(str,h.data[j].num)==0)
   {
       return j;
       h.data[j].c++;//!
}//衝突は発生せず、比較して検索に成功
   if(h.data[j].num[0]==0)
   {
       p=j;
       return 0;
   }
   else
   {
       h.data[j].c++;//!
       i=(j+1)%Size;//第1回衝突解決
       while(h.data[i].num[0]!=0&&i!=j) 
       {     
          if(strcmp(str,h.data[j].num)==0)
          {
              h.data[j].c++;//!
              return i;
}//競合が発生し、何回か比較して検索に成功
          i=(i+1)%Size;//位置を後ろに探る
       }
       if (i==j)
printf(「オーバーフロー」);
       else        
       {
          p=i;
          h.data[j].c++;//!
          return 0;//検索に失敗しました
       }
   }
}
 
int HashSearch 2(Hashtable&h,char*str,int&p)//二次プローブ
{
   int i,j,t=1,d=1;
   int k=exchange(str);
   j=k%Size;
   if(strcmp(str,h.data[j].num)==0)
   { 
       h.data[j].c++;//!
       return j;
}//競合が発生していないため、一度の検索を比較できました
   if(h.data[j].num[0]==0)
   {
       p=j;
       return 0;
   }
   else
   {
       i=(j+d)%Size;//第1回衝突解決
       while(h.data[i].num[0]!=0&&i!=j) 
       {  
           if(strcmp(str,h.data[j].num)==0)
          {
               h.data[j].c++;//!
               return i;
          }
          if(t>0)
              t=-1*d*d;
          else
          {
              d=d+1;
              t=-1*d*d ;
          }
          i=(j+t+Size)%Size;//新しい位置を探る
          while(i<0)
          {
              h.data[j].c++;//!
              i=(i+Size)%Size;             
          }
           if (i==j)
printf(「オーバーフロー」);
           else
          {
              p=i;
              h.data[j].c++;//!
              return 0;//検索が失敗した場合に挿入
          }
        }
    }
  }
(五)デバッグ分析
本実験の実行環境はVC++である.要求に応じて、事前にいくつかの記録を導入しなければならない.以下は本実験のテストデータである.
4
侯進斌北京6627584
王璐太原6650370
唐磊天津6626074
高启波太原6651805
メニューの指示に従って操作すればいいです.
 
(六)使用説明
プログラム名はhashtable.exe、実行環境はVC++です.メニューに詳細な操作プロンプトがあるので、上記のプロンプトに従って一歩一歩操作すればいいです.
(七)テストデータ
プログラムが実行されると、次のメニューが表示されます.
 
 
 
               
1を選択すると、次のウィンドウが表示され、既存のレコードが表示されます.
 
操作2を選択すると、電話帳1に記録を追加できます.以下のようにします.
 
操作3は、電話帳2に記録を追加し、以下のようにする.
 
次に、クエリー操作を行うこともできます.4を選択すると、電話帳1で探している人の情報をクエリーできます.
 
同様に、5を選択すると、電話帳2で対応するクエリーを行うこともできます.
 
電話帳1で検索する速度(専門用語:ASL)を比較したい場合は、操作6を選択します.
 
電話帳2の機能も同様に表示できます.
 
操作を終了するには、0を選択してシステムを終了します.
  
以上が本システムの主な機能です.
三、カリキュラム設計の総括或いは結論
1.完成した仕事
この実験のすべての要求:ハッシュ表の作成、2つの異なる方法で衝突を処理して、各種の衝突を処理する方法のASLを考察します;
2.未完了の作業
なし
3.必要な改善
衝突をより多く処理する方法を試みるべきだ.
いくつかのコードの効率は低く、改善が必要です.
四、参考文献
『データ構造』(C言語版)清華大学出版社厳蔚敏呉偉民編著