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

本文介绍了散列(Hashing)的基本思想,包括通过散列函数确定关键词存储位置和解决冲突的方法。具体实现中,采用分离链接法解决冲突,并使用除留余数法构造散列函数。文章还提供了一段C++代码,用于统计打电话次数最多的人,展示了散列在处理数据记录中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

散列(Hashing)的基本思想:

 

 

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

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

 

 

完整代码如下:

 

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

 

 

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

 

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

散列函数:除留余数法。

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

//#include "stdafx.h"
#include <iostream>
#include <string.h>
#include <math.h>
#include <stdlib.h>

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 T>
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 <class T> Table<T>::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);
	}
}

//返回大于size的最小素数
template <class T> int Table<T>::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 <class T> int Table<T>::Hash(int KeyNum)
{
	//除留余数法
	return KeyNum % TableSize;
}

//散列查找
template <class T> ListNode Table<T>::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 <class T> bool Table<T>::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 <class T> void Table<T>::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 <class T> Table<T>::~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<char> H(N);

	H.Print();

	return 0;
}

 

运行结果:

 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值