浙大慕课数据结构-11-散列1 电话聊天狂人 (25分)

错误记录:
1.以下两个代码等价吧,虽然我看不十分懂

char Data[KEYLENGTH+1];
//与
typedef char ElementType[KEYLENGTH + 1];//不十分理解
ElementType Data;

2.类型转换
for(i=(int)sqrt(q);i>2;–i){//wrong used sqr 另:为什么要使用双精度的q 函数原型:double sqrt(double x);
这里可以说一下类型转换的tiny知识点,当函数被调用时,声明将对参数进行强制类型转换,因此这里使用整型的p作为实参传入也是可以的,但是我运行了两次,发现直接使用p时程序运行时间比使用q变量的时间的两倍。(不知道为什么)
在这里插入图片描述
3. if(p%i==0) break; //%只能用于整数运算的运算符,%是求余运算符,只能适用于整数与整数运算,如果用于非整数运算,程序会报错导致无法运行。
4. H->Heads = (PtrToLNode)malloc(H->TableSize*sizeof(struct LNode));
//这是一个动态数组,H->Heads为动态数组首地址,数组中的元素为struct LNode,我当时错以为申请的动态数组中的元素是指针变量。
5. H->TableSize = NextPrime(TableSize);//wrong used TableSize = NextPrime(TableSize)
这里的目的是给哈希表H的TableSize成员赋值,但我忘记写H了。
6.p[i]与*(p+i)是相同的,都是指针p所指向的对象,而(p+i)是指针,才能使用->运算符
7.

(H->Heads+i)->Data[0] = '\0';//wrong used H->Heads[i]->Data = '\0'; 
      	//这里的Data是一个数组,还有事我没懂
      	//想不明白 这个H->Heads难道不是指针么,对他是一个指针,但是对指针加[]就相当于解引用,此时H->Heads[i]为指针指向的节点
      	H->Heads[i].Next = NULL;
      	H->Heads[i].cnt = 0;

8.while(*Key!=’\0’){//wrong used if(*Key!=’\0’)
我这里错把while写成了if,通过了前两个测试,第三个超时,这里的Key是一个指针,*Key++的运算顺序,间接寻址运算符和增1运算符的优先级都是二,但是结合方向为右结合,所以其实等价于 *(Key++),因此是对指针做增一运算。
9. P = H->Heads[h].Next;
//wrong used P = H->Heads+h这就是没懂散列表数据结构的表现,散列表中的列表头节点不存储数据

Index Hash(const char *Key,int TableSize){
  	unsigned int h=0;
    while(*Key!='\0'){//wrong used if(*Key!='\0')
      	h += (h << 5) + *Key++;//wrong used h += (Key<<5) + Key++;
    }
  	return h%TableSize;
}
#include<math.h>
#include<stdbool.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXTABLESIZE 1000000 //为啥
#define HASHNUM 5
#define KEYLENGTH 11

typedef char ElementType[KEYLENGTH + 1];//不十分理解
typedef int Index;

typedef struct LNode *PtrToLNode;
struct LNode{
    PtrToLNode Next;
    int cnt;
    ElementType Data;
};
typedef PtrToLNode Position;

//散列表节点定义
typedef struct TableNode *HashTable;//不十分理解为什么这么命名
struct TableNode{
    int TableSize;
    PtrToLNode Heads;//这是一个数组,每个节点都是LNode
};

int NextPrime(int N){
		int i,p = (N%2)? (N+2):(N+1);
  	double q = p;
  	while(q<MAXTABLESIZE){
      	for(i=(int)sqrt(q);i>2;--i){//wrong used sqr 另:为什么要使用双精度的q     double sqrt(double x);
          	if(p%i==0) break; //%只能用于整数运算的运算符,%是求余运算符,只能适用于整数与整数运算,如果用于非整数运算,程序会报错导致无法运行。
				}
      	if(i==2) break;
      	else p += 2;
    }
  	return p;
}
HashTable CreateTable(int TableSize){
  	HashTable H;
  	int i;
  	H = (HashTable)malloc(sizeof(struct TableNode));
  	H->TableSize = NextPrime(TableSize);//wrong used TableSize = NextPrime(TableSize)
  	H->Heads = (PtrToLNode)malloc(H->TableSize*sizeof(struct LNode));
  	//这是一个动态数组,H->Heads为动态数组首地址,数组中的元素为struct LNode
  	for(i=0;i<H->TableSize;++i){
      	(H->Heads+i)->Data[0] = '\0';//wrong used H->Heads[i]->Data = '\0'; 
      	//这里的Data是一个数组,还有事我没懂
      	//想不明白 这个H->Heads难道不是指针么,对他是一个指针,但是对指针加[]就相当于解引用,此时H->Heads[i]为指针指向的节点
      	H->Heads[i].Next = NULL;
      	H->Heads[i].cnt = 0;
    }
  	return H;  
}
Index Hash(const char *Key,int TableSize){
  	unsigned int h=0;
    while(*Key!='\0'){//wrong used if(*Key!='\0')
      	h += (h << 5) + *Key++;//wrong used h += (Key<<5) + Key++;
    }
  	return h%TableSize;
}
Position Find(HashTable H,ElementType Key){
  	Position P;
  	Index h;
  	h = Hash(Key+KEYLENGTH-HASHNUM,H->TableSize);//wrong used h = Hash(Key-KEYLENGTH+HASHNUM,H->TableSize)
  	P = H->Heads[h].Next;
  	//wrong used P = H->Heads+h这就是没懂散列表数据结构的表现,散列表中的列表头节点不存储数据
  	while(P && strcmp(Key,P->Data)){
      	P = P->Next;
    }  	
  	return P;
}
bool Insert(HashTable H,ElementType Key){
  	Position P,NewCell;
  	Index pos;
  	P = Find(H,Key);
  	if(!P){
      	NewCell = (PtrToLNode)malloc(sizeof(struct LNode));
      	strcpy(NewCell->Data,Key);//wrong used strcopy(NewCell->Data,Key);
      	NewCell->cnt = 1;//现在有点懵 这个cnt保存的是什么 哦想起啦了 狂人打电话次数
      	pos = Hash(Key+KEYLENGTH-HASHNUM,H->TableSize);
      	NewCell->Next = H->Heads[pos].Next;
      	H->Heads[pos].Next = NewCell;
      	return true;
    }
  	else{
      	P->cnt++;
      	return false;
    }
}
void DestroyTable(HashTable H){
  	int i;
  	PtrToLNode P,temp;
  	for(i=0;i<H->TableSize;++i){
      	P = H->Heads[i].Next;
      	while(P){
          	temp = P->Next;
          	free(P);
          	P = temp;
        }
    }
  	free(H->Heads);
  	free(H);
}
void ScanAndOutput(HashTable H){
  	int i,Mcnt=0,Pcnt=0;
  	ElementType MinPhone;
  	MinPhone[0] = '\0';//其实我不太懂为什么这样初始化
  	PtrToLNode P;
  	for(i=0;i<H->TableSize;++i){
      	P = H->Heads[i].Next;
      	while(P){
          	if(P->cnt>Mcnt){
              	Mcnt = P->cnt;
              	strcpy(MinPhone,P->Data);
              	Pcnt = 1;
            }
          	else if(P->cnt==Mcnt){
              	if(strcmp(MinPhone,P->Data)>0){
                  	strcpy(MinPhone,P->Data);
                }
              	Pcnt++;
            }
          	P = P->Next;//我竟然忘了这个
        }
    }
  	printf("%s %d",MinPhone,Mcnt);
  	if(Pcnt>1) printf(" %d",Pcnt);
  	printf("\n");
}
int main(){
  	HashTable H;
  	int i,N;
  	ElementType Key;
  	scanf("%d",&N);
  	H = CreateTable(2*N);
  	for(i=0;i<N;++i){
      	scanf("%s",Key);Insert(H,Key);
      	scanf("%s",Key);Insert(H,Key);
    }
  	ScanAndOutput(H);
	DestroyTable(H);
  	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值