散列表(拉链式和线性探测)

无论是顺序查找还是二分查找(包括二叉树),查找或插入的时间复杂度总会与数据的总数N有关,而散列表可以将查找和插入操作降低到常数级别。

最简单的一种常数级别的符号表,就是直接将数据的键值作为数组的索引,通过键值就可以立即访问到数据,时间复杂度为1.但是这种方法有一个缺点就是键值的分布并不是平均的,而且跨度可能会很大,这样就会导致数组中很多空间被浪费了。

而散列表就是解决了这个缺点,将键值映射到均匀分布的一定范围内的索引值。而在映射的过程中,由于键值的不均匀分布,必然会出现不同键值映射到同一索引的情况(即碰撞),所以还要进行碰撞处理,常用的有拉链式线性探测等

1.拉链式

顾名思义,就是把产生碰撞的数据按顺序排成链表,先通过映射找到所在链表,然后再在链表中查找数据。

除了映射处理,主要的时间都是花在链表查找上,所以链表越短查找越快,但是空间占用也越大,所以根据实际情况作平衡处理。另一方面,链表的平均长度=数据量N/链表数量M,因此应当尽量保证每条链表的长度差不多,那么就要使用更加均匀的映射函数

我这里使用的是C++自带的hash函数,再按链表数M取余。即:

	std::hash<int> h;
	int h_val=h(key)%_chainNum;

拉链式散列表的声明:

class SeparateChainingHashST
{
public:
	SeparateChainingHashST(int chainNum);//指定链表数目
	~SeparateChainingHashST();
	void put(int key, int val);
	ChainNode* get(int key);
	void showChains();//所有链表打印出来

private:
	void deleteAllNodes(ChainNode* head);//删除链表头为head的所有节点
	inline unsigned int  hash(int key);//计算哈希值(小于链表数)

private:
	int _chainNum;
	NodePoniter *_chainHeads; //存放链表头的数组
	std::hash<int> _h;//用来计算hash码
};

具体实现:

SeparateChainingHashST::SeparateChainingHashST(int chainNum)
{
	_chainNum=chainNum;
	_chainHeads=new NodePoniter[chainNum];//新建一个数组来存放链表的头
	for(int i=0;i<chainNum;i++)//将所有链表头初始化为空指针
		_chainHeads[i]=nullptr;
}

unsigned int SeparateChainingHashST::hash(int key)
{
//	std::hash<int> h;
	return _h(key)%_chainNum;
}

void SeparateChainingHashST::put(in
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值