线性开型寻址
由一维数组存放散列表,数组的每一项称为桶,不同的桶对应不同的关键字。
(将数组视为环形,即数组末项的后一项是数组首项)
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;//除数
};
本文介绍了散列表的两种实现方式。线性开型寻址用一维数组存放散列表,阐述了搜索、插入和删除元素的方法;链表散列则是创建链表类的数组,每个关键字对应一个链表,说明了插入和删除元素的操作。
1548

被折叠的 条评论
为什么被折叠?



