問題介紹
設計電話號碼查詢系統
基本要求
1.設每個記錄有下列數據項:
電話號碼、用戶名、地址;
2.從鍵盤輸入各記錄,分別以電話號碼和用戶名為關鍵字建立散列表;
3.采用合適的方法解決沖突;
4.查找並顯示給定電話號碼的記錄;
5.查找並顯示給定用戶名的記錄;
6.插入用戶記錄;
7.刪除用戶記錄;
8.輸出用戶的信息。
算法思想
1.將輸入的用戶的電話號碼和用戶名以字符串的形式存儲起來。采用除留取余法將電話號碼和用戶名所對應的字符串的ASCII碼的和求出來,對除數取余,放到散列表中。
2.對於除數怎么確定呢?首先我們先輸入一個n,表示用n個用戶,然后將n+10,求n到n+10里面最大的素數,作為除數。這就是除留取余法。
//判斷素數 bool isprime(int n) { if (n <= 1) return false; long long m = floor(sqrt(n) + 0.5); for (long long i = 2; i <= m; ++i) { if (n%i == 0) return false; } return true; } //確定除留取余法的除數,m=n+10. int confirm(int m) { while (!isprime(m)) { //如果函數返回值是false,說明m不是素數,就把m-- --m; } return m; }
3.沖突的判定方法(以輸入電話號碼為例)
如果輸入的電話號碼的ASCII碼對應的余數值對應的位置已經有元素了,我們就將這個元素位置往后移一位,並接着判斷此位置是否已經有元素了。
如果判斷到散列表的末尾,就接着從頭開始判斷。如果判斷的次數等於表長,就說明此電話號碼插不進去了。
while (rec1[sum].flag == true) { //如果該位置已經有數據了,就向后移動一位 if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << telnum << "插入不進散列表" << endl; break; } } if (count != m) { strcpy(rec1[sum].telnum, telnum); strcpy(rec1[sum].telname, telname); strcpy(rec1[sum].teladd, teladd); rec1[sum].flag = true; rec1[sum].count = count; }
4.查詢算法和刪除算法
查詢算法首先需要找到對應余數值相等的位置,再判斷此處的字符串是否與之匹配,如果匹配就輸出,不匹配就往后移一位,這個過程和插入是類似的。
刪除也是,刪除只要將對應位置的標志位記為false即可。
源代碼
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<string.h> #include<iomanip> using namespace std; const int maxn = 100; int n;//記錄個數 int n1, n2; //n1,n2分別表示兩個散列表里面的用戶數 int m;//散列表大小 //用戶信息 struct record { char telnum[maxn]; //電話號碼 char telname[maxn]; //用戶名 char teladd[maxn]; //地址 bool flag; //標志位,如果flag=false,說明此處無數據。反之,則有數據 int count = 0; //記錄發生沖突的次數 }; struct record rec1[maxn]; //電話號碼散列表 struct record rec2[maxn]; //用戶名散列表 //判斷素數 bool isprime(int n) { if (n <= 1) return false; long long m = floor(sqrt(n) + 0.5); for (long long i = 2; i <= m; ++i) { if (n%i == 0) return false; } return true; } //確定除留取余法的除數 int confirm(int m) { while (!isprime(m)) { //如果函數返回值是false,說明m不是素數,就把m-- --m; } return m; } //構建電話號碼散列表 void init1() { while (n1--) { char telnum[maxn], telname[maxn], teladd[maxn]; cout << "請輸入電話號碼:"; cin >> telnum; cout << "請輸入用戶名:"; cin >> telname; cout << "請輸入地址:"; cin >> teladd; int sum(0); bool flag = false; int count(0); //記錄發生沖突的次數 for (int i = 0; i <strlen(telnum); ++i) { sum += telnum[i] - '0'; //計算key值 } sum = sum % m; //除留取余,找到key值在散列表中對應的位置 while (rec1[sum].flag == true) { //如果該位置已經有數據了,就向后移動一位 if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << telnum << "插入不進散列表" << endl; break; } } if (count != m) { strcpy(rec1[sum].telnum, telnum); strcpy(rec1[sum].telname, telname); strcpy(rec1[sum].teladd, teladd); rec1[sum].flag = true; rec1[sum].count = count; } } } //通過電話號碼查詢信息 void print1() { char t[20]; cout << "請輸入需要查找的電話號碼:"; cin >> t; int sum(0); for (int i = 0; i <strlen(t); ++i) { sum += t[i] - '0'; //計算key值 } sum = sum % m; //除留取余,找到key值在散列表中對應的位置 int count(0); //記錄判斷的次數 while (strcmp(rec1[sum].telnum, t) != 0) { if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << "查詢失敗" << endl; cout << t << "不在散列表中" << endl; break; } } if (count != m) { cout << "查詢成功" << endl; cout << "電話號碼:" << rec1[sum].telnum << endl; cout << "用戶名:" << rec1[sum].telname << endl; cout << "地址:" << rec1[sum].teladd << endl; cout << "沖突次數:" << rec1[sum].count << endl; } } //根據電話號碼插入用戶 void insert1() { char telnum[maxn], telname[maxn], teladd[maxn]; cout << "請輸入需要插入的用戶的電話號碼 "; cin >> telnum; int sum(0); bool flag = false; int count(0); //記錄發生沖突的次數 for (int i = 0; i <strlen(telnum); ++i) { sum += telnum[i] - '0'; //計算key值 } sum = sum % m; //除留取余,找到key值在散列表中對應的位置 while (rec1[sum].flag == true) { //如果該位置已經有數據了,就向后移動一位 if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << "通訊錄已滿,用戶電話號碼為" << telnum << "的用戶插入失敗" << endl; break; } } if (count != m) { cout << "插入成功,請完善該用戶的其他信息" << endl; cout << "請輸入用戶名:"; cin >> telname; cout << "請輸入地址:"; cin >> teladd; strcpy(rec1[sum].telnum, telnum); strcpy(rec1[sum].telname, telname); strcpy(rec1[sum].teladd, teladd); rec1[sum].flag = true; rec1[sum].count = count; } } //根據電話號碼刪除用戶 void Delete1() { char telnum[maxn], telname[maxn], teladd[maxn]; cout << "請輸入需要刪除的用戶的電話號碼 "; cin >> telnum; int sum(0); bool flag = false; int count(0); //記錄發生沖突的次數 for (int i = 0; i <strlen(telnum); ++i) { sum += telnum[i] - '0'; //計算key值 } sum = sum % m; //除留取余,找到key值在散列表中對應的位置 while (strcmp(rec1[sum].telnum, telnum) != 0||rec1[sum].flag==false) { if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << "刪除失敗,電話號碼為" << telnum << "的用戶不在通訊錄中" << endl; break; } } if (count != m) { cout << "刪除成功" << endl; rec1[sum].flag = false; } } //顯示電話號碼散列表的信息 void fun1() { cout << "******************************" << endl; cout << "********電話號碼通訊錄********" << endl; cout << "******************************" << endl; for (int i = 0; i < m; ++i) { if (rec1[i].flag == true) { cout << i << "號用戶的信息" << "電話號碼:" << rec1[i].telnum << " " << "用戶名:" << rec1[i].telname << " " << "地址:" << rec1[i].teladd << " " << "沖突次數:" << rec1[i].count << endl; } } } //計算電話號碼通訊錄查找成功的ASL void succ_asl1() { int counter = 0; //統計發生沖突的次數 int counter1 = 0; //統計散列表里面有多少個數據 for (int i = 0; i < m; ++i) { if (rec1[i].flag) { counter += rec1[i].count+1; ++counter1; } } double succ_asl; if (counter1 != 0) { succ_asl = (double)((double)counter / (double)counter1); } cout << counter << endl; cout<<"查找成功的ASL為 "<< setprecision(5) << fixed <<succ_asl<< endl; } //計算電話號碼通訊錄查找失敗的ASL void fail_asl1() { int counter = 0; //統計發生沖突的次數 int counter1; //統計連續有數據的個數 for (int i = 0; i < m; ++i) { counter1 = 0; int temp = i; while(rec1[temp].flag) { if (temp == m) { temp = 0; } ++counter1; ++temp; } counter1++; counter += counter1; } double fail_asl; fail_asl = (double)((double)counter / (double)m); cout << counter << endl; cout << "查找失敗的ASL為 " << setprecision(5) << fixed << fail_asl << endl; cout << counter << endl; } //構建用戶名散列表 void init2() { while (n2--) { char telnum[maxn], telname[maxn], teladd[maxn]; cout << "請輸入用戶名(請輸入英文名):"; cin >> telname; cout << "請輸入電話號碼:"; cin >> telnum; cout << "請輸入地址:"; cin >> teladd; int sum(0); bool flag = false; int count(0); //記錄發生沖突的次數 for (int i = 0; i <strlen(telname); ++i) { sum += telname[i] - 'A'; //計算key值 } sum = sum % m; //除留取余,找到key值在散列表中對應的位置 while (rec2[sum].flag == true) { //如果該位置已經有數據了,就向后移動一位 if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << telnum << "插入不進散列表" << endl; break; } } if (count != m) { strcpy(rec2[sum].telnum, telnum); strcpy(rec2[sum].telname, telname); strcpy(rec2[sum].teladd, teladd); rec2[sum].flag = true; rec2[sum].count = count; } } } //通過用戶名查詢信息 void print2() { char t[20]; cout << "請輸入需要查找的用戶名(請輸入英文名):"; cin >> t; int sum(0); for (int i = 0; i <strlen(t); ++i) { sum += t[i] - 'A'; //計算key值 } sum = sum % m; //除留取余,找到key值在散列表中對應的位置 int count(0); //記錄判斷的次數 while (strcmp(rec2[sum].telname, t) != 0) { if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << "查詢失敗" << endl; cout << t << "不在用戶名通訊錄中" << endl; break; } } if (count != m) { cout << "查詢成功" << endl; cout << "用戶名:" << rec2[sum].telname << endl; cout << "電話號碼:" << rec2[sum].telnum << endl; cout << "地址:" << rec2[sum].teladd << endl; cout << "沖突次數:" << rec2[sum].count << endl; } } //根據用戶名插入用戶 void insert2() { char telnum[maxn], telname[maxn], teladd[maxn]; cout << "請輸入需要插入的用戶的用戶名 "; cin >> telname; int sum(0); bool flag = false; int count(0); //記錄發生沖突的次數 for (int i = 0; i <strlen(telname); ++i) { sum += telname[i] - 'A'; //計算key值 } sum = sum % m; //除留取余,找到key值在散列表中對應的位置 while (rec2[sum].flag == true) { //如果該位置已經有數據了,就向后移動一位 if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << "通訊錄已滿,用戶名為" << telname << "的用戶插入失敗" << endl; break; } } if (count != m) { cout << "插入成功,請完善該用戶的其他信息" << endl; cout << "請輸入電話號碼:"; cin >> telnum; cout << "請輸入地址:"; cin >> teladd; strcpy(rec2[sum].telnum, telnum); strcpy(rec2[sum].telname, telname); strcpy(rec2[sum].teladd, teladd); rec2[sum].flag = true; rec2[sum].count = count; } } //根據用戶名刪除用戶 void Delete2() { char telnum[maxn], telname[maxn], teladd[maxn]; cout << "請輸入需要刪除的用戶的用戶名 "; cin >> telname; int sum(0); bool flag = false; int count(0); //記錄發生沖突的次數 for (int i = 0; i <strlen(telname); ++i) { sum += telname[i] - '0'; //計算key值 } sum = sum % m; //除留取余,找到key值在散列表中對應的位置 while (strcmp(rec2[sum].telname, telname) != 0||rec2[sum].flag==false) { if (sum < m - 1) sum++; //如果已經移動到最后一位了,就 else sum = 0; //從頭開始判斷 ++count; //記錄沖突次數 if (count == m) { cout << "刪除失敗,用戶名為" << telname << "的用戶不在通訊錄中" << endl; break; } } if (count != m) { cout << "刪除成功" << endl; rec2[sum].flag = false; } } //顯示用戶名散列表的信息 void fun2() { cout << "****************************" << endl; cout << "********用戶名通訊錄********" << endl; cout << "****************************" << endl; for (int i = 0; i < m; ++i) { if (rec2[i].flag == true) { cout << i << "號用戶的信息" << "用戶名:" << rec2[i].telname << " " << "電話號碼:" << rec2[i].telnum << " " << "地址:" << rec2[i].teladd << " " << "沖突次數:" << rec2[i].count << endl; } } } //計算用戶名通訊錄查找成功的ASL void succ_asl2() { int counter = 0; //統計發生沖突的次數 int counter1 = 0; //統計散列表里面有多少個數據 for (int i = 0; i < m; ++i) { if (rec2[i].flag) { counter += rec2[i].count + 1; ++counter1; } } double succ_asl; if (counter1 != 0) { succ_asl = (double)((double)counter / (double)counter1); } cout << counter << endl; cout << "查找成功的ASL為 " << setprecision(5) << fixed << succ_asl << endl; } //計算用戶名通訊錄查找失敗的ASL void fail_asl2() { int counter = 0; //統計發生沖突的次數 int counter1; //統計連續有數據的個數 for (int i = 0; i < m; ++i) { counter1 = 0; int temp = i; while (rec2[temp].flag) { if (temp == m) { temp = 0; } ++counter1; ++temp; } counter1++; counter += counter1; } double fail_asl; fail_asl = (double)((double)counter / (double)m); cout << counter << endl; cout << "查找失敗的ASL為 " << setprecision(5) << fixed << fail_asl << endl; cout << counter << endl; } //主函數 int main() { cout << "請輸入用戶個數: "; cin >> n; n1 = n; n2 = n; m = confirm(n + 10); //確定散列表的大小 cout << "散列表大小為" << m << endl; while (1) { int counter(0); cout << " * * * * * * * * * * * * * * * * * * * * * * * * * * *" << endl; cout << " * * * * * * * * * 歡迎使用電話號碼查詢系統 * * * * * * * * * * *" << endl; cout << " * *" << endl; cout << " * 1.根據電話號碼構建散列表 2.根據用戶名構建散列表 *" << endl; cout << " * 3.根據電話號碼查詢相關信息 4.根據用戶名查詢相關信息 *" << endl; cout << " * 5.根據電話號碼插入用戶信息 6.根據用戶名插入用戶信息 *" << endl; cout << " * 7.根據電話號碼刪除散列表信息 8.根據用戶名刪除散列表信息 *" << endl; cout << " * 9.顯示電話號碼散列表信息 10.顯示用戶名散列表信息 *" << endl; cout << " * 11.求電話號碼散列表查找成功的ASL 12.求用戶名散列表查找成功的ASL *" << endl; cout << " * 13.求電話號碼散列表查找失敗的ASL 14.求用戶名散列表查找失敗的ASL *" << endl; cout << " * 15.清屏 16.安全退出 *" << endl; cout << " * *" << endl; cout << " * * * * * * * * * * * * * * * * * * * * * * * * * * *" << endl; cout << "請輸入數字進行操作 "; cin >> counter; switch (counter) { case 1: { init1(); cout << endl << endl; }; break; case 2: { init2(); cout << endl << endl; }; break; case 3: { print1(); cout << endl << endl; }; break; case 4: { print2(); cout << endl << endl; }; break; case 5: { insert1(); cout << endl << endl; }; break; case 6: { insert2(); cout << endl << endl; }; break; case 7: { Delete1(); cout << endl << endl; }; break; case 8: { Delete2(); cout << endl << endl; }; break; case 9: { fun1(); cout << endl << endl; }; break; case 10: { fun2(); cout << endl << endl; }; break; case 11: { succ_asl1(); cout << endl << endl; }; break; case 12: { succ_asl2(); cout << endl << endl; }; break; case 13: { fail_asl1(); cout << endl << endl; }; break; case 14: { fail_asl2(); cout << endl << endl; }; break; case 15: { system("cls"); }; break; case 16: { return 0; }; break; } } }
效果展示







ENDing
呃呃呃,沒有ending,鄙人賊菜,有什么好的意見,評論區留言哈! :)
