实验8.1 线性开型寻址

该文详细介绍了如何使用线性开型寻址法实现散列表中的插入、查询和删除操作。通过散列函数的除数D和操作数m,文章描述了搜索、插入、查找和删除的步骤,并提供了C++实现代码。在删除操作中,还涉及到移动元素的计数问题。
摘要由CSDN通过智能技术生成

实验8.1 线性开型寻址

要求

使用线性开型寻址实现

描述

给定散列函数的除数D和操作数m,输出每次操作后的状态。
有以下三种操作:

  1. 插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
  2. 查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。
  3. 删除x,若散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。

格式

输入格式

第一行两个整数D,m。分别代表散列函数的除数D和操作数m。
接下来m行,每行两个整数opt和x,分别代表操作类型和操作数。
若opt为0,代表插入x。
若opt为1,代表查询x。
若opt为2,代表删除x。

输出格式

按要求输出。

思路与探讨

散列表线性探查

笔记补充——第十章:散列表(指路10.5.3)

整体思路描述

  • 主要是散列表描述字典中线性探查的应用,包括哈希表的类定义及搜索、查询、插入、删除等功能函数的定义与实现。

    本次实验几乎全是基本数据结构模型应用,在课本相关功能基础上,在输出上做了细微调整。

细节思路描述

方法search

搜索一个公开地址散列表,查找关键字为theKey的数对;
如果匹配的数对存在,返回它的位置
否则,如果散列表不满,则返回关键字为theKey的数对可以插入的位置

  • 首先搜索关键字为k的起始桶f(k)

  • 接着对表中后继桶进行搜索,直到发生以下情况:

    • (1)存有关键字为k的桶已找到,即找到了要搜索的数对
    • (2)到达一个空桶
    • (3)又回到起始桶f(k)。
  • 若发生情况(2)和(3),则说明表中没有关键字为k的数对。

方法insert

插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。

  • search搜索散列表,查找匹配的数对
  • 检查匹配的数对是否存在
  • 若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标(search会返回可以插入的位置)。

方法find

查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。

  • search搜索散列表,查找匹配的数对
  • 检查匹配的数对是否存在
  • 若散列表不含有x(含有的要求是严格的对应键就是theKey),输出“-1”,否则输出x对应下标

方法earse

散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。

  • search搜索散列表,查找匹配的数对

  • 检查匹配的数对是否存在

  • 若散列表不含有x(含有的要求是严格的对应键就是theKey),输出“Not Found”,否则输出输出删除x过程中移动元素的个数。

  • 关键点提示

    • signal = table[point]->first % divisor;

    • m是移动辅助变量,point是当前元素位置,signal是当前元素的理想位置。

    • 移动的三种情况:(signal <= m && m < point) || (point < signal && signal <= m) || (point < signal && m < point)

    • 具体情况流程举例在这里插入图片描述在这里插入图片描述

方法补充

把类型k映射到一个非负整数(不加这个OJ也能过,但是这是哈希表处理重点)

template <class K> class Hash;
template<>
class Hash<int>
{
public:
    size_t operator()(const int theKey) const
    {
        return size_t(theKey);
    }
};
//原文链接:https://blog.csdn.net/SunnySantino/article/details/112688024

若已看懂思路,试着自己写~


实现代码

#include <string>
#include <iostream>
using namespace std;

template<class K, class E>
class hashTable
{
	public:
    	hashTable(int theDivisor = 11);
    	~hashTable() { delete[] table; }
    	
		//插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
    	void insert(const pair<const K, E>&);	
    	//查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。 
    	void find(const K& theKey) const;
    	//删除x,若散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。 
    	void erase(K& theKey);
	protected:
    	int search(const K&) const;
    	pair<const K, E>** table;//散列表 
    	int dSize;//字典中数对的个数
    	int divisor;//散列函数的除数
};

//构造函数 
template<class K, class E>
hashTable<K, E>::hashTable(int theDivisor)
{
    divisor = theDivisor;
    dSize = 0;
	//分配和初始化散列表数组
    table = new pair<const K, E> * [divisor];
    for (int i = 0; i < divisor; i++)
        table[i] = NULL;
}

//方法search 
template<class K, class E>
int hashTable<K, E>::search(const K& theKey) const
{//搜索一个公开地址散列表,查找关键字为theKey的数对;
 //如果匹配的数对存在,返回它的位置
 //否则,如果散列表不满,则返回关键字为theKey的数对可以插入的位置
    int i = theKey % divisor;//起始桶
    int j = i;//从起始桶开始
    do
    {
        if (table[j] == NULL || table[j]->first == theKey)
            return j;
        j = (j + 1) % divisor;//下一个桶
    } while (j != i);//结束条件判断:是否返回到起始桶
    return j;//表满
}

//插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
template<class K, class E>
void hashTable<K, E>::insert(const pair<const K, E>& thePair)
{
	//搜索散列表,查找匹配的数对
    int b = search(thePair.first);
	//检查匹配的数对是否存在
    if (table[b] == NULL)
    {
        table[b] = new pair<const K, E>(thePair);
        dSize++;
        cout << b << endl;
    }
    else
    {
        if (table[b]->first == thePair.first)
        {
            cout << "Existed" << endl;
        }
    }
}

//若散列表不含有x,输出“-1”,否则输出x对应下标 
template<class K, class E>
void hashTable<K, E>::find(const K& theKey) const
{
    int b = search(theKey);
    if (table[b] == NULL || table[b]->first != theKey) 
	{
        cout << -1 << endl;
        return;
    }
    cout << b << endl;
    return;
}

//若散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。
template <class K, class E>
void hashTable<K, E>::erase(K& theKey)
{
	//搜索散列表,查找匹配的数对
    int b = search(theKey);
    if (table[b] == NULL || table[b]->first != theKey)
        cout << "Not Found" << endl;
    else
    {
        table[b] = NULL;
        int flag = 0;//记录移动元素的个数 
        int point = b, m = b, signal;
        //从欲删除的数对开始逐个检查每个桶以确定要移动的数对
        do
        {
            point = (point + 1) % divisor;//下一个桶 
            if (table[point] == NULL)
                break;
            signal = table[point]->first % divisor;
            if ((signal <= m && m < point) || (point < signal && signal <= m) || (point < signal && m < point))
            {
                table[m] = table[point];
                table[point] = NULL;
                m = point;
                flag++;
            }
        } while (table[(point + 1) % divisor] != NULL && point != b);
        cout << flag << endl;
    }
}

int main()
{
    int D, m;//散列函数的除数D和操作数m 
    cin >> D >> m;
    hashTable<int, int> a(D);
    pair<int, int> q;
    for (int i = 0; i < m; i++) 
	{
        int opt, number;
        cin >> opt >> number;
        if (opt == 0) 
		{
            q.first = number; 
			q.second = number;
            a.insert(q);
        }
        else if (opt == 1) 
		{
            q.first = number; 
			q.second = number;
            a.find(q.first);
        }
        else 
		{
            q.first = number; 
			q.second = number;
            a.erase(q.first);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啦啦右一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值