課設題目:哈希表實現電話號碼查找系統

  1. // MyHashTable.cpp : 定義控制檯應用程序的入口點。  
  2. ////設計哈希表實現電話號碼查詢系統  
  3. //說明:一是從文件old.txt中讀取的數據自己在程序運行前建立,  
  4. //      二是由系統隨機生成數據,在程序運行由隨機數產生器生成,並且將產生的記錄保存到 new.txt文件。  
  5.   
  6. //存在的問題:使用隨機產生的文件,在顯示時出現亂碼  
  7.   
  8.   
  9. #include "stdafx.h"  
  10. #include<fstream>//文件流  
  11. #include<iostream>  
  12. #include <string>  
  13. using namespace std;  
  14.   
  15. const int D[] = {3,5,8,11,13,14,19,21};//預定再隨機數  
  16. const int HASH_MAXSIZE = 50;//哈希表長度  
  17.   
  18. //記錄信息類型  
  19. class DataInfo  
  20. {  
  21. public:  
  22.     DataInfo();//默認構造函數  
  23.     friend ostream& operator<<(ostream& out, const DataInfo& dataInfo); //重載輸出操作符  
  24.     //friend class HashTable;  
  25.   
  26. //private:  
  27.     string name;//姓名  
  28.     string phone;//電話號碼  
  29.     string address;//地址   
  30.     char sign;//衝突的標誌位,'1'表示衝突,'0'表示無衝突  
  31. };  
  32.   
  33. DataInfo::DataInfo():name(""), phone(""), address(""), sign('0')  
  34. {  
  35.   
  36. }  
  37.   
  38. ostream& operator<<(ostream& out, const DataInfo& dataInfo) //重載輸出操作符  
  39. {  
  40.     cout << "姓名:" << dataInfo.name << "   電話:" << dataInfo.phone   
  41.          << "    地址:" << dataInfo.address << endl;  
  42.     return out;  
  43. }  
  44.   
  45. //存放記錄的哈希表類型  
  46. class HashTable  
  47. {  
  48. public:  
  49.     HashTable();//默認構造函數  
  50.     ~HashTable();//析構函數  
  51.     int Random(int key, int i);// 僞隨機數探測再散列法處理衝突  
  52.     void Hashname(DataInfo *dataInfo);//以名字爲關鍵字建立哈希表      
  53.     int Rehash(int key, string str);// 再哈希法處理衝突   注意處理衝突還有鏈地址法等  
  54.     void Hashphone(DataInfo *dataInfo);//以電話爲關鍵字建立哈希表         
  55.     void Hash(char *fname, int n);// 建立哈希表  
  56.     //fname 是數據儲存的文件的名稱,用於輸入數據,n是用戶選擇的查找方式    
  57.       
  58.     int Findname(string name);// 根據姓名查找哈希表中的記錄對應的關鍵碼  
  59.     int Findphone(string phone);// 根據電話查找哈希表中的記錄對應的關鍵碼  
  60.     void Outhash(int key);// 輸出哈希表中關鍵字碼對應的一條記錄  
  61.     void Outfile(string name, int key);// 在沒有找到時輸出未找到的記錄  
  62.     void Rafile();// 隨機生成文件,並將文件保存在 new.txt文檔中  
  63.     void WriteToOldTxt();//在運行前先寫入數據      
  64.   
  65. //private:  
  66.         DataInfo *value[HASH_MAXSIZE];  
  67.     int length;//哈希表長度  
  68. };  
  69.   
  70. HashTable::HashTable():length(0)//默認構造函數  
  71. {  
  72.     //memset(value, NULL, HASH_MAXSIZE*sizeof(DataInfo*));  
  73.     for (int i=0; i<HASH_MAXSIZE; i++)  
  74.     {  
  75.         value[i] = new DataInfo();  
  76.     }  
  77. }  
  78.   
  79. HashTable::~HashTable()//析構函數  
  80. {  
  81.     delete[] *value;  
  82. }  
  83.   
  84. void HashTable::WriteToOldTxt()  
  85. {  
  86.     ofstream openfile("old.txt");  
  87.     if (openfile.fail())  
  88.     {  
  89.         cout << "文件打開錯誤!" << endl;  
  90.         exit(1);  
  91.     }  
  92.   
  93.     string oldname;  
  94.         string oldphone;  
  95.     string oldaddress;  
  96.   
  97.     for (int i=0; i<30; i++)  
  98.     {  
  99.         cout << "請輸入第" << i+1 << "條記錄:" << endl;          
  100.         cin >> oldname ;  
  101.         cin >> oldphone;  
  102.         cin >> oldaddress;  
  103.         openfile << oldname << "  " << oldphone << "  " << oldaddress << "," << endl;  
  104.     }  
  105.     openfile.close();  
  106. }  
  107.   
  108.   
  109. int HashTable::Random(int key, int i)// 僞隨機數探測再散列法處理衝突  
  110. {//key是衝突時的哈希表關鍵碼,i是衝突的次數,N是哈希表長度  
  111.     //成功處理衝突返回新的關鍵碼,未進行衝突處理則返回-1  
  112.     int h;  
  113.     if(value[key]->sign == '1')//有衝突  
  114.     {  
  115.         h = (key + D[i]) % HASH_MAXSIZE;  
  116.         return h;  
  117.     }  
  118.     return -1;  
  119. }  
  120.   
  121. void HashTable::Hashname(DataInfo *dataInfo)//以名字爲關鍵字建立哈希表  
  122. {//利用除留取餘法建立以名字爲關鍵字建立的哈希函數,在發生衝突時調用Random函數處理衝突  
  123.     int i = 0;    
  124.     int key = 0;  
  125.   
  126.         for (int t=0; dataInfo->name[t]!='\0'; t++)     
  127.     {         
  128.         key = key + dataInfo->name[t];  
  129.     }  
  130.     key = key % 42;  
  131.     while(value[key]->sign == '1')//有衝突  
  132.     {  
  133.         key = Random(key, i++);//處理衝突  
  134.     }  
  135.     if(key == -1) exit(1);//無衝突  
  136.     length++;//當前數據個數加  
  137.     value[key]->name = dataInfo->name;  
  138.     value[key]->address = dataInfo->address;  
  139.     value[key]->phone = dataInfo->phone;  
  140.     value[key]->sign = '1';//表示該位置有值  
  141.     //cout << value[key]->name << "  " << value[key]->phone << "  "  << value[key]->address << endl;  
  142. }  
  143.   
  144. int HashTable::Rehash(int key, string str)// 再哈希法處理衝突  
  145. {//再哈希時使用的是摺疊法建立哈希函數      
  146.     int h;  
  147.     int num1 = (str[0] - '0') * 1000 + (str[1] - '0') * 100 + (str[2] - '0') * 10 + (str[3] - '0');  
  148.     int num2 = (str[4] - '0') * 1000 + (str[5] - '0') * 100 + (str[6] - '0') * 10 + (str[7] - '0');  
  149.     int num3 = (str[8] - '0') * 100  + (str[9] - '0') * 10  + (str[10] - '0');  
  150.     h = num1 + num2 + num3;  
  151.     h = (h + key) % HASH_MAXSIZE;  
  152.     return h;  
  153. }  
  154.   
  155. void HashTable::Hashphone(DataInfo *dataInfo)//以電話爲關鍵字建立哈希表  
  156. {//利用除留取餘法建立以電話爲關鍵字建立的哈希函數,在發生衝突時調用Rehash函數處理衝突  
  157.     int key = 0;      
  158.     int t;  
  159.       
  160.     for(t=0; dataInfo->phone[t] != '\0'; t++)  
  161.     {     
  162.         key = key + dataInfo->phone[t];  
  163.     }  
  164.     key = key % 42;  
  165.     while(value[key]->sign == '1')//有衝突  
  166.     {  
  167.         key = Rehash(key, dataInfo->phone);  
  168.     }  
  169.     length++;//當前數據個數加  
  170.     value[key]->name = dataInfo->name;  
  171.     value[key]->address = dataInfo->address;  
  172.     value[key]->phone = dataInfo->phone;     
  173.     value[key]->sign = '1';//表示該位置有值   
  174. }  
  175.   
  176. void HashTable::Outfile(string name, int key)//在沒有找到時輸出未找到的記錄  
  177. {  
  178.     ofstream fout;  
  179.     if((key == -1)||(value[key]->sign == '0'))//判斷哈希表中沒有記錄  
  180.     {  
  181.         fout.open("out.txt",ios::app);//打開文件  
  182.   
  183.         if(fout.fail())  
  184.         {  
  185.             cout << "文件打開失敗!" << endl;  
  186.             exit(1);  
  187.         }  
  188.         fout << name << endl;//將名字寫入文件,有個問題,每次寫入的時候總是將原來的內容替換了  
  189.         fout.close();  
  190.     }  
  191. }  
  192.   
  193. void HashTable::Outhash(int key)//輸出哈希表中關鍵字碼對應的記錄  
  194. {    
  195.     if((key==-1)||(value[key]->sign=='0'))  
  196.         cout << "沒有找到這條記錄!" << endl;  
  197.     else  
  198.     {         
  199.         for(unsigned int i=0; value[key]->name[i]!='\0'; i++)  
  200.         {  
  201.             cout << value[key]->name[i];             
  202.         }  
  203.   
  204.         for(unsigned int i=0; i<10; i++)  
  205.         {  
  206.             cout << " ";  
  207.         }  
  208.   
  209.         cout << value[key]->phone;  
  210.   
  211.         for(int i=0; i<10; i++)  
  212.         {  
  213.             cout << " ";  
  214.         }  
  215.   
  216.         cout << value[key]->address << endl;  
  217.     }  
  218. }  
  219.   
  220. void HashTable::Rafile()//隨機生成文件,並將文件保存在new.txt文檔中  
  221. {  
  222.     ofstream fout;  
  223.     fout.open("new.txt");//打開文件,等待寫入  
  224.     if(fout.fail())  
  225.     {  
  226.         cout << "文件打開失敗!" << endl;  
  227.         exit(1);  
  228.     }  
  229.     for(int j=0; j<30; j++)  
  230.     {         
  231.         string name = "";  
  232.         for(int i=0; i<20; i++)//隨機生成長個字的名字  
  233.         {  
  234.             name += rand() % 26 + 'a';//名字是由個字母組成             
  235.         }  
  236.         fout << name << "   ";//將名字寫入文件  
  237.   
  238.         string phone = "";  
  239.         for(int i=0; i<11; i++)//隨機生成長位的電話號碼  
  240.         {  
  241.             phone += rand() % 10 + '0';//電話號碼是純數字  
  242.         }  
  243.         fout << phone << "      ";//將電話號碼寫入文件  
  244.   
  245.         string address = "";  
  246.         for(int i=0; i<29; i++)//隨機生成長個字的名字  
  247.         {  
  248.             address += rand() % 26 + 'a';//地址是由個字母組成  
  249.         }  
  250.         address += ',';  
  251.         fout << address << endl;//將地址寫入文件  
  252.     }  
  253.     fout.close();  
  254. }  
  255.   
  256. void HashTable::Hash(char *fname, int n)//建立哈希表  
  257. //fname是數據儲存的文件的名稱,用於輸入數據,n是用戶選擇的查找方式  
  258. //函數輸入數據,並根據選擇調用Hashname或Hashphone函數進行哈希表的建立  
  259. {  
  260.     ifstream fin;         
  261.     int i;  
  262.     fin.open(fname);//讀文件流對象  
  263.     if(fin.fail())  
  264.     {  
  265.         cout << "文件打開失敗!" << endl;  
  266.         exit(1);  
  267.     }  
  268.     while(!fin.eof())//按行讀入數據  
  269.     {  
  270.         DataInfo *dataInfo = new DataInfo();  
  271.         char* str = new char[100];        
  272.         fin.getline(str, 100, '\n');//讀取一行數據  
  273.   
  274.         if(str[0] == '*')//判斷數據結束  
  275.         {  
  276.             break;  
  277.         }  
  278.   
  279.         i = 0;//記錄字符串數組的下標  
  280.         //a-z:97-122     A-Z:65-90      
  281.         //本程序的姓名和地址都使用小寫字母  
  282.         while((str[i] < 97) || (str[i] > 122))//讀入名字  
  283.         {  
  284.             i++;  
  285.         }  
  286.   
  287.         for(; str[i]!=' '; i++)  
  288.         {             
  289.             dataInfo->name += str[i];              
  290.         }  
  291.   
  292.         while(str[i] == ' ')  
  293.         {  
  294.             i++;  
  295.         }  
  296.   
  297.         for(int j=0; str[i]!=' '; j++,i++)//讀入電話號碼  
  298.         {             
  299.             dataInfo->phone += str[i];  
  300.         }  
  301.   
  302.         while(str[i] == ' ')  
  303.         {  
  304.             i++;  
  305.         }  
  306.   
  307.         for(int j=0; str[i]!=','; j++,i++)//讀入地址  
  308.         {             
  309.             dataInfo->address += str[i];  
  310.         }  
  311.   
  312.         if(n == 1)  
  313.         {             
  314.             Hashname(dataInfo);  
  315.         }  
  316.         else  
  317.         {             
  318.             Hashphone(dataInfo);//以電話爲關鍵字  
  319.         }  
  320.   
  321.         delete []str;  
  322.         delete dataInfo;  
  323.     }     
  324.     fin.close();  
  325. }  
  326.   
  327. int HashTable::Findname(string name)//根據姓名查找哈希表中的記錄對應的關鍵碼  
  328. {  
  329.     int i = 0;  
  330.     int j = 1;  
  331.     int t;  
  332.     int key = 0;  
  333.       
  334.     for(key=0, t=0; name[t] != '\0'; t++)  
  335.     {  
  336.         key = key + name[t];  
  337.     }  
  338.     key = key % 42;  
  339.     while((value[key]->sign == '1') && (value[key]->name != name))  
  340.     {    
  341.         key = Random(key, i++);  
  342.         j++;  
  343.         if(j >= length) return -1;  
  344.     }  
  345.     return key;  
  346. }  
  347.   
  348. int HashTable::Findphone(string phone)//根據電話查找哈希表中的記錄對應的關鍵碼  
  349. {    
  350.     int key = 0;  
  351.     int t;  
  352.       
  353.     for(t=0; phone[t] != '\0' ; t++)  
  354.         {  
  355.                 key = key + phone[t];  
  356.         }  
  357.     key = key % 42;  
  358.     int j = 1;  
  359.     while((value[key]->sign == '1') && (value[key]->phone != phone))  
  360.     {  
  361.         key = Rehash(key, phone);  
  362.         j++;  
  363.         if(j >= length)   
  364.                 {  
  365.                     return -1;  
  366.                 }  
  367.         }  
  368.     return key;  
  369. }  
  370.   
  371. void main()  
  372. {  
  373.     //WriteToOldTxt();    
  374.     int k;  
  375.     int ch;   
  376.     char *Fname;  
  377.     HashTable *ht = new HashTable;  
  378.     while(1)  
  379.     {  
  380.         system("cls");//cls命令清除屏幕上所有的文字  
  381.         cout << "歡迎使用本系統!" << endl << endl;  
  382.         cout << "請選擇數據" << endl;  
  383.         cout << "1.使用已有數據文件" << endl;  
  384.         cout << "2.隨機生成數據文件" << endl;  
  385.         cout << "0.結束" << endl;  
  386.         cout << "輸入相應序號選擇功能:";  
  387.         cin >> k;  
  388.         switch(k)  
  389.         {  
  390.         case 0:  
  391.             return;  
  392.         case 1:  
  393.             Fname = "old.txt";//從數據文件old.txt(自己現行建好)中讀入各項記錄  
  394.             break;  
  395.         case 2:  
  396.             ht->Rafile();  
  397.             Fname = "new.txt";//由系統隨機產生各記錄,並且把記錄保存到new.txt文件中  
  398.             break;  
  399.         default:  
  400.             cout << "輸入序號有誤,退出程序。" << endl;   
  401.             return;  
  402.         }  
  403.   
  404.         do  
  405.         {  
  406.             system("cls");  
  407.             cout << " 請選擇查找方式" << endl;  
  408.             cout << "1.通過姓名查找" << endl;  
  409.             cout << "2.通過電話查找" << endl;  
  410.             cout << "輸入相應序號選擇功能:";  
  411.             cin >> ch;  
  412.             if((ch != 1) && (ch != 2))  
  413.                 cout << "輸入序號有誤!" << endl;  
  414.         }while((ch != 1) && (ch != 2));  
  415.   
  416.         ht->Hash(Fname, ch);  
  417.         while(ch == 1)  
  418.         {  
  419.             int choice;  
  420.             cout << endl << "請選擇功能" << endl;  
  421.             cout << "1.輸入姓名查找數據" << endl;  
  422.             cout << "2.顯示哈希表" << endl;  
  423.             cout << "0.退出"<<endl;  
  424.             cout << "輸入相應序號選擇功能:";  
  425.             cin >> choice;  
  426.             switch(choice)  
  427.             {  
  428.             case 1:   
  429.                 {//注意此處應該加上大括號  
  430.                     int key1;                     
  431.                     string name;                      
  432.                     cout << "請輸入姓名:";  
  433.                     cin >> name;                    
  434.                     key1 = ht->Findname(name);  
  435.                     ht->Outfile(name, key1);  
  436.                     ht->Outhash(key1);     
  437.                 }  
  438.                 break;  
  439.   
  440.             case 2:   
  441.                 {  
  442.                     for(int i=0; i<HASH_MAXSIZE; i++)  
  443.                     {  
  444.                         if(ht->value[i]->sign!='0')  
  445.                         {  
  446.                             ht->Outhash(i);   
  447.                         }  
  448.                     }     
  449.                 }                             
  450.                 break;  
  451.   
  452.   
  453.             default:  
  454.                 cout << endl << "您的輸入有誤!" << endl;                  
  455.             }  
  456.   
  457.             if(choice == 0)   
  458.             {  
  459.                 return;  
  460.             }  
  461.         }  
  462.   
  463.         while(ch == 2)  
  464.         {  
  465.             int choice;  
  466.             cout << endl << "請選擇功能" << endl;  
  467.             cout << "1.輸入電話查找數據" << endl;  
  468.             cout << "2.顯示哈希表"<<endl;  
  469.             cout << "0.退出"<<endl;  
  470.             cout << "輸入相應序號選擇功能:";  
  471.             cin >> choice;  
  472.             switch(choice)  
  473.             {  
  474.             case 1:   
  475.                 {  
  476.                     int key2;                     
  477.                     string phone;                     
  478.                     cout << "請輸入11位的電話號碼:";  
  479.                       
  480.                     do  
  481.                     {  
  482.                         cin >> phone;                       
  483.                         if(phone.length() != 11)                      
  484.                         {  
  485.                             cout << "電話號碼應爲11位!\n請重新輸入:";  
  486.                         }  
  487.                               
  488.                     }while(phone.length() != 11);  
  489.                       
  490.                     key2 = ht->Findphone(phone);  
  491.                     ht->Outfile(phone, key2);  
  492.                     ht->Outhash(key2);  
  493.                 }  
  494.                 break;  
  495.   
  496.             case 2:   
  497.                 {  
  498.                     for(int i=0; i<HASH_MAXSIZE; i++)  
  499.                     {  
  500.                         if(ht->value[i]->sign != '0')   
  501.                         {  
  502.                             ht->Outhash(i);   
  503.                         }  
  504.                     }  
  505.                 }                 
  506.                 break;  
  507.   
  508.             default:  
  509.                  cout << endl << "您的輸入有誤!" << endl;                  
  510.             }  
  511.   
  512.             if(choice == 0)   
  513.             {  
  514.                 return;  
  515.             }  
  516.         }  
  517.   
  518.         while((ch != 1) && (ch != 2))  
  519.         {  
  520.             cout << "您的輸入有誤!請輸入相應需要選擇功能:";  
  521.         }  
  522.     }  
  523.     system("pause");      
  524. }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章