哈希表查找(C语言实现)

本文介绍了一种使用电话键盘对应的字母组合来生成特定数字串所对应的可能字符串的方法,并通过回溯法结合哈希表查找的方式,在给定的字典中找出所有匹配的字符串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
 * 题目:给定一个全部由字符串组成的字典,字符串全部由大写字母构成。其中为每个字符串编写密码,编写的
 *       方式是对于 n 位字符串,给定一个 n 位数,大写字母与数字的对应方式按照电话键盘的方式:
 *         2: A,B,C     5: J,K,L    8: T,U,V
 *         3: D,E,F     6: M,N,O    9: W,X,Y,Z
 *         4: G,H,I     7: P,Q,R,S
 * 题目给出一个1--12位的数,找出在字典中出现且密码是这个数的所有字符串。字典中字符串的个数不超过5000。
 *        
 * 思路:1.回溯法找出所有可能的字符串
 *       2.在字典中查找此字符串是否存在。(字典存储采用哈希表存储) 
 *
 */

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

#define HASHTABLE_LENGTH 5001  //哈希表长度
#define STRING_LENGTH   13     //单词最大长度

//字符串
typedef struct
{
	char str[STRING_LENGTH];
	int length;
}HString;

HString string={'\0',0};             //暂存可能的字符串
HString hashTable[HASHTABLE_LENGTH]; //哈希表

//hash函数,构造哈希表
void createHashTable(char *str)
{
	int i,key,step=1;
	i=key=0;
	while(str[i]){
		key+=str[i++]-'A';
	}
	key%=HASHTABLE_LENGTH;
	while(1){
		if(hashTable[key].length==0){
			hashTable[key].length=strlen(str);
			strcpy(hashTable[key].str,str);
			break;
		}
		key=(key+step+HASHTABLE_LENGTH)%HASHTABLE_LENGTH;
		//处理冲突,线性探测再散列
		if(step>0)
    		step=-step;
		else{
			step=-step;
			step++;
		}
	}
}

//从文件中读字典
void readString()
{
	int i;
	char str[STRING_LENGTH];
	char ch;
	FILE *fp;
    if((fp=fopen("document/dictionary.txt","r"))==NULL){   
       printf("can not open file!\n");   
       exit(0);   
    }  
	
    i=0;
    while((ch=getc(fp))!=EOF){   
        if(ch=='\n'){//读完一个字符串
			str[i]='\0';
            createHashTable(str);
			i=0;
			continue;
		}
		str[i++]=ch;
	}

    if(fclose(fp)){   
        printf("can not close file!\n");   
        exit(0);   
    }   
}

//在哈希表中查找是否存在该字符串,存在返回1,不存在返回0
int search(char *str)
{
	int i,key,step=1;
	i=key=0;
	while(str[i]){
		key+=str[i++]-'A';
	}
	key%=HASHTABLE_LENGTH;
	while(1){
		if(hashTable[key].length==0)
			return 0;
		if(strcmp(hashTable[key].str,str)==0){
			return 1;
		}
		key=(key+step+HASHTABLE_LENGTH)%HASHTABLE_LENGTH;
		//处理冲突,线性探测再散列
		if(step>0)
    		step=-step;
		else{
			step=-step;
			step++;
		}
	}
	return 0;
}

//求所有可能的字符串
void getString(char* num)
{
	int i,digit,max;
	if(*num==0){//递归出口,字符串已到末尾
		string.str[string.length]='\0';
        if(search(string.str))//这个字符串存在于字典中,输出
			puts(string.str);
		return;
	}

	digit=*num-'0';//取第一位字符,转成数字
	if(digit>=2&&digit<=6){
		i=(digit-2)*3+'A';
		max=(digit-2)*3+'A'+3;
	}
	else if(digit==7){
		i='P';
		max='P'+4;
	}
	else if(digit==8){
		i='T';
		max='T'+3;
	}
	else if(digit==9){
		i='W';
		max='W'+4;
	}

	for(i;i<max;i++){
		string.str[string.length++]=i;
        getString(num+1); //递归
		string.length--;
	}
}

void main()
{
	char num[STRING_LENGTH];   //由于输入的数字超出了unsigned long的范围,所以用字符串来存储
	readString();              //把字典从文件中读入内存
    printf("please inputer an number(1--12位,不能有0或1)\n");
    scanf("%s",num);
	getString(num);
}


 

### 哈希表在C语言中的实现方法及代码示例 以下是一个完整的哈希表实现示例,使用链地址法来解决冲突。此实现基于静态数组和链表结构,适用于存储字符串键值对。 #### 数据结构定义 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define HASH_TABLE_SIZE 101 // 哈希表大小为101[^1] // 定义哈希表节点结构体 typedef struct nlist { struct nlist *next; // 指向下一个节点的指针 char *name; // 键(字符串) char *defn; // 值(字符串) } NLIST; // 哈希表数组 NLIST *hashtab[HASH_TABLE_SIZE]; // 初始化哈希表 void initialize_hashtable() { for (int i = 0; i < HASH_TABLE_SIZE; i++) { hashtab[i] = NULL; } } // 计算哈希值的函数 unsigned hash(const char *key) { unsigned hashval = 0; while (*key != '\0') { hashval = *key++ + 31 * hashval; } return hashval % HASH_TABLE_SIZE; } // 查找键是否已存在 NLIST *lookup(const char *key) { NLIST *np; unsigned hashval = hash(key); for (np = hashtab[hashval]; np != NULL; np = np->next) { if (strcmp(key, np->name) == 0) { return np; } } return NULL; } // 插入键值对到哈希表 NLIST *install(const char *name, const char *defn) { NLIST *np; unsigned hashval; if ((np = lookup(name)) == NULL) { // 如果键不存在 np = (NLIST *)malloc(sizeof(*np)); if (np == NULL || (np->name = strdup(name)) == NULL) { return NULL; } hashval = hash(name); np->next = hashtab[hashval]; hashtab[hashval] = np; } else { // 如果键已经存在,替换其值 free((void *)np->defn); // 释放旧值 } if ((np->defn = strdup(defn)) == NULL) { return NULL; } return np; } // 打印哈希表内容 void print_hashtable() { for (int i = 0; i < HASH_TABLE_SIZE; i++) { NLIST *np = hashtab[i]; if (np != NULL) { printf("Index %d: ", i); while (np != NULL) { printf("%s -> %s ", np->name, np->defn); np = np->next; } printf("\n"); } } } ``` #### 主函数示例 ```c int main() { initialize_hashtable(); // 初始化哈希表 // 插入一些键值对 install("apple", "fruit"); install("banana", "yellow fruit"); install("carrot", "vegetable"); // 打印哈希表内容 print_hashtable(); // 查找某个键 NLIST *result = lookup("banana"); if (result != NULL) { printf("Found: %s -> %s\n", result->name, result->defn); } else { printf("Not found\n"); } return 0; } ``` #### 关键点解释 - **哈希函数**:通过计算字符串的 ASCII 值及其倍数来生成哈希值,并将其映射到固定范围的索引上[^1]。 - **链地址法**:当发生哈希冲突时,将多个键值对存放在同一个链表中。 - **动态内存分配**:使用 `malloc` 和 `strdup` 动态分配内存以存储键和值。 #### 注意事项 - 在实际应用中,需要考虑内存泄漏问题,确保释放所有分配的内存。 - 哈希表的大小应根据具体需求调整,过大或过小都会影响性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值