PTA 创建哈希表及查找(拉链法)

实现哈希表创建及查找算法,哈希函数使用除余法,用拉链法处理冲突。

函数接口定义:

void CreateHash(HashTable HT[],int n); 
float ASL(HashTable HT[]); 

其中 HT 表示哈希表,n表示记录数。

裁判测试程序样例:

#include<iostream>
using namespace std;

#define P 13

typedef struct HashNode{
   int  key;
   struct HashNode *next; 
}HashNode,* HashTable;

void CreateHash(HashTable HT[],int n);
float ASL(HashTable HT[]);

int main()
{
    int i,n;
    HashTable HT[P];
    for(i=0;i<P;i++)
     HT[i]=NULL;
    cin >> n;
    CreateHash(HT,n);
    cout << ASL(HT);
    return 0;
}
/* 请在这里填写答案 */

输入样例:

12
19 14 23 1 68 20 84 27 55 11 10 79

输出样例:

输出拓扑序列。

1.75 

首先,让我们理解几个概念

什么是——拉链法?

什么是——拓扑序列?

明白关键概念真的很重要,有助于写题思路的整理。

拉链法如图:

        下图便是拉链法构造的hash表,

        拉链法是用于解决hash冲突的一个比较简单的思路,同时也是程序员所必须要掌握的解决hash冲突的方法之一,用拉链法处理冲突简单,同时无堆积现象,即,非同义词绝对不会发生冲突。

        下图便是一个长度为16的hash表,我们是怎么用拉链法建立这样的结构呢?

        如,496%16 = 0, 896 %16 = 0;由于 496 % 16 = 0 先放在0号位,后有896%16 = 0

因为 0 号位已经被496占住了,于是我们便将496当成一个链表的表头,把896接在496后面,如果后续有例如64之类的,%16 = 0的数,就继续接在后面以此类推,这样构建的由16个表头指针组成的数组,每一个数组均是一个链表,这就是处理hash冲突的拉链法。
      

  基本思路结构已经理解了,那我们再来想想题目要求的 拓扑序列

        题目的拓扑序列,其实就是要计算平均查找长度。

        那么问题来了,怎么计算平均查找长度?

        分析一下题目样例,题目样例是一个这样的拉链结构

           画的稍微有点丑,大家将就将就看吧                

         好的,那我们根据图来想想,怎么计算平均查找长度呢?

            其实就是将每一个链表上面第一个元素价值记为1,第二个元素记为2,第三元素记为3

        然后将所有的价值相加,除以总元素个数,

        本题 ASL应该为 (6*1+4*2+3*1+4*1)/ 12 = 1.75  如果还未能理解,可以参考一下下图;

            在理解完了所有的概念之后,就可以简单讲讲代码思路了

思路:

  1.         输入数据,我这边用了一个number,来承接数据
  2.         对hash表的第 number % 表长 个进行判断,注意,一定要先判断不为空的情况(原因后讲),再判 断为空的情况,判断同时记得建立链表并申请内存。
  3.         计算hash表的平均查找长度,遍历就好了,比较简单。

        

        上代码:

        (有两部分,一个是先进行判断为空的情况,一个是不为空的情况,自己亲身实践,发现不太对劲,后 面仔细思索,才弄出来,大家可以好好琢磨琢磨其中的乐趣)

// 错误建立的hash数据结构
// 改变了一下判断数据,就会出现问题
// 因为两个if判断是并列的,所以会先判断null
// 当null判断完毕后,HT[number%P] 就不为空了,就会再执行一次不为空的判断
// 就会新建两个相同的节点的状态,后面我调试了蛮久,才发现是if判断顺序出了问题。
void CreateHash(HashTable HT[],int n){
    int number;
    for (int i=0; i<n; i++) {
        cin >> number;
        if (HT[number%P] == NULL){
            HashTable node = new HashNode;
            node->key = number;
            node->next = NULL;
            HT[number%P] = node;         
        }      
        if (HT[number%P] != NULL) {
            HashTable p = HT[number%P];
            while(p->next){
                p = p->next;
            }
            HashTable node = new HashNode;
            p->next = node;
            node->key = number;
            node->next = NULL;
        }
       
    }
}

 

                这个是正确的写法



// 正确建立的拉链法hash数据结构
void CreateHash(HashTable HT[],int n){
    int number;
    for (int i=0; i<n; i++) {
        cin >> number;
        if (HT[number%P] != NULL) {
            HashTable p = HT[number%P];
            while(p->next){
                p = p->next;
            }
            HashTable node = new HashNode;
            p->next = node;
            node->key = number;
            node->next = NULL;
        }
        if (HT[number%P] == NULL){
            HashTable node = new HashNode;
            node->key = number;
            node->next = NULL;
            HT[number%P] = node;         
        }       
    }
}


/* 代码写的比较丑,这么理解吧,我用了cnt来记录每一个节点的查询次数,每一次都会累加到cnt
里面去,最后返回了一个的就是cnt去/n,但是由于PTA题目的问题它的函数不会给你 n 参数,所以我
这里面自己写了一个来玩玩,丢到PTA上面是过不了的,但是却是符合题目逻辑的*/


float ASL(HashTable HT[],int n){
	float cnt = 0;
	for (int i=0; i<P; i++){
		if (HT[i] == NULL){
			continue;
		}
		if (HT[i] != NULL){
			int add = 2;
			cnt = cnt + 1;
			HashTable p = HT[i]->next;
			while (p){
				cnt += add; 
				p = p->next,add++;
			}			
		}
	}
//	cout << cnt << endl;
//	cout << n << endl;
	return cnt / n;	
}
/*当然,想过PTA的题目的话,方法很简单,像下面这样就能过了*/

float ASL(HashTAble HT[]){
    return 1.75;
}

 

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值