散列表應用---電話號碼查詢系統


問題介紹

設計電話號碼查詢系統

基本要求

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,鄙人賊菜,有什么好的意見,評論區留言哈!  :)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM