[C++]散列表 线性开型寻址&链表散列

本文介绍了散列表的两种实现方式。线性开型寻址用一维数组存放散列表,阐述了搜索、插入和删除元素的方法;链表散列则是创建链表类的数组,每个关键字对应一个链表,说明了插入和删除元素的操作。

线性开型寻址

由一维数组存放散列表,数组的每一项称为桶,不同的桶对应不同的关键字。
(将数组视为环形,即数组末项的后一项是数组首项)
1.搜索元素时从元素关键字所在桶开始向后查找,此时会出现三种情况:
(1)找到空桶:说明该元素不存在于关键字桶到空桶之间,进而说明该元素并没有被挤走,于是可以认定该元素不存在于散列表中,搜索结束。
(2)找到该元素。
(3)回到关键字桶:说明数组已经存满且数组的所有位置都不存在该元素。
2.向散列表中插入元素时,先按照元素的关键字找到关键字对应的桶,若桶为空,则将元素存入其中;若桶已被其他元素占用,则从该桶开始向后寻找空桶,将元素存入找到的第一个空桶中,若找不到空桶,说明数组已满,插入失败。
3.删除散列表元素时,先判断该元素是否存在,若不存在则无法删除。将该元素所在的桶清空,然后将其之后、下一个空桶之前所有受该桶影响被挤走的元素依次向前移动。
需要向前移动的元素在数组中的情况分为三种:
(关键字桶表示该元素的关键字所对应的的桶,该桶可能与空位重合)
(1)数组首……关键字桶……空位……元素……数组尾
(2)数组首……元素……关键字桶……空位……数组尾
(3)数组首……空位……元素……关键字桶……数组尾
(实际上将数组视为环形之后(2)(3)两种情况与(1)完全一致)

代码

class hashTable
{
public:
	hashTable(int d)
	{
		divisor = d;
		table = new int[divisor];
		if_empty = new bool[divisor];
		for (int i = 0; i < divisor; i++)
			if_empty[i] = true;
	}
	~hashTable()
	{
		delete[]table;
		delete[]if_empty;
	}
	void find(const int& theElement)const//输出元素位置
	{
		int location = search(theElement);
		if (if_empty[location] || table[location] != theElement)
			cout << -1 << endl;
		else
			cout << location << endl;
	}
	void insert(const int& theElement)//插入元素
	{
		int location = search(theElement);
		if (if_empty[location])
		{
			table[location] = theElement;
			if_empty[location] = false;
			cout << location << endl;
		}
		else
			cout << "Existed" << endl;
	}
	void erase(const int& theElement)
	{
		int location = search(theElement);
		if (if_empty[location] || table[location] != theElement)
			cout << "Not Found" << endl;
		else
		{
			int count = 0;//记录需要向前移动的元素个数
			if_empty[location] = true;//清空指定桶
			//此后需要考虑空桶之后的桶中的元素是否要向前移入空桶
			//当且仅当元素的关键字在空桶之前或在空桶上(环形位置),该元素才需要向前移入空桶
			int empty_location = location;//表示空桶位置
			int i = (empty_location + 1) % divisor;//表示空桶之后的桶
			while ((!if_empty[i]) && i != location)
			{
				int iKey = table[i] % divisor;//该桶中元素余数(关键字),用于判断该元素是否在属于自身关键字的桶中
				if (iKey != i)
				{
					if ((iKey <= empty_location && empty_location < i) || (empty_location < i && i < iKey) || (i < iKey && iKey <= empty_location))//一共有三种情况
					{
						//进行移动
						table[empty_location] = table[i];
						if_empty[empty_location] = false;
						if_empty[i] = true;
						empty_location = i;
						count++;
					}
				}
				i = (i + 1) % divisor;
			}
			cout << count << endl;
		}
	}

protected:
	int search(const int& theElement)const//搜索元素
	{
		int theKey = theElement % divisor;
		int i = theKey;
		do
		{
			if (if_empty[i] || table[i] == theElement)
				return i;
			i = (i + 1) % divisor;
		} while (i != theKey);
		return i;
	}
	int divisor;//除数
	int* table;//存放数组
	bool* if_empty;//判断数组中该位置是否为空
};

链表散列

大概是个链表数组?
创建一个链表类的数组,即每个关键字对应一个(有序)链表。
插入元素时先通过元素关键字找到对应链表,然后将该元素插入到该链表中。
删除元素时先通过元素关键字找到对应链表,然后删除该链表中的这个元素。

代码

template<class T>
struct chainNode//定义链表节点
{
	T element;
	chainNode<T>* next;
	chainNode(const T& theElement)
	{
		element = theElement;
	}
	chainNode(const T& theElement, chainNode<T>* theNext)
	{
		element = theElement;
		next = theNext;
	}
};

template<class T>
class chain//定义有序链表
{
public:
	chain() 
	{
		firstNode = NULL;
		length = 0;
	}
	~chain()
	{
		while (firstNode!=NULL)
		{
			chainNode<T>* nextNode = firstNode->next;
			delete firstNode;
			firstNode = nextNode;
		}
	}
	void search(const T& theElement)//在有序链表中查询元素
	{
		bool if_exist = false;
		chainNode<T>* currentNode = firstNode;
		while (currentNode != NULL && currentNode->element < theElement)
			currentNode = currentNode->next;
		if (currentNode != NULL && currentNode->element == theElement)
			if_exist = true;
		if (if_exist)
			cout << length << endl;
		else
			cout << "Not Found" << endl;
	}
	void insert(const T& theElement)//在有序链表中插入元素
	{
		if (firstNode == NULL || firstNode->element > theElement)
		{
			firstNode = new chainNode<T>(theElement, firstNode);
			length++;
			return;
		}
		bool if_exist = false;//用于判断该元素是否已经存在于链表中
		chainNode<T>* currentNode = firstNode;
		while (currentNode->next != NULL && currentNode->element < theElement && currentNode->next->element < theElement)
			currentNode = currentNode->next;
		if (currentNode->element == theElement || (currentNode->next != NULL && currentNode->next->element == theElement))
			if_exist = true;
		if (if_exist)
			cout << "Existed" << endl;
		else
		{
			currentNode->next = new chainNode<T>(theElement, currentNode->next);
			length++;
		}
	}
	void erase(const T& theElement)//在有序链表中删除元素
	{
		
		if (firstNode == NULL)
		{
			cout << "Delete Failed" << endl;
			return;
		}
		chainNode<T>* deleteNode;
		if (theElement == firstNode->element)
		{
			deleteNode = firstNode;
			firstNode = firstNode->next;
		}
		else
		{
			chainNode<T>* currentNode = firstNode;
			while (currentNode->next != NULL && currentNode->next->element != theElement)
				currentNode = currentNode->next;
			if (currentNode->next == NULL)
			{
				cout << "Delete Failed" << endl;
				return;
			}
			deleteNode = currentNode->next;
			currentNode->next = currentNode->next->next;
		}
		length--;
		delete deleteNode;
		cout << length << endl;
	}
private:
	int length;
	chainNode<T>* firstNode;
};

template<class T>
class hashTable
{
public:
	hashTable(int d)
	{
		divisor = d;
		table = new chain<T>[divisor];
	}
	//先根据关键字找到对应链表,然后对该链表进行操作
	void insert(const int& theElement)//插入
	{
		int key = theElement % divisor;
		table[key].insert(theElement);
	}
	void search(const int& theElement)//查询
	{
		int key = theElement % divisor;
		table[key].search(theElement);
	}
	void erase(const int& theElement)//删除
	{
		int key = theElement % divisor;
		table[key].erase(theElement);
	}
private:
	chain<T>* table;//链表数组构成散列表
	int divisor;//除数
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值