查找 - 散列表(分离链接法+除留余数法)C++实现

散列(Hashing)的基本思想:

1.计算位置:构造散列函数确定关键词存储位置。

2.解决冲突:应用某种策略解决多个关键词位置相同的问题。

完整代码如下:

如下程序实现统计打电话次数最多的人

输入:通话记录的条数N。接下来输入N条记录,每条记录含有两个电话号码。

冲突解决办法:分离链接法。

散列函数:除留余数法。

//查找打电话最多的人
//冲突处理的方法:分离链接法
//哈希函数:出留余数法

//#include "stdafx.h"
#include 
#include 
#include 
#include 

using namespace std;

const int MAXD = 5;  //取电话后5位为key
const int KEYLENGTH = 11;  //电话号码的长度
const int MAXTABLESIZE = 10000;  //允许开辟的最大散列表长度

								 //链表节点定义
struct LNode
{
	char Data[KEYLENGTH + 1];  //数据域
	struct LNode* Next;  //指针域
	int Count;  //用来记录次数
};
typedef struct LNode* ListNode;

template 
class Table
{
private:
	struct LNode* Heads;  //保存指向链表头结点的数组、类似于int* A;A - 数组A
	int TableSize;  //散列表的长度

public:
	Table(int size);  //构造函数
	~Table();  //析构函数
	int Hash(int KeyNum);  //哈希函数
	ListNode Find(char key[]);  //散列查找
	bool Insert(char key[]);  //向散列表中插入数据
	void Print();  //输出电话聊天狂人
	int NextPrime(int N);  //返回大于N的最小素数
};

//Table类的实现
//构造函数
template  Table::Table(int size)
{
	char  key[KEYLENGTH+1];
	TableSize = NextPrime(size * 2);
	Heads = new LNode[TableSize * sizeof(ListNode)];  //为链表数组分配空间

													  //散列表的初始化
	for (int i = 0; i < TableSize; ++i)
	{
		Heads[i].Data[0] = '\0';
		Heads[i].Count = 0;
		Heads[i].Next = NULL;
	}
	//插入通话记录
	for (int i = 0; i < size; i++)
	{
		cin >> key; Insert(key);
		cin >> key; Insert(key);
	}
}

//返回大于size的最小素数
template  int Table::NextPrime(int N)
{
	int p, i;
	//从大于N的第一个奇数开始
	if (N % 2 == 0)
		p = N + 1;
	else
		p = N + 2;

	while (p <= MAXTABLESIZE)
	{
		for (i = (int)sqrt(p); i > 2; --i)
		{
			if (p%i == 0)  //p不是素数,break
				break;
		}
		if (i == 2) break;  //说明p是素数,while循环结束
		else
			p += 2;  //否则试探下一个奇数
	}

	return p;
}

//哈希函数
template  int Table::Hash(int KeyNum)
{
	//除留余数法
	return KeyNum % TableSize;
}

//散列查找
template  ListNode Table::Find(char  key[])
{
	int Pos;
	ListNode p;

	//计算要查找的key的哈希值
	Pos = Hash(atoi(key + KEYLENGTH - MAXD));
	//从该哈希值所对应的链表的第一个节点开始
	p = Heads[Pos].Next;
	//当未到该链表尾,并且key未找到时
	while (p != NULL && strcmp(p->Data, key))
		p = p->Next;

	return p;  //p为指向的节点或者NULL
}

//向散列表中插入数据
template  bool Table::Insert(char key[])
{
	ListNode P, NewCell;
	int Pos;

	P = Find(key);
	if (!P)  //关键词未找到,则插入该新数据
	{
		NewCell = new LNode;
		strcpy(NewCell->Data, key);
		NewCell->Count = 1;

		Pos = Hash(atoi(key + KEYLENGTH - MAXD));

		//将NewCell插到Heads[Pos]链表的头
		NewCell->Next = Heads[Pos].Next;
		Heads[Pos].Next = NewCell;

		return true;
	}
	else  //关键词以存在
	{
		P->Count++;
		return false;
	}
}

//输出电话聊天狂人
template  void Table::Print()
{
	ListNode Ptr;
	int i, MaxCnt, PCnt;
	MaxCnt = PCnt = 0;  //MaxCnt - 最多次数,PCnt个聊天狂人
	char MinPhone[KEYLENGTH+1];
	MinPhone[0] = '\0';

	for (i = 0; i < TableSize; i++)
	{
		Ptr = Heads[i].Next;
		while (Ptr)
		{
			if (Ptr->Count > MaxCnt)
			{
				MaxCnt = Ptr->Count;
				strcpy(MinPhone, Ptr->Data);
				PCnt = 1;
			}
			else if (Ptr->Count == MaxCnt)
			{
				PCnt++;  //通话狂人数加1
				if (strcmp(MinPhone, Ptr->Data) > 0)
				{
					strcpy(MinPhone, Ptr->Data);  //更新狂人的最小电话号码
				}
			}

			Ptr = Ptr->Next;
		}
	}

	cout << "电话:" << MinPhone << "最大通话次数:" << MaxCnt << endl;
	if (PCnt > 1)
		cout << "PCnt: " << PCnt << endl;
}

//析构函数,释放动态分配的内存空间
template  Table::~Table()
{
	int i;
	ListNode P, tmp;

	for (i = 0; i < TableSize; ++i)
	{
		P = Heads[i].Next;
		while (P)
		{
			tmp = P->Next;
			delete tmp;
			P = tmp;
		}
	}
}

int main()
{
	int N;
	cin >> N;

	Table H(N);

	H.Print();

	return 0;
}

运行结果:

查找 - 散列表(分离链接法+除留余数法)C++实现_第1张图片

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