散列表应用---电话号码查询系统

问题介绍

设计电话号码查询系统

基本要求

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,鄙人贼菜,有什么好的意见,评论区留言哈!  :)

 

    原文作者:Tiancfq
    原文地址: https://www.cnblogs.com/laysfq/p/10111851.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注