您的位置:首页 > 其它

如果我们刚刚计算出“excel”的散列函数,那么我们就不必再从头开始计算“excel”的散列函数。调整散列函数使得它能够利用前面的计算

2016-05-16 21:37 621 查看
数据结构与算法分析——c语言描述 练习5.13 c 答案

前面几道单独的习题的组合。虽然没什么新意,思路一看就懂。但我竟然写了4个小时!!!!!!!!!

下午写的时候插入单词没问题,4重循环外面找单词没问题,但循环里面找就不行了。里面我也没修改散列表啊,只用了find函数,根本没修改。找不到问题,晚上重新写,想了半小时还是觉得下午的思路没错,并且是最好的。改一下变量名,完善一下代码格式规范竟然好了。。。。

1.代码规范要好,我原本枚举里面的类型是用小写的,后来改成大写bug就自动消失了。。。。。

2.指定长度的字符串(mystrcmp)比较要考虑全面。一个bug就是这个问题出现的。现象是init空间太小就会把前缀改成单词。就是这个函数没写好。使以为前面插入的前缀和现在插入的单词以为是相同的。

思考再写代码。切记切记。不要盲目使用printf大法,printf的是人品。。。。

输入的是课本上开始的例子

4 4
this
two
fat
that
this
wats
oahg
fgdt


hashQuad.h

enum KindOfStr { PREFIX, WORD };

struct ElementType {
char *str;
enum KindOfStr infoOfStr;
};

#ifndef _HashQuad_H
#define _HashQuad_H

typedef unsigned int Index;
typedef Index Position;

struct HashTbl;
typedef struct HashTbl* HashTable;

HashTable initializeTable(int tableSize);
void destroyTable(HashTable h);
Position find(const char *s, int len, HashTable h);
HashTable insert(char *s, int len, KindOfStr infoOfStr, HashTable h);
HashTable rehash(HashTable h);
ElementType retrive(Position p, HashTable h);
int isLegitimate(Position pos, HashTable h);
HashTable insertWord(char *word,HashTable h);
#endif


#include"hashQuad.h"
#include"fatal.h"
#include<math.h>
#include<string.h>
#define MinTableSize 10

enum KindOfEntry { Legitimate, Empty, Deleted };

struct HashEntry {
ElementType element;
enum KindOfEntry info;
};

typedef struct HashEntry Cell;

struct HashTbl {
int tableSize;
int hasInsertedNum;
Cell *theCells;//数组
};

static int hash(const char * key, int len, int tableSize) {
unsigned int hashVal = 0;
while (len--)
hashVal = (hashVal << 5) + *key++;
return hashVal % (tableSize);
}
static int isPrime(int num) {
for (int i = 2; i <= sqrt(num); i++)
if (num%i == 0)
return 0;
return 1;
}
static int nextPrime(int num) {
int i = num;
while (!isPrime(i))
i++;
return i;
}

static int mystrcmp(char *s1, const char *s2, int len) {
while (len&& *s1 != '\0'&& *s2 != '\0') {
if (*s1 != *s2)
return *s1 - *s2;
s1++;
s2++;
len--;
}
if (!len)
return *s1 - '\0';//指定s2的长度(少于实际长度),结束的时候当然是用假设的'\0',s1可能比s2长,相等
return 1;//s1比s2短,不相等
}

static void mystrcpy(char *s1, char *s2, int len) {
while (len--) {
*s1 = *s2;
s1++;
s2++;
}
*s1 = '\0';
}

int isLegitimate(Position pos, HashTable h) {
return h->theCells[pos].info == Legitimate;
}

static HashTable insert(char *s, int len, enum KindOfStr info, HashTable h, unsigned int *hashRecord) {
if ((double)h->hasInsertedNum / h->tableSize > 0.5)
h = rehash(h);

Position currentPos;
*hashRecord = ((*hashRecord) * 32 + *(s + len - 1));
currentPos = (*hashRecord) % h->tableSize;
while (h->theCells[currentPos].info != Empty && mystrcmp(h->theCells[currentPos].element.str, s, len) != 0) {
currentPos = (currentPos + 1) % h->tableSize;
}

if (h->theCells[currentPos].info != Legitimate) {
h->theCells[currentPos].element.str = (char *)malloc(sizeof(char)*len + 1);
mystrcpy(h->theCells[currentPos].element.str, s, len);
h->theCells[currentPos].element.infoOfStr = info;
h->theCells[currentPos].info = Legitimate;
h->hasInsertedNum++;
}
else {// 存在相同的字符串
if (h->theCells[currentPos].element.infoOfStr == PREFIX)
h->theCells[currentPos].element.infoOfStr = info;//可以直接赋值,值可能为PREFIX或WORD
}
return h;
}

HashTable insertWord(char * word, HashTable h) {
int j;
int len = strlen(word);
unsigned int hashRecord = 0;
for (j = 1; j < len; j++) {//插入前缀
h = insert(word, j, PREFIX, h, &hashRecord);
}
h = insert(word, j, WORD, h, &hashRecord);//插入单词
return h;
}

HashTable initializeTable(int tableSize) {
HashTable h;
int i;
if (tableSize < MinTableSize) {
Error("Table size too small");
return NULL;
}
h = (HashTable)malloc(sizeof(struct HashTbl));
if (h == NULL)
FatalError("Out of space!!!");
h->tableSize = nextPrime(tableSize);
h->theCells = (Cell *)malloc(sizeof(Cell)*h->tableSize);
h->hasInsertedNum = 0;
if (h->theCells == NULL)
FatalError("Out of space!!!");
for (i = 0; i < h->tableSize; i++) {
h->theCells[i].info = Empty;
}
return h;
}

void destroyTable(HashTable h) {
for (int i = 0; i < h->tableSize; i++)
if (h->theCells[i].info == Legitimate)
free(h->theCells[i].element.str);
free(h->theCells);
free(h);
}

Position find(const char *s, int len, HashTable h) {
Position currentPos = hash(s, len, h->tableSize);
while (h->theCells[currentPos].info != Empty && mystrcmp(h->theCells[currentPos].element.str, s, len) != 0) {
currentPos = (currentPos + 1) % h->tableSize;

}
return currentPos;
}

HashTable insert(char *s, int len, enum KindOfStr infoOfStr, HashTable h) {
if ((double)h->hasInsertedNum / h->tableSize > 0.5)
h = rehash(h);
Position pos = find(s, len, h);
if (h->theCells[pos].info != Legitimate) {
h->theCells[pos].element.str = (char *)malloc(sizeof(char)*len + 1);
mystrcpy(h->theCells[pos].element.str, s, len);//
h->theCells[pos].element.infoOfStr = infoOfStr;
h->theCells[pos].info = Legitimate;
h->hasInsertedNum++;
}
else {//已存在相同的字符串。若插入的是单词,存在的是前缀,改
if (h->theCells[pos].element.infoOfStr == PREFIX)
h->theCells[pos].element.infoOfStr = infoOfStr;
}
return h;
}

static HashTable insert(ElementType key, HashTable h) {
if ((double)h->hasInsertedNum / h->tableSize > 0.5)
h = rehash(h);
Position pos = find(key.str, strlen(key.str), h);
if (h->theCells[pos].info != Legitimate) {
h->theCells[pos].element.str = (char *)malloc(sizeof(char)*strlen(key.str) + 1);
strcpy(h->theCells[pos].element.str, key.str);
h->theCells[pos].element.infoOfStr = key.infoOfStr;
h->theCells[pos].info = Legitimate;
h->hasInsertedNum++;
}
return h;
}

HashTable rehash(HashTable h) {
HashTable newH = initializeTable(h->tableSize * 2);
for (int i = 0; i < h->tableSize; i++)
if (h->theCells[i].info == Legitimate)
insert(h->theCells[i].element, newH);
destroyTable(h);
return newH;
}

ElementType retrive(Position p, HashTable h) {
return h->theCells[p].element;
}


main.cpp

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include"hashQuad.h"

#define MAXN 100

#define N 1000
#define LEN 40

char dictionary[MAXN][MAXN];
char table[MAXN][MAXN];//字谜

//由上顺时针旋转一圈
int dx[8] = { 0,1,1,1,0,-1,-1,-1 };
int dy[8] = { 1,1,0,-1,-1,-1,0,1 };

int dic_num, n;

int main() {
HashTable h = initializeTable(10);//小于30出问题

scanf("%d%d", &dic_num, &n);

for (int i = 0; i < dic_num; i++) {
scanf("%s", dictionary[i]);
h = insertWord(dictionary[i], h);
}

for (int i = 0; i < n; i++) {
scanf("%s", table[i]);
}

int dirChangedCnt = 0;
printf("\n");
for (int r = 0; r < n; r++) {//行
for (int c = 0; c < n; c++) {//列
for (int d = 0; d < 8; d++) {//方向
std::string s;
int rr = r;
int cc = c;
for (int l = 1; l <= n; l++) {//长度
s += table[rr][cc];
rr += dx[d];
cc += dy[d];
Position pos = find(s.c_str(), s.length(), h);
if (isLegitimate(pos, h) && retrive(pos, h).infoOfStr == WORD)
printf("%s\n", s.c_str());
else if (!isLegitimate(pos, h)) {//找不到前缀
dirChangedCnt++;
break;//找不到,换方向
}
}
}
}
}
printf("direction has changed %d times\n", dirChangedCnt);
}


生成随机字符串,和上面的没关系,用来测试rehash时用的

#define N 1000
#define LEN 40

int randInt(int i, int j) {
int temp;
temp = (int)(i + (1.0*rand() / RAND_MAX)*(j - i));
return temp;
}

void getRandStr(char s[][LEN],int n) {
for (int i = 0; i < n; i++) {
int len = randInt(1, LEN-1);
int j;
for ( j = 0; j < len; j++)
s[i][j] = randInt(33, 126);//可打印字符的ascii区间
s[i][j] = '\0';
}
}

char s
[LEN];
getRandStr(s,N);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: