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

数据结构与算法分析——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[N][LEN];
getRandStr(s,N);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值