資料結構課程設計_排名估計
/* *本文僅供學習參考使用 **/
一、選題
1、所選題目
題目五:排名估計
2、選題內容
(1)問題描述
某次考試有n個選手參加,知情人洩露了若干組排序資訊,每組資訊包括兩個人的排中情況,如A>B A<B或者A-B.分別表示A在B之前,A在B之後,A和B排名相等。你的任務是儘量求出完整的排序表。
(2)設計要求
要求一:選手測試資料請自行構造,儲存在文字檔案中。
要求二:一個測試資料檔案可以有多個測試用例。
要求三:需要包含三種測試用例,一是資料不矛盾,但無法完整排
序:二是資料可以完整排序;三是資料有矛盾,如A>B、B>C、 C>A,無法排序。
要求四:選手姓名用逗號分隔,每個姓名可以很長;採用雜湊表索引選手。(可選)
相關資料結構和演算法:
並查集、圖、鄰接表、拓撲排序、雜湊表。
二、實現分析
1.題目分析與設計方案
針對題目要求,鑑於c++語言高效的執行速度及強大的標準模板庫STL,我們小組選用c++語言進行本次課程設計。
題目要求我們將按照題目要求所自行制定的測試資料存入文字檔案(TXT檔案)中,文字中有三類資料資訊:A>B(A排名在B之前),A<B(A排名在B之後),A-B(A與B排名相等),文字中每組資料儲存為一行。
整體的解答思路就是首先將資料從TXT文字讀入記憶體中,先使用並查集將相等的資料合併為一個集合,選擇一個節點為該集合的代表節點,後續對該集合中所有節點的操作都將轉移到代表節點上,集合中除代表節點外,其餘節點均不再參與後續的構圖等過程,只需在輸出結果時插入到代表節點的前面。然後構造雜湊表和有向圖,雜湊表採用資料項字串的ASCII碼相加然後對雜湊表的最大儲存空間取模,採用線性探測解決雜湊衝突。圖使用鄰接表儲存,圖中節點使用雜湊表作為索引。然後對有向圖進行拓撲排序,當圖有環的時候證明資料是矛盾的,就是出現了A>B, B>C,C>A的情況,這種情況構圖是有環的,拓撲排序完整與否可以判斷是否有環。當拓撲排序時同時有兩個節點入度為0就是無法排序的情況,也就是A>C, B>C,A和B的關係沒有給出所以無法確定A和B的關係,A和B就無法排序,排除這兩種情況,拓撲排序的結果就是最終排序答案
2.輸入輸出說明
輸入:
程式從工程檔案中直接讀取預置的TXT文字作為程式輸入,我們小組一共預置了三種測試資料,包括可以完整排序樣例1(無排名相等)、可以完整排序樣例2(有排名相等)、資料不矛盾但無法完整排序、資料有矛盾無法排序共四組測試樣例,測試樣例不可增加,但可以在四組樣例中修改測試資料。
輸出:
程式使用控制檯介面進行結果輸出,使用win32函式封裝了易操作、結果清晰的使用者互動介面,為了避免個別姓名過長或過短造成輸出的冗餘和獲得更加的直觀的程式結果,我們規定測試樣例中不同兩個姓名的首字母不能相同,並在輸出時用首字母代替姓名,程式輸出有三種結果,分別對應三種測試樣例:
(1) 可以排序:輸出完整的排序情況
(2) 資料不矛盾但無法排序:輸出資料在哪個節點之後出現了無法排序的情況
(3) 資料矛盾:輸出資料在哪個節點之後出現了矛盾
3.資料結構使用分析
程式中主要運用了:並查集、雜湊表、圖、佇列、線性表等資料結構。
並查集使用陣列(ufs[])表示,如果節點沒有相等節點,則ufs[i] = i, 即它的代表節點就是它本身,如圖2.1中,ufs[4] = 4。如果節點有相等節點,則所有相等節點組成一個集合,若a = b = c,a為其代表節點,則有ufs[c] = ufs[b] = ufs[a] = a, 如圖2.1中, 節點1 = 節點3 = 節點8, 節點1為其代表節點,則有ufs[8] = ufs[3] = ufs[1] = 1,這樣當我們索引節點8時,得到的是其代表節點:節點1,對節點8的所有操作都將在節點1進行。
圖2.1 並查集關係
雜湊表節點HashNode包含兩項屬性:節點儲存的姓名string name和當前節點的狀態enum EntryType Info, 狀態值是一個列舉型別:
1 enum EntryType { Legitimate, Empty, Deleted };
分別代表當前節點的狀態:已存放數值、空節點、節點已刪除雜湊表資料結構HashTable包含兩項屬性:已經存入的資料大小TableSize和雜湊節點陣列指標HashNode *Cells。
雜湊表提供了三個訪問介面,分別為:
1 int hash_func(string name);//雜湊函式,返回應插入下標,以姓名的ASCII碼總和作為雜湊索引 2 3 int hash_insert(HashTable& tab, string name); //雜湊表插入,採用線性探測,返回插入位置的下標 4 5 int hash_find(HashTable& tab, string name);//雜湊查詢,返回查詢元素下標
圖2.2 雜湊表結構
有向圖節點Tunode包含四項屬性:節點資料name、入度indegree、出度outdegree、節點狀態state,state是一個列舉型別:
1 enum State { Hang, Using, DataContra }; 2 3 /* 節點屬性裡增加的一個狀態:(掛起、使用中, 矛盾),當u v相等時,u代替v所有的操作, 4 5 |* v的狀態變為:掛起,不再加入圖中參與後面的圖演算法,在輸出結果時,插入到u的前面。 6 7 |* 矛盾代表資料在該節點出現無法完整排序的情況 8 9 */
以節點指標儲存有向圖資訊,vector陣列儲存圖鄰接表資訊,對有向圖節點的訪問使用雜湊表索引進行訪問。
1 Tunode* Ceils;//圖資訊,與鄰接連結串列下標一一對應 2 3 vector<int> adj[MAXN];//圖鄰接表
對有向圖提供了拓撲排序介面,拓撲排序返回返回值是一個列舉型別,為了能夠在後續將“掛起”的節點插入到結果中進行輸出,拓撲排序的結果儲存在連結串列RES中:
1 list<int> RES;//用於儲存拓撲排序結果 2 3 enum TopState { True, Contra, False };//拓撲排序返回的三種狀態,分別代表資料能排序、資料不矛盾但無法排序、資料矛盾 4 5 enum TopState TopSort();//拓撲排序
圖2.3 有向圖結構
3、演算法設計與分析
(1)演算法正確性分析
程式中主要使用了拓撲排序演算法,我們主要針對拓撲排序演算法進行分析
圖3.1 拓撲排序演算法
•初始化:進入拓撲排序後申請輔助空佇列q,選出入度為零的有效節點加入佇列,使用臨時變數count統計加入佇列中的節點數, flag標記資料狀態, cnt統計存入結果連結串列的資料數量,將第一個入度為零的節點加入佇列和結果連結串列中。
•保持:不斷彈出佇列的隊頂元素,加入到結果連結串列中,並將其鄰接節點加入到佇列中,在判斷鄰接節點時,會使用臨接節點的代表節點,如果資料集是正確的,一定會有且僅有一個節點加入到佇列中,如果是佇列中存在兩個以上元素,證明資料集存在無法排序的節點,將flag標記為Contra,標記有資料無法排序。
•終止:當佇列為空時,程式終止,根據存入結果連結串列的節點數量和flag的狀態判斷拓撲排序返回值,資料集按出隊順序排列即為資料集的拓撲排序結果,依次儲存在RES結果連結串列中,遍歷RES結果連結串列即為最終答案,因此演算法正確。
(2)複雜度分析
•時間複雜度:程式中各演算法時間複雜度如圖所示:
圖3.2 各函式時間複雜度
拓撲排序中e為有向圖中邊的數量,整體的時間複雜度為O(n ),若設計算機單次執行時間為1e-9s,此程式的效能趨勢圖如下:
圖3.3 理論效能趨勢圖
•空間複雜度:
拓撲排序演算法額外申請了一個佇列,空間複雜度為O(n)。
•不同資料結構的效能差異:
我們可以在程式中取消雜湊表索引而採用直接儲存姓名,這樣可以節省一定的空間,但是代價是每次使用姓名時都會在姓名陣列中查詢並返回所在位置,每次索引都將耗費O(n)的時間,得不償失。
一、實驗結果截圖及分析
1、實驗結果截圖
表 1選單選擇
四、實驗程式碼
1 #include <iostream> 2 #include <algorithm> 3 #include <fstream> 4 #include <string> 5 #include <vector> 6 #include <queue> 7 #include <list> 8 #include "Interface.h" 9 using namespace std; 10 11 const int MAXN = 100;//最大儲存空間 12 int ResCnt;//最終加入圖中參與圖演算法資料的數量 13 enum State { Hang, Using, DataContra }; 14 /* 節點屬性裡增加的一個狀態:(掛起、使用中, 矛盾),當u v相等時,u代替v所有的操作, 15 |* v的狀態變為:掛起,不再加入圖中參與後面的圖演算法,在輸出結果時,插入到u的前面。 16 |* 矛盾代表資料在該節點出現無法完整排序的情況 17 */ 18 struct Tunode { 19 string name;//節點資料 20 int indegree;//入度 21 int outdegree;//出度 22 enum State state; 23 }; 24 int ufs[MAXN];//並查集,當u v排名相等時,將u v作為一個集合,所有對v的操作轉移到對u進行操作,即使ufs[v] = u 25 Tunode* Ceils;//圖資訊,與鄰接連結串列下標一一對應 26 vector<int> adj[MAXN];//圖鄰接表 27 28 /*********************** TXT檔案讀取 ************************/ 29 vector<string> fileMsg;//用於儲存讀取的檔案資訊 30 void Read_File(string filename);//讀取檔案內容到fileMsg 31 32 /*********************** 拓撲排序 ************************/ 33 list<int> RES;//用於儲存拓撲排序結果 34 enum TopState { True, Contra, False };//拓撲排序返回的三種狀態,分別代表資料能排序、資料不矛盾但無法排序、資料矛盾 35 enum TopState TopSort();//拓撲排序 36 37 /*********************** 雜湊表 ************************/ 38 enum EntryType { Legitimate, Empty, Deleted };//用於雜湊索引的節點的狀態 已存、空、已刪除 39 struct HashNode {//雜湊表資料節點 40 string name; 41 enum EntryType Info;//用於雜湊索引的狀態值 42 }; 43 struct HashTable {//雜湊表 44 int TableSize = 0;//已經存入的資料大小 45 struct HashNode* Cells; /* 存放節點的陣列 */ 46 }; 47 int hash_func(string name);//雜湊函式,返回應插入下標,以姓名的ASCII碼總和作為雜湊索引 48 int hash_insert(HashTable& tab, string name); //雜湊表插入,採用線性探測,返回插入位置的下標 49 int hash_find(HashTable& tab, string name);//雜湊查詢,返回查詢元素下標 50 HashTable tab;//雜湊表 51 52 /*********************** 並查集 ************************ 53 |*ufs_find: 並查集路徑壓縮查詢,返回x所在集合的代表節點*/ 54 int ufs_find(int x) { 55 if (x == ufs[x]) 56 return x; 57 else { 58 ufs[x] = ufs_find(ufs[x]); //父節點設為根節點 59 return ufs[x];//返回父節點 60 } 61 } 62 inline void merge(int u, int v) {//並查集,合併,將 v 合併到 u, 簡單來說,即ufs[v] = u, 這樣在使用ufs[v]時,得到的是u 63 ufs[ufs_find(v)] = ufs_find(u); 64 } 65 66 /*********************** 過程封裝函式 ************************/ 67 void __Init__();//初始化全域性變數, 讀取TXT檔案 68 void Read_Msg_equal();//讀出排名相等的條目,進行並查集合並 69 void Read_Msg_unequal();//讀出大小條目,構造圖鄰接表 70 void PrintRes(enum TopState res);//根據拓撲排序的狀態返回值輸出結果 71 void __Free__();//釋放記憶體 72 73 int main() { 74 setTitle("排名估計");//設定控制檯標題 75 while (1) {//迴圈讀入,非法輸入退出 76 /*** 一、初始化全域性變數, 讀取TXT檔案 ***/ 77 __Init__(); 78 79 /*** 二、解析fileMsg,構圖 *** 80 |*解析讀出來的fileMsg,將姓名存入雜湊表便於索引,利用雜湊表的索引構建圖鄰接表 81 |*使用索引時,會判斷節點有沒有代表節點, 82 |* 1.先讀出排名相等的條目,進行並查集合並 */ 83 Read_Msg_equal(); 84 /** 2.讀出大小條目,構造圖鄰接表 */ 85 Read_Msg_unequal(); 86 87 /*** 三、對圖進行拓撲排序 ***/ 88 for (int i = 0; i < MAXN; i++) { 89 if (Ceils[i].name != "-1" && Ceils[i].state != Hang) {//統計有效資料數量 90 ResCnt++; 91 } 92 } 93 enum TopState res = TopSort();//拓撲排序,得到排序結果狀態返回值 94 95 /*** 四、輸出結果 ***/ 96 PrintRes(res);//根據拓撲排序的狀態返回值輸出結果 97 __Free__();//釋放記憶體 98 } 99 return 0; 100 } 101 void __Init__() {//初始化函式 102 system("cls");//清屏 103 mainFrame();//主要介面框架 104 ResCnt = 0; 105 tab.Cells = new HashNode[MAXN]; 106 Ceils = new Tunode[MAXN]; 107 for (int i = 0; i < MAXN; i++) { 108 ufs[i] = i;//並查集初始化,所有節點"各自為戰" 109 Ceils[i].state = Using; Ceils[i].name = "-1"; Ceils[i].indegree = 0; Ceils[i].outdegree = 0; 110 tab.Cells[i].Info = Empty; 111 } 112 string file[4] = { "可以完整排序樣例1(無排名相等).txt", "可以完整排序樣例2(有排名相等) .txt", 113 "資料不矛盾但無法完整排序.txt", "資料有矛盾無法排序.txt" }; 114 setPos(LEFTOTHER + 25, TOPOTHER + 7); 115 cout << "當前可選擇四個初始化樣例:"; 116 for (int i = 1; i <= 4; i++) { 117 setPos(LEFTOTHER + 25, TOPOTHER + 7 + i * 3); 118 cout << i << ". " << file[i - 1]; 119 } 120 string tip = "請選擇讀入的檔案:"; 121 setPos((WIDTH - tip.size()) / 2 + LEFTOTHER - 1, HIGHT + TOPOTHER - 2); 122 cout << tip; 123 124 int choise; 125 cin >> choise; 126 if (choise < 1 || choise > 4) { 127 system("cls");//清屏 128 tip = "非法輸入!程式退出"; 129 setPos((WIDTH - tip.size()) / 2 + LEFTOTHER, TOPOTHER + 10);//居中列印 130 cout << tip; 131 mainFrame(); 132 exit(-1); 133 } 134 Read_File(file[choise - 1]); 135 } 136 void Read_Msg_equal() {//讀出排名相等的條目,進行並查集合並 137 for (int i = 0; i < fileMsg.size(); i++) {//先讀出排名相等的條目,進行並查集合並 138 int pos; 139 if ((pos = fileMsg[i].find("-", 0)) != -1) {//資料集中a-b代表ab排名相等 140 /* 根據符號分割,將姓名分割出來儲存到臨時變數u v中 **/ 141 142 string u = fileMsg[i].substr(0, pos); 143 string v = fileMsg[i].substr(pos + 1, fileMsg[i].size()); 144 //查詢雜湊表中是否名字已經存在 145 int u_index = hash_find(tab, u);//u, v 在雜湊表中的索引 146 int v_index = hash_find(tab, v); 147 if (u_index == -1) {//姓名不存在,將姓名插入雜湊表,更新下標 148 u_index = hash_insert(tab, u); 149 Ceils[u_index].name = u; 150 151 } 152 if (v_index == -1) {//姓名不存在,將姓名插入雜湊表,更新下標 153 v_index = hash_insert(tab, v); 154 Ceils[v_index].name = v; 155 } 156 /*並查集,將u設為v的代表節點**/ 157 merge(u_index, v_index); 158 Ceils[v_index].state = Hang;//v的狀態變更為掛起,將不再參與後續的構圖 159 //cout << Ceils[u_index].name << " = " << Ceils[v_index].name << " /*v的代表 " << Ceils[ufs_find(v_index)].name << endl; 160 } 161 } 162 } 163 void Read_Msg_unequal(){//讀出大小條目,構造圖鄰接表 164 for (int i = 0; i < fileMsg.size(); i++) { 165 int pos; 166 if ((pos = fileMsg[i].find(">", 0)) != -1) { 167 /* 根據符號分割,將姓名分割出來儲存到臨時變數u v中 **/ 168 string u = fileMsg[i].substr(0, pos); 169 string v = fileMsg[i].substr(pos + 1, fileMsg[i].size()); 170 171 //查詢雜湊表中是否名字已經存在 172 int u_index = hash_find(tab, u);//u, v 在雜湊表中的索引 173 int v_index = hash_find(tab, v); 174 if (u_index == -1) {//姓名不存在,將姓名插入雜湊表,更新下標 175 u_index = hash_insert(tab, u); 176 Ceils[u_index].name = u; 177 } 178 if (v_index == -1) {//姓名不存在,將姓名插入雜湊表,更新下標 179 v_index = hash_insert(tab, v); 180 Ceils[v_index].name = v; 181 } 182 adj[ufs_find(u_index)].push_back(ufs_find(v_index)); //u > v 即u 指向v 183 Ceils[ufs_find(u_index)].outdegree++; 184 Ceils[ufs_find(v_index)].indegree++; 185 //cout << Ceils[u_index].name << " > " << Ceils[v_index].name << " /*圖由 " << Ceils[ufs_find(u_index)].name << " 指向 "<< Ceils[ufs_find(v_index)].name << endl; 186 } 187 else if ((pos = fileMsg[i].find("<", 0)) != -1) { 188 /* 根據符號分割,將姓名分割出來儲存到臨時變數u v中 **/ 189 string u = fileMsg[i].substr(0, pos); 190 string v = fileMsg[i].substr(pos + 1, fileMsg[i].size()); 191 192 //查詢雜湊表中是否名字已經存在 193 int u_index = hash_find(tab, u);//u, v 在雜湊表中的索引 194 int v_index = hash_find(tab, v); 195 if (u_index == -1) {//姓名不存在,將姓名插入雜湊表,更新下標 196 u_index = hash_insert(tab, u); 197 Ceils[u_index].name = u; 198 } 199 if (v_index == -1) {//姓名不存在,將姓名插入雜湊表,更新下標 200 v_index = hash_insert(tab, v); 201 Ceils[v_index].name = v; 202 } 203 adj[ufs_find(v_index)].push_back(ufs_find(u_index)); //u < v 即v 指向 u 204 Ceils[ufs_find(u_index)].indegree++; 205 Ceils[ufs_find(v_index)].outdegree++; 206 //cout << Ceils[u_index].name << " < " << Ceils[v_index].name << " /*圖由 " << Ceils[ufs_find(v_index)].name << " 指向 "<< Ceils[ufs_find(u_index)].name << endl; 207 } 208 } 209 } 210 void __Free__() {//釋放記憶體 211 for (int i = 0; i < MAXN; i++) adj[i].clear();//清空圖鄰接表 212 fileMsg.clear();//清空Msg中的元素 213 RES.clear();//清空結果陣列 214 ResCnt = 0; 215 delete [] tab.Cells; 216 delete [] Ceils; 217 } 218 void Read_File(string filename) { 219 fstream input(filename, ios::in);//c++檔案輸入流讀取檔案,ios::in 以讀方式開啟 220 if (!input) {//如果沒有找到檔案,程式終止 221 cout << "沒有找到檔案!" << endl; 222 exit(-1); 223 } 224 string msg; 225 while (getline(input, msg)) {//逐行取存 226 fileMsg.push_back(msg);//存入fileMsg 227 } 228 input.clear(); 229 } 230 enum TopState TopSort() { 231 queue<int> q;//用於拓撲排序的輔助佇列 232 int count = 0;//入度為零的節點數,超過2個代表無法排序 233 enum TopState flag = True;//標記資料 234 int cnt = 0;//結果儲存下標 235 for (int i = 0; i < MAXN; i++) { 236 if (Ceils[i].name != "-1" && Ceils[i].state != Hang && Ceils[i].indegree == 0) {//節點有效並且入度為0 237 q.push(i);//加入佇列 238 count++; 239 } 240 } 241 if (count >= 2) flag = Contra; 242 while (!q.empty()) { 243 int t = q.front(); 244 q.pop(); 245 count--; 246 RES.push_back(t); 247 cnt++; 248 for (int i = 0; i < adj[t].size(); i++) {//尋找新的入度為0的節點,這個節點必然在上一個入度為零節點的鄰接表中 249 int next = ufs_find(adj[t][i]); 250 Ceils[next].indegree--; 251 if (Ceils[next].indegree == 0) { 252 count++; 253 q.push(next); 254 } 255 } 256 if (count >= 2) { 257 flag = Contra; 258 Ceils[t].state = DataContra; 259 } 260 } 261 if (cnt == ResCnt && flag == True) 262 return True; 263 else if (cnt == ResCnt && flag == Contra) 264 return Contra; 265 else 266 return False; 267 } 268 void PrintRes(enum TopState res) {//輸出結果 269 system("cls"); 270 mainFrame(); 271 if (res == True) { 272 string re = "資料可以完整排序, 排序結果為:"; 273 setPos((WIDTH - re.size()) / 2 + LEFTOTHER, TOPOTHER + 10);//居中列印 274 cout << re << endl; 275 for (int i = 0; i < MAXN; i++) {//將"掛起"的節點插入到輸出結果列表中,插入位置為其代表節點後方 276 if (Ceils[i].name != "-1" && Ceils[i].state == Hang) { 277 RES.insert(find(RES.begin(), RES.end(), ufs_find(i)), i); 278 } 279 } 280 re = ""; 281 setPos(LEFTOTHER + 14, TOPOTHER + 13); 282 for (list<int>::iterator lt = RES.begin(); lt != RES.end(); lt++) { 283 if (ufs[*lt] != *lt) { 284 re += Ceils[*lt].name[0]; 285 re += "="; 286 } 287 else { 288 re += Ceils[*lt].name[0]; 289 re += "->"; 290 } 291 } 292 cout << re.substr(0, re.size() - 2);//-2去掉最後一個箭頭 293 string tip = "按任意鍵繼續..."; 294 setPos((WIDTH - tip.size()) / 2 + LEFTOTHER - 1, HIGHT + TOPOTHER - 2); 295 system("pause"); 296 } 297 else if (res == Contra) { 298 string re = "資料不矛盾但無法完整排序: "; 299 setPos((WIDTH - re.size()) / 2 + LEFTOTHER, TOPOTHER + 10);//居中列印 300 cout << re; 301 re = "資料在 "; 302 for (list<int>::iterator lt = RES.begin(); lt != RES.end(); lt++) { 303 if (Ceils[*lt].state == DataContra) { 304 re += Ceils[*lt].name[0]; 305 re += " "; 306 } 307 } 308 re += "後方出現無法排序的情況"; 309 setPos((WIDTH - re.size()) / 2 + LEFTOTHER, TOPOTHER + 13); 310 cout << re; 311 string tip = "按任意鍵繼續..."; 312 setPos((WIDTH - tip.size()) / 2 + LEFTOTHER - 1, HIGHT + TOPOTHER - 2); 313 system("pause"); 314 } 315 else { 316 string re = "資料矛盾無法排序: "; 317 setPos((WIDTH - re.size()) / 2 + LEFTOTHER, TOPOTHER + 10);//居中列印 318 cout << re; 319 re = "資料在 "; 320 re += Ceils[RES.back()].name[0]; 321 re += " 後方出現數據矛盾"; 322 setPos((WIDTH - re.size()) / 2 + LEFTOTHER, TOPOTHER + 13); 323 cout << re; 324 string tip = "按任意鍵繼續..."; 325 setPos((WIDTH - tip.size()) / 2 + LEFTOTHER - 1, HIGHT + TOPOTHER - 2); 326 system("pause"); 327 } 328 329 } 330 int hash_func(string name) {//雜湊函式,返回應插入下標,以姓名的ASCII碼總和作為雜湊索引 331 int char_ascii_sum = 0; 332 for (int i = 0; i < name.size(); i++) { 333 char_ascii_sum += (int)name[i];//累加ASCII碼 334 } 335 return char_ascii_sum % MAXN; 336 } 337 int hash_insert(HashTable& tab, string name) {//雜湊表插入,採用線性探測,返回插入位置的下標 338 int index = hash_func(name); 339 while (tab.Cells[index].Info != Empty) { 340 index++; 341 if (index == MAXN) index = 0; 342 } 343 tab.Cells[index].name = name; 344 tab.Cells[index].Info = Legitimate; 345 tab.TableSize++; 346 return index; 347 } 348 int hash_find(HashTable& tab, string name) { 349 int index = hash_func(name); 350 while (tab.Cells[index].Info == Legitimate) { 351 if (tab.Cells[index].name == name) { 352 return index; 353 } 354 index++; 355 if (index == MAXN) index = 0; 356 } 357 return -1; 358 }View Code