[C++]实现散列表的分离链接法的数据结构

  散列表,英文叫做Hash Table,因此也叫哈希表,是一种根据关键字值来确定主存中存储位置的数据结构.通过一个散列函数(关于键值的函数),来确定存储该关键字的位置.

  主要的方法有:  1.分离链接法(拉链法)

  分离链接法的散列函数为 position = key % n. 即关键字的存储位置为关键字的值对表项的数量取模.若表项大小为13,对于关键值为27的项,存储在1(27 % 13 = 1)的表项处.为了减少冲突,n往往取素数.对于同余的关键字,采用 队列(链表) 的方式连接在一起,新放入的元素放入队头或者队尾均可.用图描述如下:

  2.线性探查法

    线性探查法是根据冲突次数,来从目标位置后移冲突次数次位置来避免冲突的,即position_new = (position + i) % n,其中i为冲突次数,n为表项大小.

  3.平方探查法

    与线性探查法类似,只不过是散列函数的不同,其position_new = (position + i) % n

  4. 双散列,再散列等

  分离链接法的数据结构的数据结构的构造,使用一个名为HashTable的类来封装整个表的操作和属性.用vector<deque<int>>来表示整个数据结构,即整个表是一个由(双端)

队列组成的向量(数组).类中还包含其他的函数,用来访问类中的私有属性.

  类的声明如下:

 1 class HashTable {
 2     public:
 3         HashTable(int = 11);
 4         ~HashTable() = default;
 5         int getHashItemSize(const int) const;        //获得队列长度
 6         int getHashTableSize() const;        //获得表项的大小
 7         bool insertRecord(int);        //插入一个值
 8         void removeRecord(const int);            //删除一个值
 9         bool isEmpty() const;       //判断哈希表是否为空
10         void print() const;       //打印哈希表
11
12     private:
13         vector<deque<int>>  HashItem;    //结构定义
14         int HashTableSize = 0;      //哈希表表项数
15 };

  

构造函数定义:

  

 1 HashTable::HashTable(int n)     //构造函数定义
 2 {
 3     HashTableSize = n;
 4
 5     for (int i = 0; i < n; ++i)
 6     {
 7         deque<int> adeque;
 8         HashItem.push_back(adeque);     //向向量中压入足够的空队列
 9     }
10 }

插入记录的函数的定义:

 1 bool HashTable::insertRecord(int data)      //插入一个指定值的记录
 2 {
 3     int position = data % HashTableSize;                //映射规则
 4
 5     if (position >= HashTableSize || position < 0)    //合法性判断
 6         return false;
 7
 8     else
 9     {
10         HashItem.at(position).push_front(data);  //根据时间局部性原理,插入到队头
11         return true;
12     }
13 }

删除记录的函数定义

 1 void HashTable::removeRecord(const int aim)     //删除一个指定值的记录
 2 {
 3     int i = 0;
 4     int j = 0;
 5
 6     for (; i < HashTableSize; ++i)            //遍历表项
 7     {
 8
 9         for (j = 0; j < static_cast<int>(HashItem.at(i).size()); ++j)                //遍历队列
10         {
11             if (HashItem.at(i).at(j) == aim)
12                 HashItem.at(i).erase(HashItem.at(i).begin() + j);       //删除记录
13         }
14     }
15
16 }

打印函数:

 1 void HashTable::print() const
 2 {
 3     for (int i = 0; i < getHashTableSize(); ++i)        //遍历表项
 4     {
 5         deque<int> temp = HashItem.at(i);
 6
 7         for (auto &j : temp)            //遍历队列
 8             cout << j << ‘ ‘;
 9
10         cout << endl;
11     }
12 }

对于主函数,写了一点测试语句来进行测试:

 1 int main()
 2 {
 3     HashTable hashtable(13);
 4
 5     for (int i = 0; i < 100; ++i)
 6         hashtable.insertRecord(i);
 7
 8     hashtable.print();
 9
10     cout << endl;
11
12     hashtable.removeRecord(91);
13     hashtable.removeRecord(70);
14
15     hashtable.print();
16
17     return 0;
18 }

插入0到99的关键字,散列到表项大小为13的散列表中,在删除91和70两个关键值.

运行结果输出了0到99的散列情况和删除操作之后的散列情况:

本人原创,转载请注明出处,谢谢合作!

时间: 2024-08-06 11:56:35

[C++]实现散列表的分离链接法的数据结构的相关文章

散列之分离链接法

1 #include <vector> 2 #include <list> 3 #include <string> 4 #include <algorithm> 5 using std::vector; 6 using std::list; 7 using std::string; 8 using std::find; 9 10 int hash(const string &key) 11 { 12 int hashVal = 0; 13 14 fo

数据结构--散列(分离链接法解决冲突)

散列方法的主要思想是根据结点的关键码值来确定其存储地址:以关键码值K为自变量,通过一定的函数关系h(K)(称为散列函数),计算出对应的函数值来,把这个值解释为结点的存储地址,将结点存入到此存储单元中.检索时,用同样的方法计算地址,然后到相应的 单元里去取要找的结点.通过散列方法可以对结点进行快速检索.散列(hash,也称"哈希")是一种重要的存储方式,也是一种常见的检索方法. 因此,散列函数更像是一种映射,散列函数的选择有很多种,下面以散列函数为关键值对10取余为例,说明散列的插入关键

分离链接法实现散列表

散列表是一种用于查找的数据结构.其基本思想来自于索引,也可以看成是数组的一种扩展.对于一些数据信息,比如说图片文件名,如果我们要查找某张图片,通常将图片名作为关键字进行搜索.这个时候是不可能把图片名直接当成数组下标的,因此可以将图片名关键字通过某个函数映射为某个地址,或地址偏移量.那么每次要查找图片的时候直接输入关键字就能直接计算得出存储地址.其定义 T=h(k) 其中k为关键字,h为映射函数,T为得到的散列表,得到的函数值为地址或地址偏移量. 如果不同关键字通过某函数得到的散列值(地址偏移量)

散列表的C语言实现-分离链接法

一:散列表的定义: 散列表的实现常常叫做散列,散列是一种用于以常数平均时间执行插入,查找,删除的技术,但是,那些需要元素间任何排序信息的操作将不会得到支持,如findmin,findmax等等.散列表的优点很明显,它的查询时间为常数,速度非常快,缺点就是元素间没有排序,对于一些需要排序的场合不适用.理想的散列表数据结构就是一个包含有关键字的具有固定大小的数组,用一个散列函数来跟据关键字的值来将关键字插入到表中.这是散列的基本想法,剩下的问题是要选择一个好的散列函数,当俩个关键字散列到同一个值得时

数据结构--解决散列冲突,分离链接法

散列表的实现经常叫做散列. 散列是一种用以常数平均时间运行插入.删除,和查找的技术.可是那些须要元素信息排序的树操作不会得到支持. 因此比如findMax,findMin以及排序后遍历这些操作都是散列不支持的. 假设当一个元素被插入时与已经插入的元素散列(比方散列表的数组序号,非常多元素插入到同一个数组序号中).那么就会产生一个冲突,这个冲突须要消除.解决冲突的办法有两种: 1 分离链接法 2  开放定址法(包含线性探測,平方探測,双散列) 两者都有可能须要再散列 以下说明分离链接法,上代码:

解决hash冲突之分离链接法

解决hash冲突之分离链接法 分离链接法:其做法就是将散列到同一个值的所有元素保存到一个表中. 这样讲可能比较抽象,下面看一个图就会很清楚,图如下 相应的实现可以用分离链接散列表来实现(其实就是一个linkedList数组) 至于基本的增加.删除和查询的思路都是先根据散列函数来确定遍历哪个链表.然后再到被确定的链表中执行一次查找,然后再进行相应的操作. 接下来就讲几个注意点吧 (一)什么时候需要rehash来扩大散列表的大小 讲这个的时候,先介绍一下什么是装填因子. 装填因子 = 关键字个数 /

习题5.11 分离链接法的删除操作函数 (20分)

试实现分离链接法的删除操作函数. 函数接口定义: bool Delete( HashTable H, ElementType Key ); 其中HashTable是分离链接散列表,定义如下: typedef struct LNode *PtrToLNode; struct LNode { ElementType Data; PtrToLNode Next; }; typedef PtrToLNode Position; typedef PtrToLNode List; typedef struc

哈希表冲突的两个解决方法线性探测和分离链接法

1.线性探测法 就是当要插入的行号发生冲突时,往下一个行号存放哈希值,直到没有冲突. 2.分离链接法 就是将一个行号做成链表的形式,如果有这个行号的冲突便新建一个节点将其插入这个行号的链表中. 在Mahout中,FastByIDMap是基于散列的,但它在处理散列冲突时使用的是线性探测,而非分离链接.因为线性探测不必为每个条目新增加一个额外的Map.Entry对象,节省了内存开销:在数据规模很庞大的时候,这种优势更加体现得出来.

算法学习 - Hash Table操作,分离链接法解决哈希冲突

分离链接法 hash table是映射机制的,最大的优点就是它的操作是O(1)级别的.但是会出现哈希冲突,这就需要几种办法来解决.这里先说一种:分离链接法. 就是当插入的位置已经存在一个值之后,那么在这个值之后插入,就可以了,也叫拉链法.(但是其实会降低查找速度,变成O(n)级别) 下面是代码: // // main.cpp // HashTable_SeparateChaining // // Created by Alps on 14-8-5. // Copyright (c) 2014年