精华内容
下载资源
问答
  • C++哈希表

    2020-08-24 10:32:03
    哈希表原理3.c++哈希表接口的使用 1.什么是哈希表 散列表(Hash table 也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过关键码值映射到表中一个位置来访问记录,以加快查找的...

    1.什么是哈希表

    散列表(Hash table 也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

    2.哈希表原理

    给定表M,存在函数f(key),对任意给定的关键字key,代入函数后若能得到包含关键字的记录在表中的地址,则称表M为哈希表(Hash Table),函数f(key)为哈希函数。
    基本概念:
    (1)若关键字为k,则其值存放在f(k)的存储位置上。由此,不需要比较便可直接取得所查记录。称这个对应关系f为散列函数,按这个意思建立的表为散列表。
    (2)对不同的关键字可能得到同一散列地址,即k1≠k2,而f(k1)=f(k2),这种现象称为碰撞。具有相同函数值的关键字对该散列函数来说乘坐同义词。综上所述,根据散列函数f(k)和处理碰撞的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址中的“像”作为记录在表中的存储位置,这种表便称为散列表,这一映射过程称为散列造表或散列,所得的存储位置称散列地址。
    (3)若对于关键字集合中的任一关键字,经散列函数映射到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数,这就使关键字经过散列函数得到一个“随机的地址”,从而减少碰撞。
    几种常见的哈希表设计方法以及解决哈希冲突的方法:
    哈希表的原理和使用
    完美哈希(重点,面试中经常会被问到)
    当关键字的集合是一个不变的静态集合(Static)时,哈希技术还可以用来获取出色的最坏情况性能。如果某一种哈希技术在进行查找时,其最坏情况时间复杂度是O(1) ,则称其为完美哈希(Perfect Hashing)。
    完美哈希表的设计:https://blog.csdn.net/tiankong_/article/details/76769230

    3.c++中哈希表接口的使用

    头文件#include<hash_map>,并非标准库中的,但绝大部分都实现
    http://blog.csdn.net/tiankong_/article/details/76718467

    展开全文
  • C++ 哈希表

    2021-02-22 20:35:28
    哈希表的基本介绍: 散列表( Hash table,也叫哈希表)是根据关键码值(key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,...

    一 哈希表的基本介绍:

    散列表( Hash table,也叫哈希表)是根据关键码值(key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

    那么他是如何映射的呢,就是通过哈希函数(散列函数),常用的有取余法(h(x)= x mod p),线性函数(h(x) = ax+b),平方取中法(h(x = x*x的中间几位))。
    好理解的取余法如下图。

    在这里插入图片描述
    先看左上方的表,它以53取余,所以55,2,108都在2的下方。取余可以保证你的数据一定在这个区间内。右边是一个素数表,对素数取余保证你的散列分布相对均匀。下方的表是开链法,由于数据量巨大,比如上万个数据,那么这时对53取余就不太合适,这时就会对哈希表开链,重新生成一个新的哈希表。

    散列冲突,就是上面的55,2,108对53取余都是2,那么这就是冲突了,对此我们有几种常用的方法,开放定址法(分为线性探测,二次探测(h’(x)= ((h(x)+ d)mod n) d是一组伪随机数),还有就是链地址法,就是2的后面其实是一个链表,那么其实就是对链表的操作了,添加,遍历,如上图。

    三 小例子

    首先输入一个整数,代表将要数。输入字符串的数量,然后输入字符串,将其存储起来

    class MyHash
    {
    public:
    	MyHash() 
    	{	
    		fill(h,h+1542, 0);		
    	}
    	int myhash(string str)
    	{
    		int r = 0;
    		for (int i = 0; i < str.size(); i++)
    		{
    			r = (r + 97 + str[i]) % 1543;
    		}
    		return r;
    	}
    
    	bool insert(string str)
    	{
    		int ha = myhash(str);
    		int h0 = ha;
    		h[ha];
    		while (s[h[ha]] != str)
    		{
    			if (h[ha] == 0)//当前位置没有被占用
    			{
    				h[ha] = cur;
    				s[cur] = str;
    				cur++;
    				return true;
    			}
    			ha = (ha + 97)%1543;//被占用,线性探测
    			if (ha == h0)//防止成环
    			{
    				ha = (h0 + 1) % 1543;
    			}
    		}
    		return false;
    	}
    
    private:
    	int h[1542];
    	string s[10001];
    	int cur = 1;
    };
    
    int main()
    {
    	MyHash myhash;
    	int c;
    	cin >> c;
    	int nCount = 0;
    	while (c--)
    	{
    		string str;
    		cin >> str;
    		if (myhash.insert(str))
    			nCount++;
    
    	}
    	cout << "count:" << nCount << endl;
    	return 0;
    }
    

    结果
    在这里插入图片描述
    这个例子,哈希函数采用线性函数,处理散列冲突采用开放定址法。还有一个find方法,觉得简单就没写,和插入是一样的,仔细想一下就明白

    四 STL

    stl的散列函数
    可以发现数值类型的,hash函数的处理都是返回原值,但char*类型的进行单独处理,__stl_hash_string见下面

    template <class Key> struct hash { };
    /*字符串类型*/
    inline size_t __stl_hash_string(const char* s)
    {
    	/*处理方法*/
    	unsigned long h = 0;
    	for (; *s; ++s)
    		h = 5 * h + *s;
     
    	return size_t(h);
    }
     
    /*字符串类型,则调用上面处理方法*/
    struct hash<char*>
    {
    	size_t operator()(const char* s) const { return __stl_hash_string(s); }
    };
     
    struct hash<const char*>
    {
    	size_t operator()(const char* s) const { return __stl_hash_string(s); }
    };
     
    /*下面各种类型直接返回,无需额外处理*/
    struct hash<char> {
    	size_t operator()(char x) const { return x; }
    };
    struct hash<unsigned char> {
    	size_t operator()(unsigned char x) const { return x; }
    };
    struct hash<signed char> {
    	size_t operator()(unsigned char x) const { return x; }
    };
    struct hash<short> {
    	size_t operator()(short x) const { return x; }
    };
    struct hash<unsigned short> {
    	size_t operator()(unsigned short x) const { return x; }
    };
    struct hash<int> {
    	size_t operator()(int x) const { return x; }
    };
    struct hash<unsigned int> {
    	size_t operator()(unsigned int x) const { return x; }
    };
    struct hash<long> {
    	size_t operator()(long x) const { return x; }
    };
    struct hash<unsigned long> {
    	size_t operator()(unsigned long x) const { return x; }
    };
    
    
    //面这些包装函数最终会调用 hash(key) % n ,hash函数取编号,
    //之后再对n取余后自然可以找到自己该放在哪个buckets
    
    size_type bkt_num_key(const key_type& key) const
      {
        return bkt_num_key(key, buckets.size());
      }
    
      size_type bkt_num(const value_type& obj) const
      {
        return bkt_num_key(get_key(obj));
      }
    
      size_type bkt_num_key(const key_type& key, size_t n) const
      {
        return hash(key) % n;
      }
    
      size_type bkt_num(const value_type& obj, size_t n) const
      {
        return bkt_num_key(get_key(obj), n);
      }
    
    

    插入操作与表格重整

    /*以下函数判断是否需要重建表格。如果不需要,立即返回。如果需要,就重建*/
    template <class V, class K, class HF, class Ex, class Eq, class A>
    void hashtable<V, K, HF, Ex, Eq, A>::resize(size_type num_elements_hint)
    {
    	const size_type old_n = buckets.size();//bucket vector 的大小
    	/*如果元素个数(把新增元素计入后)比bucket vector 大,则需要重建表格*/
    	if (num_elements_hint > old_n) {
    		const size_type n = next_size(num_elements_hint);//找出下一个质数
    		
    		if (n > old_n) { //old_n不是质数表里面的最大值时,才可扩展
    			vector<node*, A> tmp(n, (node*)0);//设立新的bucket vector,大小为n
    			try {
    				//以下处理每一个旧的bucket
    				for (size_type bucket = 0; bucket < old_n; ++bucket) {
    					node* first = buckets[bucket];//指向节点所对应之串行(链表)的起始节点
    					while (first) {//处理单个bucket中的链表
    						size_type new_bucket = bkt_num(first->val, n);//找出节点落在哪一个新的bucket内
    						buckets[bucket] = first->next;//令旧bucket指向其所对应的链表的下一个节点,以便迭代处理
     
    						/*下面将当前节点插入到新的bucket内,成为其对应链表的第一个节点,这里的实现比较巧妙
    						相当于插入新节点到新bucket vector中,新插入的元素插入到链表的首位置,这里不同于一般的插入的是,
    						由于之前已有元素占据空间,这里只是修改节点指针指向*/
    						first->next = tmp[new_bucket];
    						tmp[new_bucket] = first;
     
    						first = buckets[bucket];//回到旧bucket所指的待处理链表,准备处理下一个节点
    						                        //first = old_first->next;
    					}
    				}
    				buckets.swap(tmp);//vector::swap 新旧两个buckets 对调(浅修改)
    				/*对调两方如果大小不同,大的会变小,小的会变大,离开时释放local tmp 的内存*/
    			}
    			catch (...) {
    				for (size_type bucket = 0; bucket < tmp.size(); ++bucket) {
    					while (tmp[bucket]) {
    						node* next = tmp[bucket]->next;
    						delete_node(tmp[bucket]);
    						tmp[bucket] = next;
    					}
    				}
    				throw;
    			}
    		}
    	}
    }
     
    /*插入元素,不允许重复*/
    template <class V, class K, class HF, class Ex, class Eq, class A>
    pair<hashtable<V, K, HF, Ex, Eq, A>::iterator, bool>
    hashtable<V, K, HF, Ex, Eq, A>::insert_unique_noresize(const value_type& obj)
    {
    	const size_type n = bkt_num(obj);//定位bucket
    	node* first = buckets[n];
     
    	/*判断插入元素是否有重复*/
    	for (node* cur = first; cur; cur = cur->next)
    	if (equals(get_key(cur->val), get_key(obj)))
    		return pair<iterator, bool>(iterator(cur, this), false);
     
    	node* tmp = new_node(obj);//产生新节点 node_allocator::allocate()
    	/*先插入节点放在链表最前面*/
    	tmp->next = first;
    	buckets[n] = tmp;
    	++num_elements;//元素个数增加
    	return pair<iterator, bool>(iterator(tmp, this), true);
    }
     
    /*插入元素,允许重复*/
    template <class V, class K, class HF, class Ex, class Eq, class A>
    hashtable<V, K, HF, Ex, Eq, A>::iterator
    hashtable<V, K, HF, Ex, Eq, A>::insert_equal_noresize(const value_type& obj)
    {
    	const size_type n = bkt_num(obj);//定位bucket
    	node* first = buckets[n];//链表头节点
     
    	for (node* cur = first; cur; cur = cur->next)
    	if (equals(get_key(cur->val), get_key(obj))) {//如果插入元素是重复的(与cur->val重复)
    		node* tmp = new_node(obj);
    		tmp->next = cur->next;//新增元素插入重复元素的后面
    		cur->next = tmp;
    		++num_elements;
    		return iterator(tmp, this);
    	}
    	//没有重复,等同于insert_unique_noresize()
    	node* tmp = new_node(obj);
    	tmp->next = first;
    	buckets[n] = tmp;
    	++num_elements;
    	return iterator(tmp, this);
    }                                                                                                                                                         
    

    五 总结

    核心就是hash函数和冲突处理。
    放几个觉得好的文章连接,老文章了。
    STL源码分析
    深度探索 STL

    展开全文
  • c++ 哈希表

    2020-10-26 11:10:00
    文章目录前言一、什么是哈希/散列...但是unordered_map和unordered_set的效率是O(1),而它的底层原理就是哈希表 一、什么是哈希/散列? 构造一种存储结构,通过某种函数使元素的存储位置与它的关键码之间能够建立一一映


    前言

    在学习完map和set后,我们会惊讶于它的效率O(logn)。
    但是unordered_map和unordered_set的效率是O(1),而它的底层原理就是哈希表

    一、什么是哈希/散列?

    构造一种存储结构,通过某种函数使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)

    二、什么是哈希冲突?如何解决

    不同关键字通过相同哈希哈数计算出相同的哈希地址,会导致哈希冲突

    1.开放定制法(闭散列)

    1. 线性探测
      线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
    2. 二次探测
      找下一个空位置的方法为: = ( + )% m,或者: = ( - )% m。其中:i = 1,2,3…, 是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,m是表的大小

    2.拉链法(开散列)

    开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

    三、如果哈希表中冲突得很厉害怎么办?

    1.​控制负载因子
    ​2.使用拉链法,如果一个冲突链到达一定长度,就不用链表,转换成红黑树

    四、unordered_map和unordered_set跟map/set的区别?

    一个底层是哈希表,时间复杂度O(1),遍历出来无序

    ​一个是红黑树,时间复杂度O(logN) ,遍历出来有序

    map和set是双向迭代器,unordered_map和unordered_set是单向迭代器

    总结

    应用链地址法处理溢出,需要增设链接指针,似乎增加了存储开销。事实上: 由于开地址法必须保持大量的空闲空间以确保搜索效率,如二次探查法要求装载因子a <= 0.7,而表项所占空间又比指针大的多,所以使用链地址法反而比开地址法节省存储空间。

    面试题:

    给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中?
    解决方案:
    1.排序,二分查找
    2.set/unordered_set(红黑树/哈希表)存起来再查找
    以上方案的问题:数据量太大,放不到内存(16G)
    那么解决方法是:位图,高效且节省空间 (500M)

    展开全文
  • 这意味着我们需要时刻留意哈希表的尺寸以及当前表中已有的元素数量。因为一旦哈希表中有太多元素,也将很难找到可用的位置来存放我们新插入的元素,因此这里我们需要引入一个重要的术语,负载系数(Load Factor)负载...

    开放寻址是其中一种缓解散列冲突的编程技术,当使用开放寻址作为冲突解决技术时,键值对存储在表(数组)中,而不是像单独链表那样的数据结构中。这意味着我们需要时刻留意哈希表的尺寸以及当前表中已有的元素数量。因为一旦哈希表中有太多元素,也将很难找到可用的位置来存放我们新插入的元素,因此这里我们需要引入一个重要的术语,负载系数(Load Factor)

    负载系数

    4e4286bc17493b8ae6f14ae425984721.png


    其实就是表中已有元素个数和表尺寸的比例,我们要密切关注这个系数的是因为哈希表的O(1)恒定时间行为假设负载因子k保持一定的固定值,这意味着一旦k>阈值,我们就需要增加表的大小(理想情况下是指数增长,例如,两倍)

    517b898d56cdeb4e6334a45e1eec71dd.png


    在上图中,你会看到有两种缓解冲突的方法,即单独链表和线性探测(Linear Probing),在开放寻址(线性探测)技术看来,一旦达到某个阀值,它的时间复杂度就会呈现指数级恶化的趋势

    当我们想要将键值对插入哈希表时,我们对键进行哈希处理并获得该键值对所属位置的原始位置。如果我们的键被散列到的位置被占用(此时出现了冲突),对于开放寻址来说,同一个位置中不允许有两个键的,这不是数组的工作方式,我们要做的是使用一个探测序列函数(Probing Seque Function) 这里简称p(x),因为我们已从散列函数获取了冲突点的所在位置,现在我们使用p(x)进行探测直到在沿途发现一个空闲的位置为止

    探测函数

    您可以提出无限数量的探测序列,这里仅提及一些常见的探测函数:

    • 线性探测(Linear Probing):p(x)= kx + b其中a,b是常数
    • 二次探测(Quaratic Probing):p(x)= ax ^ 2 + bx + c,其中a,b,c是常数
    • 双重散列(Double Hashing):p(k,x)= x * h(k),其中h(k)是辅助s散列函数
    • 伪随机数发生器(Pseudo Random Number Generator): p(k,x)= x*RNG(h(k),x)其中RNG是以H(k)作为种子的随机数生成器函数

    本篇仅介绍线性探测函数进行线性探测,因此给定输入参数x,当我们进行探测时,我们通常会将变量x初始化为0或1作为一个起点,如果我们找不到空闲的位置,会依次将x增加1,对以上所有这些探测函数都是一样的

    开放寻址的通用算法

    接下来,这是一个通用的开放寻址插入算法,假设我们有一个表的尺寸为n,开放寻址算法首先会初始化变量x=1,因为x是一个变量,我们要用它来探测,每当我们未能到达闲置的位置时,都需要递增x,然后我们通过散列函数获得keyHash,而实际上我们首先要查看表的索引,当表索引被占用意味着它不为空,那么新索引就是我们散列的最初位置(keyHash所指向的起始索引)加上探测函数的总和再于表尺寸N取模运算得到整数,由于我们总是回到表里,在循环中要递增x。下一次当我们在不同的位置探测时,在while循环中,最终我们会找到一个空闲的位置

    x=1keyHash=h(k)index=keyHashwhile table[index]!=NULL:      index=(keyHash+p(k,x)) mod N      x=x+1insert(k,v,index) 

    死循环地狱(Chaos with Cycle)

    由于我们知道负载系数被控制在一定的范围内,所以这里有个问题,就是开放寻址中的探测函数存在缺陷--死循环地狱,以表尺寸N为模的大多数随机选择的探测序列将产生比表大小N更短的循环。当您尝试插入一个键-值对并且循环中的所有存储桶都被占用时,这将成为灾难性问题,因为您将陷入无限循环,这在一些老外谈及哈希表的相关文章中有一个非常有趣的昵称叫死循环地狱(Chaos with Cycle)

    为了生动说明什么叫死循环地狱,我们这里看一个例子,这里有一个尺寸为12的哈希表,并且使用开放寻址插入了一些键值对,,该哈希表已经部分填充。 占用的单元格填充有键值对(Ki,Vi)和带有空令牌Φ的空单元格,如下图所示

    7002536b795afe4966059f7707786b97.png

    假设我们使用探测序列函数p(x)=4x,并且在表中插入一个新的键值对,并且该键值对的散列值为8,即h(x)=8这意味着我们会在索引8的位置插入该键值对,但是该位置已被占用,因为这里已经有简直对(k5,v5),所以我们该怎么办呢?接下来,我们需要进行探测,所以我们计算: index=h(k)+p(1)=8+4 mod 12=0

    此时,如下图,此时探测函数会跳转到索引为0的位置,糟糕的是索引1的位置也被占用了,因为(k1,v1)已经存在.

    a78a462e9e581b904abb5dc9cd3cc92b.png
    • 当x=2时,即index=h(k)+p(2)=(8+8) mod 12=4,探测函数会跳跃到索引4的位置,同样这里也是被占用的,如此类推
    • 当x=3时,即index=h(k)+p(3)=(8+12) mod 12=8,p(x)跳跃到索引8的位置,该位置被占用
    • 当x=4时,即index=h(k)+p(4)=(8+16) mod 12=0,p(x)跳跃到索引0的位置,该位置被占用
    • 当x=5时,即index=h(k)+p(5)=(8+20) mod 12=4,p(x)跳跃到索引4的位置,该位置被占用
      .....

    这样尽管我们具有探测函数,但这种特定的情况下它一直在一个死循环里面一直做一些毫无意义的事情。

    由这个例子我们可知探测函数存在缺陷,他们产生的周期短于表的尺寸,因此,我们要如何处理产生小于表大小的周期的探测功能?一般来说,一致的看法是我们不处理这个问题,相反,我们通过将探测函数的范围限制在那些产生长度为N的循环的函数上来避免这个问题,我们选择的那些产生的周期正好为N的探测函数,并且这些探测函数确实存在。

    线性探测、二次探测和双重散列等技术都受到死循环地狱问题的影响,这就是为什么与这些方法一起使用的探测函数非常特殊的原因。这是一个很大的话题,将是接下来几篇文章会重点讲述这些,我们目前需要做的是重新定义非常具体的探测函数,这些函数会产生一个循环长度为表尺寸N,并且避免无法插入元素或陷入无限循环

    注意,开放寻址对使用的哈希函数和探测函数非常敏感。如果使用单独的链接作为冲突解决方法,则不必担心此问题。

    小结

    我们本篇用一个反例生动地介绍了开放寻址插入算法的底层是由探测函数和散列函数相互作用的结果,同时我们也介绍了一些探测函数的固有缺陷,就是死循环地狱,下一篇我们会详细讨论线性探测函数的原理,敬请期待。


    链接:https://www.jianshu.com/p/b8c47701dd07

    展开全文
  • C++哈希表的实现

    2021-01-23 21:22:15
    C++哈希表的实现前言源码如下: 前言 本篇文章为笔者的读书笔记,未经允许请勿转载。如果对你有帮助记得点个赞(●’◡’●) 本文主要讲的哈希表的创建和使用, 源码如下: main #include <iostream> #...
  • c/c++ 哈希表 hashtable

    2018-08-15 06:54:00
    c/c++ 哈希表 hashtable 概念:用key去查找value 实现hash函数有很多方法,本文用除留余数法。 除留余数法的概念: 取一个固定的基数的余数,注意不能用偶数,用偶数的话,分布会不均匀 发生冲突时,用链地址法解决 ...
  • 哈希表,Hash table,也叫散列表,是根据关键字值(key)直接进行访问的数据结构,它通过把关键字值映射到表中一个位置(数组下标)来直接访问,以加快查找关键字值的速度,这个映射函数叫做哈希函数,存放记录的数组...
  • C++哈希表用法

    千次阅读 2019-08-31 11:08:18
    hash用法,记得几个关键的, 引入 #include 定义 unordered_map, string> unomap; 引入的时候可以定义初始化,例如 unordered_map,string> unomap ={{1,"dd"},{2,"ssss"}}; 打印查找: ...
  • C++标准库中使用的unordered_map底层实现是哈希表,关于哈希表的一些基础知识,我看了公众号代码随想录里面的推文:《关于哈希表,你该了解这些!》,有了基本的认识。 哈希表是什么:哈希表是根据关键码的值而直接...
  • 目录:常用数据结构及其复杂度特点常用题型总结最近刷的是leetcode关于哈希表的tag,不过个人还是建议不找官方提供的tag刷,一下子200多道,全刷是受不了,可以直接去网上找汇总的题名,题的质量往往更高。...
  • 一般哈希 ... // 向哈希表中插入一个数 void insert(int x) { int k = (x % N + N) % N; e[idx] = x; ne[idx] = h[k]; h[k] = idx ++ ; } // 在哈希表中查询某个数是否存在 bool find(int x) {
  • C++ 哈希表的原理

    2021-01-15 15:01:56
    Hash也称为散列、哈希。 其基本的原理就是把任意长度的输入、通过Hash算法变成固定长度的输出。 这个映射的规则就是对应的Hash算法,而原始数据映射后的二进制串就是哈希值 比如常用加密方式:MD5和SHA都是Hash算法...
  • C++ 哈希表 排序整数

    2020-03-21 11:44:48
    #include<stdio.h> int main() { int random[10] = { 999,1,444,7,20,9,1,3,7,7 }; int hasp_map[1000] = { 0 }; for (int i = 0;... sizeof(random) / sizeof(random[0]);... hasp_map[random[...
  • c++ 哈希表(hash表)

    2019-09-24 05:54:41
    Hash,也称散列表。一般应用于有大量“动态”的插入(删除)和查找操作的一类问题。(如果是“静态”的,通常可以先对数据排序,查找时就可以用“二分查找”) 虽然可以用“平衡树”之类方法,但实践中,用hash...
  • C++ 哈希表产生冲突

    2020-03-21 12:51:11
    #include<stdio.h> #include<string> int int_func(int key, int table_len) { return key % table_len; } int string_func(std::string str, int table_len) { int sum = 0; ......

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,239
精华内容 895
关键字:

c++哈希表

c++ 订阅