//1,使用质数解决哈希表关键字的问题,26个字母对应26个质数,不同字母组合的乘积肯定不同
//2,创建一个大小为 hashSize 的二维指针作为数组,
//3,使用所有字符串的 key % hashSize 分配到数组不同的位置对应的链表中
//4,每个二维数组中元素是一个链表,链表的元素是 字符串 key, 字符串位置 pos, 下一个指针 pNext 组成
//5,将每个链表中的元素按照 key 分配,字母异位词组合 具有相同的 key 肯定在同一个链表中
//学习点
//1,质数的运用,
//2,哈希表加二维链表的运用,数据结构的定义,哈希表初始化,元素插入,最后空间释放
//3,double类型的使用,浮点型求余系统函数 fmod, float 类型数据求余 fmodf
#define HASH_SIZE 199
#define MAX_COL_SIZE 200 //相同 字母异位词的最大个数
//二维哈希链表元素定义
struct Hash_Node {
double key;
int value;
struct Hash_Node* pNext;
};
//哈希表定义
struct Hash_Table {
struct Hash_Node** pHashHead;
int iHashSize;
};
//函数一:哈希表初始化
bool hashTableInit(struct Hash_Table** pHashTable) {
*pHashTable = (struct Hash_Table*)malloc(sizeof(struct Hash_Table));
if (NULL == *pHashTable) return false;
(*pHashTable)->iHashSize = HASH_SIZE;
(*pHashTable)->pHashHead = (struct Hash_Node**)calloc(sizeof(struct Hash_Node*) , HASH_SIZE);
if (NULL == (*pHashTable)->pHashHead) return false;
return true;
}
//函数二:哈希表元素插入
bool hashTableInsert(struct Hash_Table* pHashTable, double key, int value){
int iTablePos = 0;
struct Hash_Node* pNode = NULL;
//双精度浮点数求余的系统函数 fmod
iTablePos = (int)fmod(key, (double)HASH_SIZE);
if (NULL == pHashTable->pHashHead[iTablePos])
{
pNode = (struct Hash_Node*)malloc(sizeof(struct Hash_Node));
pNode->key = key;
pNode->value = value;
pNode->pNext = NULL;
pHashTable->pHashHead[iTablePos] = pNode;
}
else
{
pNode = pHashTable->pHashHead[iTablePos];
while ((NULL != pNode) && (NULL != pNode->pNext))
{
pNode = pNode->pNext;
}
pNode->pNext = (struct Hash_Node*)malloc(sizeof(struct Hash_Node));
pNode = pNode->pNext;
pNode->key = key;
pNode->value = value;
pNode->pNext = NULL;
}
return true;
}
//函数三:将字符串数组插入哈希表中
bool pushStrsInHashTable(struct Hash_Table* pHashTable, char** strs, int strsSize){
double lKey = 1;
int primeTable[26] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101}; //质数列表分别对应26个英文字母
//a,b,c,d,e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
for (int i = 0; i < strsSize; i++)
{
lKey=1;
//计算字符串的 key, 每个字符串所有字符相乘
for(int j=0; strs[i][j] != '\0'; j++)
{
lKey *= (double)primeTable[strs[i][j] - 'a'];
}
hashTableInsert(pHashTable, lKey, i);
}
return true;
}
//函数四:利用哈希表将字符串数组中的字母异位词存入结果中
//哈希表中每一组链表中都可能保存了不同 key 的字符串,但是 字母异位词组合肯定在一个链表中
//运用双指针,pNode 外面循环,pNext 在链表后面找相同 key 值的字符串,找到之后避免pNode重复,拷贝后将 key=0
void groupAnagramsUseHash(char** strs, char*** pRet, struct Hash_Table* pHashTable, int* returnSize, int* pColumnSizes){
int i = 0;
int iCurCol = 0;
double lTmpKey = 0;
struct Hash_Node* pNode = NULL;
struct Hash_Node* pNext = NULL;
for (i = 0; i < HASH_SIZE; i++)
{
if (NULL != pHashTable->pHashHead[i])
{
pNode = pHashTable->pHashHead[i];
pNext = pNode;
while(pNode != NULL)
{
if (pNode->key == 0)
{
pNode = pNode->pNext;
pNext = pNode;
continue;
}
if (lTmpKey != pNode->key)
{
//发现一个新key则申请新的空间存结果
pRet[iCurCol] = (char**)calloc(sizeof(char*) , MAX_COL_SIZE);
iCurCol += 1;
lTmpKey = pNode->key;
}
while(pNext != NULL)
{
//将链表后所有 key 值相同的 字符串拷贝到同一层结果中,为一串字母异位词
if (pNext->key == lTmpKey)
{
pRet[iCurCol - 1][pColumnSizes[iCurCol - 1]]=strs[pNext->value];
pColumnSizes[iCurCol - 1] += 1;
pNext->key = 0;
}
pNext = pNext->pNext;
}
pNode = pNode->pNext;
pNext = pNode;
}
}
}
*returnSize = iCurCol;
return;
}
//函数五:释放哈希表空间
void freeHashTable(struct Hash_Table* pHashTable){
int i = 0;
struct Hash_Node* pNode = NULL;
struct Hash_Node* pNext = NULL;
if (pHashTable->pHashHead != NULL)
{
for (i = 0; i < HASH_SIZE; i++)
{
pNode = pHashTable->pHashHead[i];
while(pNode != NULL)
{
pNext = pNode->pNext;
free(pNode);
pNode = pNext;
}
}
free(pHashTable->pHashHead);
}
return;
}
char *** groupAnagrams(char ** strs, int strsSize, int* returnSize, int** returnColumnSizes){
int i = 0;
char*** pRet = NULL;
struct Hash_Table* pHashTable = NULL;
struct Hash_Node* pNode = NULL;
pRet = (char***)calloc(sizeof(char**) , strsSize);
*returnColumnSizes = (int *)calloc(sizeof(int) , strsSize);
//1,哈希表初始化
hashTableInit(&pHashTable);
//2,将字符串数字插入哈希表中
pushStrsInHashTable(pHashTable, strs, strsSize);
/*
for (i = 0; i < HASH_SIZE; i++)
{
pNode = pHashTable->pHashHead[i];
while (NULL != pNode)
{
printf("[i=%d][key=%ld][val=%d][%s]\n", i, pNode->key, pNode->value, strs[pNode->value]);
pNode = pNode->pNext;
}
}
*/
//3,利用哈希表将字符串数组中的字母异位词存入结果中
groupAnagramsUseHash(strs, pRet, pHashTable, returnSize, *returnColumnSizes);
//4,释放哈希表空间
freeHashTable(pHashTable);
free(pHashTable);
//5,返回
return pRet;
}