数据结构课程设计-利用散列表做一个电话号码查找系统

这是一个数据结构课程设计项目,使用C++构建了一个散列表,能够根据电话号码和用户名进行查找。项目包括了三种哈希函数和三种解决冲突的方法:线性探测、二次探查和拉链法。在实践中,作者认识到C++语法、算法理解和数据结构的重要性,并表示将继续努力提升技能。

   【基本要求】

    (1)设每个记录有下列数据项:电话号码、用户名、地址;

    (2)从键盘输入各记录,分别以电话号码和用户名为关键字建立散列表;

    (3)采用一定的方法解决冲突;

    (4)查找并显示给定电话号码的记录;

    (5)查找并显示给定用户名的记录。

    【选做内容】

    (1)系统功能的完善;

    (2)设计不同的散列函数,比较冲突率;

 (3)在散列函数确定的前提下,尝试各种不同类型处理冲突的方法,考察平均查找长度的变化。

 

用的C++开发,基本实现了3种哈希函数+3种解决冲突的方法。因为要求同时有姓名散列与按号码散列,所以用了

flag标记每次的散列类型 ,针对不同的要求对散列函数做了个别优化。

哈希表类的结构如下

 

 1 class HashTable{
 2     public:
 3         HashTable(int size = MAXSIZE-1);
 4         ~HashTable(){ delete[]E; delete[]tag; delete[]E2; delete[]tag2; }
 5         int  hash1(string name, int flag);//哈希函数1  除数求余法
 6         int  hash2(string tel);//哈希函数2 折叠法
 7         int  hash3(string tel);//哈希函数3 数字分析法
 8         int  solve1(int hashVal, int flag);//线性探测法解决冲突
 9         int  solve2(int hashVal, int flag);//二次探测法解决冲突
10         Node*  solve3(int hashVal, int flag);//拉链法解决冲突
11         User input();//往电话薄中添加用户
12         void creat(int flag);  //创建散列表
13         void show(int flag);    //列出电话薄所有元素
14         void search(int flag,string at);  //搜索指定用户
15         void searchByNode(int flag, string at);  //拉链法搜索指定用户
16         void insert(int flag, User newUser); //插入
17         void del(int flag, string by);//删除
18         void save(int flag);//将电话薄保存至本地文件
19         int length; //要创建的电话本长度
20         Node** ht;
21     private:
22         User* E;  //用户数组  按姓名散列
23         User* E2; //用户数组2 按电话号码散列
24         int* tag; //标记散列表1每个桶的存储状态 0为空 1为实
25         int* tag2;//标记散列表2每个桶的存储状态
26         int flag;      //1表示是按姓名  2表示按电话号码 新建的哈希表
27         int maxSize;   //哈希表最大长度
28         int f;//比例因子  主要用于折叠法
29 };
View Code

User类的结构

class User{
    public:
        string name; 
        string tel;
        string address;
        bool operator==(const User&target)
        {
            if (this->name == target.name&&this->address == target.address&&this->tel == target.tel)
                return true;
            else
                return false;
        }
};

 

哈希函数1

int HashTable::hash1(string name,int flag) //除留求余法
{
    int hashValue;        long a = 0;
    switch (flag)
    {
    case 1:
        for (int i = 0; i < name.length(); i++)
            a += int(name[i]);
        hashValue = a%maxSize;
        break;
    case 2:
        int temp = atof(name.c_str());
        hashValue = temp%maxSize;
        break;

    }
    return hashValue;
};

哈希函数2

int HashTable::hash2(string    tel)  //折叠法--移位法
{
    int hashValue;   
    int temp; //移位法求和
    temp = atof(tel.substr(0, 3).c_str()) + atof(tel.substr(3, 3).c_str()) 
        + atof(tel.substr(6, 3).c_str()) + atof(tel.substr(9, 2).c_str());
    //取计算之后的数的最后三位
    if (temp >= 999)
    {
        char p[10];
        sprintf(p, "%d", temp);
        string lastThree = p;
        lastThree = lastThree.substr(lastThree.length() - 3, 3);
        hashValue = atof(lastThree.c_str());
        return hashValue;
    }
    hashValue = temp;
    return hashValue;
};

哈希函数3

int HashTable::hash3(string tel)//数字分析法做哈希函数 
{
    int hashValue;
    hashValue = atof(tel.substr(8, 3).c_str()); //因为电话号码一般后4位不同
    return hashValue;
};

 


 

 解决冲突的方法

 1.线性探测法

int HashTable::solve1(int hashVal,int flag)  //线性探查法处理冲突
{
    int output = hashVal;
    switch (flag)
    {
    case 1:
        for (int j = 1; j < MAXSIZE; j++)
        {
            output = (hashVal + j) % MAXSIZE;
            if (tag[output] == 0)
            {
                tag[output] = 1;
                return output;
            }
        }
        return -1;
        break;
    case 2:
        for (int j = 1; j < MAXSIZE; j++)
        {
            output = (hashVal + j) % MAXSIZE;
            if (tag2[output] == 0)
            {
                tag2[output] = 1;
                return output;
            }
        }
        return -1;
    default:
        break;
    }

};

2.二次探查法

int HashTable::solve2(int hashVal, int flag)   //二次探查法解决冲突
{
    int i = hashVal;            //i为初始桶号
    int k = 0;                    //k为探查次数
    int odd = 0;                //odd为控制加减的标志
    int save;                    //缓存上一次的桶号
    switch (flag)
    {
    case 1:
        while (tag[i]==1)
        {
            if (odd == 0)
            {
                k++; save = i;
                i = (i + 2 * k-1) % MAXSIZE;
                odd = 1;
            }
            else
            {
                i = (save - 2 * k+1) % MAXSIZE;
                odd = 0;
                if (i<0)
                {
                    i = i + MAXSIZE;
                }
            }
        }
        return i;
        break;
    case 2:
        while (tag2[i] == 1)
        {
            if (odd == 0)
            {
                k++; save = i;
                i = (i + 2 * k - 1) % MAXSIZE;
                odd = 1;
            }
            else
            {
                k++;
                i = (save - 2 * k + 1) % MAXSIZE;
                odd = 0;
                if (i<0)
                {
                    i = i + MAXSIZE;
                }
            }
        }
        return i;
        break;
    default:
        break;
    }
    
};

3.拉链法

<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值