线性表(3)——哈希链表

C++实现:

Key_Value_Pair.h

#pragma once
#ifndef Key_Value_Pair_H
#define Key_Value_Pair_H
template 
class Key_Value_Pair
{
public:
	typedef Key  Key_Type;
	typedef Key& Key_Reference;
	typedef Key* Key_Pointer;
	typedef const Key& Const_Key_Reference;

	typedef Value  Value_Type;
	typedef Value& Value_Reference;
	typedef Value* Value_Pointer;
	typedef const Value& Const_Value_Reference;
public:
	Key_Type key;
	Value_Type value;

public:
	Key_Value_Pair()
	{}
	//有参构造
	Key_Value_Pair(Key_Type m_key, Value_Type m_value)
		:key(m_key), value(m_value)
	{}
	//拷贝构造
	Key_Value_Pair(const Key_Value_Pair& m_KV_Pair)
		:key(m_KV_Pair.key), value(m_KV_Pair.value)
	{}
	//重载赋值运算符
	void operator= (const Key_Value_Pair& m_KV_Pair)
	{
		key = m_KV_Pair.key;
		value = m_KV_Pair.value;
	}

};
#endif // !Key_Value_Pair_H

Single_Link_List_Node.h

#pragma once
#ifndef SINGLE_LINK_LIST_NODE
#define SINGLE_LINK_LIST_NODE

template 
class Single_Link_List_Node
{
public:
	typedef T  Value_Type;
	typedef T* Value_Pointer;
	typedef T& Value_Reference;
	typedef const T& Const_Value_Reference;
	typedef Single_Link_List_Node  Node;
	typedef Single_Link_List_Node*  Node_Pointer;
	typedef const Single_Link_List_Node&  Const_Node_Reference;
	typedef Single_Link_List_Node* Next_Pointer;
	typedef Node* Node_Pool;

private:
	static  Node_Pool node_Pool;  //声明为static变量,让所有对象共享
public:
	Value_Type value;   //结点存储的值
	Next_Pointer next;  //结点保存的指向下一个结点的指针

	//结点构造函数,创建结点,对应C语言实现的create函数
	Single_Link_List_Node(Const_Value_Reference m_value, Next_Pointer m_next = nullptr)
		:value(m_value), next(m_next)
	{
	}
	//默认构造函数
	//为头指针,尾指针,当前指针的定义提供不用没有值的构造方法
	Single_Link_List_Node(Next_Pointer m_next = nullptr)
	{}

	//重载new运算符
	void* operator new(size_t)
	{
		//内存池中没有申请到结点内存时,调用全局的new申请内存直接返回
		if (node_Pool == nullptr)
			return ::new Node;
		//内存池中有结点时
		Node_Pointer temp = node_Pool;
		//从内存池中申请后,内存池中结点减少,即内存池首地址的指向下一个结点区域
		node_Pool = node_Pool->next;
		return temp;
	}

	//重载delete运算符
	void operator delete(void* free_node)
	{
		//释放结点内存直接将结点释放到内存池中

		//每释放一个都插入到内存池的头部
		//让释放的结点指向内存池首地址
		((Node_Pointer)free_node)->next = node_Pool;
		//让内存池的首地址指向释放的结点
		node_Pool = (Node_Pointer)free_node;
	}

	bool operator==(Const_Node_Reference node)
	{
		if (value == node.value && next == node.next)
			return true;
	}
};
//类的静态变量的初始化
template 
Single_Link_List_Node* Single_Link_List_Node::node_Pool = nullptr;
#endif 

Single_Link_List.h

#pragma once
#include "Single_Link_List_Node.h"
#include 
#include 

template 
class Single_Link_List
{
public:
	typedef Single_Link_List_Node  Node;
	typedef Single_Link_List_Node* Node_Pointer;
	typedef Single_Link_List_Node* Head_Type;
	typedef Single_Link_List_Node* Tail_Type;
	typedef Single_Link_List_Node* Current_Type;
	typedef T Value_Type;
	typedef const T&  Const_Value_Reference;
private:
	Head_Type head;
	Tail_Type tail;
	Current_Type curr;
	int list_Length;

	//初始化的函数,只用于此类,不提供对外接口
	void init()
	{
		head = tail = curr = new Node;
		list_Length = 0;
	}

	void removeAll()
	{
		while (head != nullptr)
		{
			curr = head;
			head = head->next;
			delete curr;
		}
	}

	//满足某种异常条件,抛出异常,打印错误信息
	void judge_OutOfRange(bool condition, const std::string& printInfo)
	{
		try
		{
			if (condition)
			{
				throw condition;
			}
		}
		catch (bool)
		{
			std::cerr << printInfo << std::endl;   //为什么不要在.h文件中使用using namespace std?
			exit(1);
		}
	}
public:
	Single_Link_List()
	{
		init();
	}
	~Single_Link_List()     //这里析构函数其实还是虚函数,因为它的父类是
	{
		removeAll();
	}

	void clear() 
	{
		removeAll();
		init();
	}


	//Single_Link_List(const Single_Link_List& list)
	//{
	//	init();
	//}
	//默认删除和插入操作都是对当前结点的下一个结点操作,这样写方便操作
	void insert(Const_Value_Reference value) 
	{
		Node* temp = curr->next;
		curr->next = new Node;			//使用operator new分配内存
		::new(curr->next)Node(value, temp);
		if (curr == tail)				//记得判断尾节点的特殊情况
			tail = curr->next;
		list_Length++;
	}

	void append(Const_Value_Reference value) 
	{
		tail->next = new Node(value, nullptr);
		tail = tail->next;
		list_Length++;
	}

	Value_Type remove() 
	{
		//判断链表是否为空
		judge_OutOfRange((curr->next == nullptr), "Link_List is none!");

		Value_Type remove_value = curr->next->value;

		//移除一个结点:让当前结点的下一个结点的指针,指向下一个结点的下一个结点,同时释放当前下一个结点
		Node* temp = curr->next;
		if (tail == curr->next)
			tail = curr;
		curr->next = curr->next->next;
		delete  temp;
		list_Length--;

		return remove_value;
	}

	void prev() 
	{
		if (curr == head)
			return;
		Node* temp = head;
		while (temp->next != curr)
			temp = temp->next;
		curr = temp;
	}

	void next() 
	{
		if (curr != tail)
			curr = curr->next;
	}

	int length() const
	{
		return list_Length;
	}

	Const_Value_Reference getValue()  
	{
		//判断链表是否为空
		judge_OutOfRange((curr->next == nullptr), "Link_List is none!");

		return curr->next->value;
	}

	int currPos()const 
	{
		Node* temp = head;
		int i;
		for (i = 0; temp != curr; i++)
		{
			temp = temp->next;
		}
		return i;
	}

	void moveToPosition(int position) 
	{
		if(list_Length!=0)
			judge_OutOfRange((position < 0 || position >= list_Length), "Position is out of range!");
		curr = head;
		for (int i = 0; i < position; i++)
			curr = curr->next;
	}



	Current_Type getCurr()
	{
		return curr->next;
	}
};

Hash_Link_Table.h

#pragma once           
#ifndef HASH_TABLE_H
#define HASH_TABLE_H
#include 
#include "Single_Link_List_Node.h"
#include "Single_Link_List.h"
#include "Key_Value_Pair.h"

#define DEFAULT_SIZE 10
template
class HashTable
{
public:
	typedef Value* Value_Pointer;
	typedef Value& Value_Reference;
	typedef const Value& Const_Value_Reference;

	typedef int Key;
	typedef int* Key_Pointer;
	typedef int& Key_Reference;
	typedef const int& Const_Key_Reference;

	typedef Single_Link_List_Node>* Return_Node_Pointer;
	typedef Single_Link_List_Node>* Next_Pointer;
	typedef Single_Link_List> List;
	typedef Single_Link_List_Node> Node;
	typedef Single_Link_List_Node>* Node_Pointer;
	typedef Single_Link_List_Node>* Curr_Node;
	typedef Key_Value_Pair Key_Value_Pair;
private:
	int array_Size;     //数组的长度
	List* list_Array;   //链表数组
	int size;    //元素个数

	Curr_Node curr;

	//哈希函数:根据key值来计算索引,定位Hash桶的位置
	int hash_function(int key)
	{
		return key % array_Size;
	}
public:
	//创建哈希链表
	HashTable(int size=DEFAULT_SIZE)
	{
		array_Size = size;
		list_Array = new List[array_Size];

	}

	//插入
	void insert(Key key,Value value)
	{
		int isExist = find(key);

		if (isExist==0)
		{
			//新建一个结点
			List *temp = &list_Array[hash_function(key)];
			Key_Value_Pair* temp_Pair = new Key_Value_Pair(key, value);
			temp->insert(*temp_Pair);
			size++;
		}
		else
		{
			std::cout << "待插入的值已经存在于哈希表中";
		}
	}

	//删除
	Value remove(Key key)
	{
		int isExist = find(key);

		if (isExist==1)
		{
			
			List *temp_List = &list_Array[hash_function(key)];
			Key_Value_Pair temp_Pair=temp_List->remove();
			size--;
			return temp_Pair.value;
		}
		else
		{
			std::cout << "待删除的结点不在哈希表中" << std::endl;
		}
	}

	//查找
	int find(Key key)
	{
		List *temp_List = &list_Array[hash_function(key)];
		//找了很久的Bug:

		//List temp_List = list_Array[hash_function(key)];
		//在初始化的时候我从内存池中申请的空间给list_Array[hash_function(key)]的,
		//结果这里局部变量temp_List在函数执行完的时候,调用了析构函数,把它释放了
		//分析原因:当我没有写拷贝构造函数时,这里进行了浅拷贝,
		          //List的head,tail,curr只是进行了赋值,仍然和原对象指向相同的地址
		//解决方法:将局部对象的定义该成指针,就不会在析构的时候调用析构函数

		temp_List->moveToPosition(0);
		for (int i = 0; i < temp_List->length(); i++)
		{
			Key_Value_Pair temp_Pair =temp_List->getValue();
			if (temp_Pair.key == key)
			{
				curr = temp_List->getCurr();
				return 1;
			}	
		}
		return 0;
	}

	Value getValue()
	{
		return (curr->value).value;
	}

	//遍历打印
	void print()
	{
		for (int i = 0; i < array_Size; i++)
		{
			for (int j = 0; j < list_Array[i].length(); j++)
			{
				list_Array[i].moveToPosition(j);
				std::cout << list_Array[i].getValue().value << std::endl;
			}
		}
	}

	int length()
	{
		return size;
	}
};
#endif

main.cpp

#include "Hash_Link_Table.h"
#include 
#include
using namespace std;

typedef int Postion;
int main()
{
	string names[4]= { "TuCheng","Lily","YanWanli","CaiLinjin" };

	
	HashTable hashTable;

	cout << "测试insert,find,getValue" << endl;
	hashTable.insert(0,names[0]);
	hashTable.insert(1,names[1]);
	hashTable.insert(2,names[2]);
	hashTable.insert(3,names[3]);

	for (int i = 0; i < 6; i++)
	{
		int temp= hashTable.find(i);
		if (temp==1)
			cout << hashTable.getValue() << endl;
		else
			cout << "你查找的值不存在!" << endl;
	}

	cout << "\n测试length" << endl;
	cout << "哈希表中元素的个数为:" << endl;
	cout << hashTable.length() << endl;

	cout << "\n遍历哈希表打印每一个元素" << endl;
	hashTable.print();

	cout << "\n测试remove" << endl;
	hashTable.remove(2);
	cout << "\n哈希表中元素的个数为:" << endl;
	cout << hashTable.length() << endl;
	cout << "\n遍历哈希表打印每一个元素" << endl;
	hashTable.print();
}

运行结果:

线性表(3)——哈希链表_第1张图片

你可能感兴趣的:(数据结构与算法)