Registro de erro:
1. Os dois códigos a seguir são equivalentes, embora eu não entenda muito bem
char Data[KEYLENGTH+1];
//与
typedef char ElementType[KEYLENGTH + 1];//不十分理解
ElementType Data;
2. Conversão de tipo
para (i = (int) sqrt (q); i> 2; –i) {// sqr usado incorretamente Outro: Por que usar protótipo de função q de dupla precisão: double sqrt (double x);
aqui está OK Fale sobre os pequenos pontos de conhecimento da conversão de tipo. Quando a função é chamada, a declaração forçará a conversão de tipo dos parâmetros. Portanto, também é possível usar o inteiro p como um argumento aqui, mas executei duas vezes e encontrei que é usado diretamente O tempo de execução do programa em p é o dobro do tempo de uso da variável q. (Não sei por quê)
3. if (p% i == 0) break; //% só pode ser usado para operações inteiras,% é o operador de resto, que só pode ser usado para operações inteiras e inteiras, se usado Para operações não inteiras, o programa relatará um erro e fará com que ele falhe ao ser executado.
4. H-> Heads = (PtrToLNode) malloc (H-> TableSize * sizeof (struct LNode));
// Este é um array dinâmico, H-> Heads é o primeiro endereço do array dinâmico, e os elementos no array são struct LNode, pensei erroneamente que os elementos do array dinâmico aplicado eram variáveis de ponteiro.
5. H-> TableSize = NextPrime (TableSize); // uso incorreto TableSize = NextPrime (TableSize)
O objetivo aqui é atribuir um valor ao membro TableSize da tabela hash H, mas esqueci de escrever H.
6. p [i] é igual a * (p + i), ambos são os objetos apontados pelo ponteiro p, e (p + i) é um ponteiro, para usar o operador ->
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') {// errado usado if (* Key! = '\ 0')
Escrevi incorretamente enquanto como se, passei nos primeiros dois testes, e o terceiro atingiu o tempo limite. A chave aqui está um ponteiro, a ordem de operação de * Key ++, a prioridade do operador de endereçamento indireto e o operador de incremento 1 são dois, mas a direção da combinação é a combinação certa, então é na verdade equivalente a * (Key ++), então está certo O ponteiro é incrementado em um.
9. P = H-> Cabeças [h]. Próximo;
// usado incorretamente P = H-> Cabeças + h Este é o desempenho de não compreender a estrutura de dados da tabela hash, o nó principal na tabela hash não armazenamento de dados
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;
}