哈希表的分类,创建,查找 以及相关问题解决

本文深入探讨哈希表的基本概念、分类与应用场景,包括字符哈希、排序哈希、链式哈希,并通过实际代码演示哈希表的创建、查找及解决冲突的方法。同时,文章还介绍了STL map的使用,并提供了多个哈希相关的编程题解决方案。

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

总体的hash学习导图如下:
在这里插入图片描述

定义
  1. 需要拥有关键字 key
  2. 维护一个key和value的映射关系,哈希函数
  3. 最终的hash表拥有直接通过key访问值的能力
分类
字符hash
/*count letters*/
void hash_char() {
	int char_map[128] = {0};
	string s = "aabbbcddeh";

	for (int i = 0;i < s.length(); ++i) {
		char_map[s[i]] ++;
	}

	for (int i = 0;i < 128; ++i) {
		if (char_map[i] > 0) {
			printf("[%c] [%d]\n",i,char_map[i]);
		}
	}
}
排序hash
void hash_sort() {
	int arr[] = {1,100,2,6,998,532,40};
	int hash_arr[999] = {0};

	for (int i = 0;i < 7; ++i) {
		hash_arr[arr[i]] ++;
	}

	for (int i = 0;i < 999; i++) {
		if (hash_arr[i] > 0) {
			cout << i << endl;
		}
	}
}
链式hash(解决hash冲突)
创建链式hash
struct HashNode
{
	int data;
	struct HashNode *next;
	HashNode(int x):data(x),next(NULL){}
};

int get_key(int key, int tabel_len) {
	return key % tabel_len;
}

void insert_hash(HashNode *hash_table[], HashNode *node, int tabel_len) {
	int key = get_key(node -> data, tabel_len);
	node ->next = hash_table[key];
	hash_table[key] = node ;
}
查找指定数值
int get_key(int key, int tabel_len) {
	return key % tabel_len;
}

bool search(HashNode *hash_table[], int value, int tabel_len) {
	int key = get_key(value,tabel_len);
	HashNode *head = hash_table[key];
	while(head) {
	    if (head -> data == value) {
	    	return true;
	    }
	    head = head -> next;
	}
	return false;
}
STL map(hash)
void stl_hash() {
	std::map<string, int> map;
	string a[3] = {"aaa","ssss","ddd"};
	map[a[0]] = 1;
	map[a[1]] = 100;
	map[a[2]] = 301;

	cout << "stl hash_table is " << endl;
	for (std::map<string, int>::iterator it = map.begin(); it != map.end(); it ++) {
		cout << "[" << it -> first.c_str() << "] :" << it -> second << endl; 
	}

	if (map.find(a[1]) != map.end()) {
		cout << "sss is in the stl map "  << map[a[1]]<< endl;
	}
}
哈希分类 完整测试代码
#include <iostream>
#include <vector> 
#include <string>
#include <map>
#include <stdio.h>

using namespace std;

struct HashNode
{
	int data;
	struct HashNode *next;
	HashNode(int x):data(x),next(NULL){}
};

/*count letters*/
void hash_char() {
	int char_map[128] = {0};
	string s = "aabbbcddeh";

	for (int i = 0;i < s.length(); ++i) {
		char_map[s[i]] ++;
	}

	for (int i = 0;i < 128; ++i) {
		if (char_map[i] > 0) {
			printf("[%c] [%d]\n",i,char_map[i]);
		}
	}
}

void hash_sort() {
	int arr[] = {1,100,2,6,998,532,40};
	int hash_arr[999] = {0};

	for (int i = 0;i < 7; ++i) {
		hash_arr[arr[i]] ++;
	}

	for (int i = 0;i < 999; i++) {
		if (hash_arr[i] > 0) {
			cout << i << endl;
		}
	}
}

int get_key(int key, int tabel_len) {
	return key % tabel_len;
}

void insert_hash(HashNode *hash_table[], HashNode *node, int tabel_len) {
	int key = get_key(node -> data, tabel_len);
	node ->next = hash_table[key];
	hash_table[key] = node ;
}


bool search(HashNode *hash_table[], int value, int tabel_len) {
	int key = get_key(value,tabel_len);
	HashNode *head = hash_table[key];
	while(head) {
	    if (head -> data == value) {
	    	return true;
	    }
	    head = head -> next;
	}
	return false;
}

void stl_hash() {
	std::map<string, int> map;
	string a[3] = {"aaa","ssss","ddd"};
	map[a[0]] = 1;
	map[a[1]] = 100;
	map[a[2]] = 301;

	cout << "stl hash_table is " << endl;
	for (std::map<string, int>::iterator it = map.begin(); it != map.end(); it ++) {
		cout << "[" << it -> first.c_str() << "] :" << it -> second << endl; 
	}

	if (map.find(a[1]) != map.end()) {
		cout << "sss is in the stl map "  << map[a[1]]<< endl;
	}
}

int main(int argc, char const *argv[])
{
	cout << "hash_char" << endl;
	hash_char();
	cout << "hash_sort" << endl;
	hash_sort();

	const int TABEL_LEN = 11;
	HashNode *hash_table[TABEL_LEN] = {0};
	std::vector<HashNode *> hash_node_vec;
	int test[8] = {1,100,2,6,998,532,40,1};

	for (int i = 0;i < 8; ++i) {
		hash_node_vec.push_back(new HashNode(test[i]));
	}

	for (int i = 0;i < hash_node_vec.size(); ++i) {
		insert_hash(hash_table,hash_node_vec[i],TABEL_LEN);
	}
	cout << "hash_table" << endl;
	for (int i = 0;i < TABEL_LEN; ++i) {
		printf("[%d] ",i);
		HashNode *head = hash_table[i];
		while(head) {
		    printf("-> %d", head->data);
		    head = head -> next;
		}
		printf("\n");
	}

	cout << endl;
	for (int i =0;i < 10; ++i) {
		if (search(hash_table, i, TABEL_LEN)) {
			printf("%d is in the hash_table\n",i);
		} else {
			printf("%d is not int the hash_table\n",i);
		}
	}

	stl_hash();
	return 0;
}

输出如下:

hash_char
[a] [2]
[b] [3]
[c] [1]
[d] [2]
[e] [1]
[h] [1]
hash_sort
1
2
6
40
100
532
998
hash_table
[0] 
[1] -> 1-> 100-> 1
[2] -> 2
[3] 
[4] -> 532
[5] 
[6] -> 6
[7] -> 40
[8] -> 998
[9] 
[10] 

0 is not int the hash_table
1 is in the hash_table
2 is in the hash_table
3 is not int the hash_table
4 is not int the hash_table
5 is not int the hash_table
6 is in the hash_table
7 is not int the hash_table
8 is not int the hash_table
9 is not int the hash_table
stl hash_table is 
[aaa] :1
[ddd] :301
[ssss] :100
sss is in the stl map 100
应用(常见题目)
1. 回文字符串(Longest Palindrome)

问题如下:
已知一个只包括大小写字符的 字符串,求用该字符串中的字符可以生 成的最长回文字符串长度。
例如 s = “abccccddaa”,可生成的 最长回文 字符串长度为 9,如 dccaaaccd、 adccbccda、 acdcacdca等,都是正确的。

代码实现如下:

#include <iostream>
#include <vector> 
#include <string>
#include <map>
#include <stdio.h>

using namespace std;

/*
已知一个只包括大小写字符的 字符串,求用该字符串中的字符可以生 成的最长回文字符串长度。
例如 s = “abccccddaa”,可生成的 最长回文 字符串长度为 9,如 dccaaaccd、 adccbccda、 acdcacdca等,都是正确的。
*/

int max_count_palindrome(string s) {
	if (s.length() == 0) {
		return 0;
	}

	int hash_table[128] = {0};
	int max_count = 0;
	int flag = 0;
	for (int i = 0; i < s.length(); ++i) {
		if ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')) {
			hash_table[s[i]] ++;
		} else {
			return -1;
		}
	}

	for (int i = 0;i < 128; ++i) {
		if (hash_table[i] > 0 ) {
			if(hash_table[i] % 2 == 0) {
				max_count += hash_table[i];
			} else {
				max_count += hash_table[i] - 1;
				flag = 1;
			}
		}
	}

	return max_count + flag;
}

int main(int argc, char const *argv[])
{
	string s;
	cin >> s; 
	cout << max_count_palindrome(s) << endl;
	return 0;
}

输出如下:

abccccddaabb
11
2. 词语模式(Word Pattern)

问题描述如下:

已知字符串pattern与字符串str,确认str是否与pattern匹配。
str与pattern匹配代表字符 串str中的单词与pattern中的字符一一对应。(其中pattern中只包含小写字符,str中
的单词只包含小写字符,使用空格分隔。) 例如,
pattern = “abba”, str = “dog cat cat dog” 匹配.
pattern = “abba”, str = “dog cat cat fish” 不匹配.
pattern = “aaaa”, str = "dog cat cat dog"不匹配.
pattern = “abba”, str = "dog dog dog dog"不匹配.

实现如下:

#include <iostream>
#include <vector> 
#include <string>
#include <map>
#include <stdio.h>

using namespace std;

/*
已知字符串pattern与字符串str,确认str是否与pattern匹配。
str与pattern匹配代表字符 串str中的单词与pattern中的字符一一对应。(其中pattern中只包含小写字符,str中
的单词只包含小写字符,使用空格分隔。) 例如,
pattern = “abba”, str = “dog cat cat dog” 匹配. 
pattern = “abba”, str = “dog cat cat fish” 不匹配. 
pattern = "aaaa", str = "dog cat cat dog"不匹配. 
pattern = "abba", str = "dog dog dog dog"不匹配.
*/

bool judge_word_partten(string partten, string str) {
	if ((partten.length() == 0 && str.length() != 0)  || (str.length() == 0)) {
		return false;
	}

	std::map<string, char> hash_table;
	int used[128] = {0};
	str.push_back(' ');
	int i = 0;
	int j = 0;
	string tmp = "";
	cout << partten << " " << str << endl;
	for(int j = 0;j < str.length(); ++j){
		if (str[j] == ' ') {
			if (hash_table.find(tmp) == hash_table.end()) {
				if (used[partten[i]]) {
					return false;
				}
				used[partten[i]] = 1;
				hash_table[tmp] = partten[i];
			} else {
				if (hash_table[tmp] != partten[i]) {
					return false;
				}
			}
			tmp = "";
			i++;
		} else {
			tmp += str[j];
		}
	}

	if (i != partten.length()) {
		return false;
	}
	return true;
}

int main(int argc, char const *argv[])
{
	/* code */
	string partten = "abba";
	string str = "dog cat cat do";

	cout << judge_word_partten(partten,str) << endl;
	return 0;
}

输出如下:

abba 
dog cat cat do 
0

abba 
dog cat cat dog 
1
3. 同字符词语分组(Group Anagrams)

问题描述:
已知一组字符串,将所有anagram(由颠倒字母顺序而构成的 字)放到一起输出。
例如:[“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] :[“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
返回:[ [“ate”, “eat”,“tea”], [“nat”,“tan”], :[ [“ate”, “eat”,“tea”], [“nat”,“tan”],[“bat”] ]

实现如下:

#include <iostream>
#include <vector> 
#include <string>
#include <map>
#include <algorithm>
#include <stdio.h>

using namespace std;

/*
已知一组字符串,将所有anagram(由颠倒字母顺序而构成的 字)放到一起输出。
例如:["eat", "tea", "tan", "ate", "nat", "bat"] :["eat", "tea", "tan", "ate", "nat", "bat"]
返回:[ ["ate", "eat","tea"], ["nat","tan"], :[ ["ate", "eat","tea"], ["nat","tan"],["bat"] ]
*/

/*map 建立 string to vector<sting> 的存储映射*/
std::vector<std::vector<string>> get_group_anagrams(std::vector<string> &str) {
	std::map<string, std::vector<string> > hash_table;
	string tmp;
	std::vector<std::vector<string>> result;

	for (int i = 0;i < str.size(); ++i){
		tmp = str[i];
		sort(tmp.begin(), tmp.end());
		if (hash_table.find(tmp) != hash_table.end()) {
			hash_table[tmp].push_back(str[i]);
		} else {
			std::vector<string> item;
			item.push_back(str[i]);
			hash_table[tmp] = item;
		}
	}

	std::map<string, std::vector<string> >::iterator it = hash_table.begin();
	for (;it != hash_table.end(); ++it) {
		result.push_back(it->second);
	}

	return result;
}

int main(int argc, char const *argv[])
{
	/* code */
	std::vector<string> str;
	for (int i = 0;i < 6; ++i) {
		string tmp;
		cin >> tmp;
		str.push_back(tmp);
	}

	std::vector<std::vector<string> > result = get_group_anagrams(str);
	for (int i = 0;i < result.size(); ++i) {
		for (int j = 0;j < result[i].size(); ++j) {
			cout << "[" << result[i][j] << " ] ";
		}
		cout << endl;
	}
	return 0;
}

输出如下:

ate eat tea tan nat bat
[bat ] 
[ate ] [eat ] [tea ] 
[tan ] [nat ] 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值