刷题笔记31——利用哈希表设计RandomPool结构

题目描述

设计一种结构,在该结构中有如下三个功能:

  1. insert(key):将某个key加入到该结构,做到不重复加入。
  2. delete(key):将原本在结构中的某个key移除。
  3. getRandom():等概率随机返回结构中的任何一个key。

要求:Insert、delete和 getRandom方法的时间复杂度都是 O(1)

思路

这个结构与哈希表的区别在于get的是key而不是value。
另外有一个getRandom函数,要严格等概率地返回结构中的任何一个key。

而只用一个哈希表并不能做到等概率地随机返回任何一个key。
因为哈希表中每个桶里挂着一些链,这些链的长度并不是严格相等的,只是差不多相等。在数量较少时甚至有些桶里链的长度是0。

于是可以设置两个map和一个size成员,map1对应keytoindex,map2对应indextokey

  • 添加记录时,如26个字母做记录按顺序进哈希表,最终哈希表的逻辑结构可能是这样的
    表示A是第0个进来的,B是第1个进来的。。。Z是第25个进来的。
    在这里插入图片描述
  • 而在删除记录时,用随机洗牌的思想,每次都是将待删除的记录与最后一个记录进行交换,再删除最后一个记录并且将size减1。这样表就是连续的了。

如果不洗牌的话,在删除记录时中间会产生一个空洞,这样记录就不是连续的了。考虑极端的情况,当这个洞特别大,如果哈希表中没有这个记录,就会继续rand,那要rand很久,肯定不是O(1)的了。

在这里插入图片描述

测试结果及代码

在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <string>
#include <math.h>
#include <map>
using namespace std;

template<typename T>
class RandomPool {
public:
	RandomPool() : _size(0) { }

	void add(T key) {
		if (key2index.count(key))
			return;
		key2index[key] = _size;
		index2key[_size] = key;
		_size++;
	}
	
	T getRandom() {
		int index = rand() % _size;	// rand() -> [0, _size)
		return index2key[index];
	}

	void Delete(T key) {
		if (key2index.count(key)) {
			int deleteIndex = key2index[key];
			int lastIndex = _size - 1;
			T lastKey = index2key[lastIndex];
			key2index[lastKey] = deleteIndex;
			index2key[deleteIndex] = lastKey;
			key2index.erase(key);
			index2key.erase(lastIndex);
			_size--;
		}
	}

private:
	map<T, int> key2index;
	map<int, T> index2key;
	int _size;
};

int main(int argc, char* argv[]){
	RandomPool<string> pool;
	pool.add("dzh");
	pool.add("abc");
	pool.add("123");
	cout << pool.getRandom() << endl;
	cout << pool.getRandom() << endl;
	cout << pool.getRandom() << endl;
	cout << pool.getRandom() << endl;
	cout << pool.getRandom() << endl;
	cout << pool.getRandom() << endl;

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值