UT HASH

16 篇文章 0 订阅

好文分享:c开源hash项目 uthash的用法总结_whatday的专栏-CSDN博客_uthash 

目录

目录

头文件

定义HASH表

前置准备

int类型为key值 

字符串类型为key值 

指针类型为key值 

添加HASH_ADD_TYPE(INT/STR/PTR)

查找HASH_FIIND_TYPE(INT/STR/PTR)

删除HASH_DEL

容量HASH_COUNT

排序Sort

遍历

方式一:原版接口

方式二:自建数组

自定义类型查找

LC练习

INT 类型习题

STR类型练习 

整体接口练习 


C 语言中,hash表通过结构体进行实现,hash表中每一个的元素,都使用结构体进行定义,结构体中的内容就是hash表一个元素所包含的内容

头文件

#include"uthash.h"

定义HASH表

在结构体中,务必带有UT_hash_handle hh;的句柄,key值只能有一个,但是context的值,可以有多个。

示例1:

typedef struct HashMap {
    int val; // val保存下标
    int key; // key保存值 UT hash 只能用键值进行查找 关键信息放键值
    UT_hash_handle hh; // hash map的头

}HashMap;

示例2:

#define SIZE 10001
typedef struct Hash{
    int index; 
    int count; 
    char key[SIZE]; // key 值
    UT_hash_handle hh;
}Hash

前置准备

HashMap *hashHandle = NULL;
HashMap *tmp = (HashMap *)malloc(sizeof(HashMap));
//tmp也可以不再一开始声明空间

int类型为key值 

HASH_ADD/FIND_INT

字符串类型为key值 

HASH_ADD/FIND_STR

指针类型为key值 

HASH_ADD/FIND_PTR
默认类型为void *

添加HASH_ADD_TYPE(INT/STR/PTR)

int类型

tmp = (HashMap *)malloc(sizeof(HashMap));
tmp->key = nums[i];
tmp->val = i;
HASH_ADD_INT(hashHandle, key, tmp);
// 第二个参数为Hash Map中你定义的key值的名称
// 第三个参数是你需要加入到HASH表中的内容

字符串类型

hashTmp = (Hash *)malloc(sizeof(Hash));
hashTmp->index = (*returnSize);
hashTmp->count = 1;
memset(hashTmp->key, 0, sizeof(hashTmp->key));
strcpy(hashTmp->key, tmp);
HASH_ADD_STR(head, key, hashTmp);

查找HASH_FIIND_TYPE(INT/STR/PTR)

int类型

int numTmp = target - nums[i];
HASH_FIND_INT(hashHandle, &numTmp, tmp);

HASH_FIND_INT(hashHandle, &numTmp, tmp);
// UT HASH 使用键值进行查询 第二个参数是键值的地址
// 第三个值为返回内容的存储区域,如果找到,则可以进行访问,如果没有找到,那么直接为NULL

 字符串类型

char tmp[(len + 1)];
strcpy(tmp, strs[i]);
HASH_FIND_STR(head, tmp, hashTmp);

注意第二个参数的差异! 

删除HASH_DEL

HASH_DEL(g_head, temp);
// 第一个依旧是Hash的头指针 第二个参数是要删除的元素
    HashStruct *temp = NULL;
    HASH_FIND_INT(g_head, &val, temp);   
    if (temp == NULL) {
        return false;
    }
    HASH_DEL(g_head, temp); // UT hash 删除元素
    free(temp); // 仅仅是在Hash map中移除,并没有free该变量

容量HASH_COUNT

int size = HASH_COUNT(head);

排序Sort

/* 多重条件排序 */
int cmp(Hash*s1, Hash *s2) {
    if (s1->freq != s2->freq) {
        return s1->freq < s2->freq;
    }
    return strcmp(s1->str, s2->str);
}
int main() {
   HASH_SORT(g_head, cmp); //Hash自带的Sort
}

代表题目:642. 设计搜索自动补全系统 

遍历

方式一:原版接口

380. O(1) 时间插入、删除和获取随机元素

    HashStruct *currentUser = NULL;
    HashStruct *temp = NULL;

    HASH_ITER(hh, hashHead, currentUser, temp) { 
          // 遍历
    } 
    //第一个参数未句柄,第二个参数为Hash head,第三个参数未当前元素,第四个就是temp

上题能够很好的历练UT_HASH的各种操作

方式二:自建数组

347. 前 K 个高频元素 力扣

首先创建结构体 

typedef struct Hash{
    int times; // 出现频次
    int val; // 数值
    UT_hash_handle hh;
}Hash;

因为后续可能要对Hash map进行进一步的操作,书写必要的操作函数

int cmp (const void *s1, const void *s2) {
    Hash *ag1 = *(Hash **)s1;
    Hash *ag2 = *(Hash **)s2;
    return ag1->times < ag2->times ? 1 : -1;
}

直接建立一个hash的数组,在C语言中这部分非常灵活。

    Hash **numTimes = (Hash **)malloc(sizeof(Hash *) * 5000);
    int index = 0;
    for (int i = 0; i < numsSize; ++i) {
        HASH_FIND_INT(head, &nums[i], tmp);
        if (tmp != NULL) {
            tmp->times++;
        } else {
            numTimes[index] = (Hash *)malloc(sizeof(Hash));
            numTimes[index]->val = nums[i];
            numTimes[index]->times = 1;
            HASH_ADD_INT(head, val, numTimes[index]);
            index++;
        }
    }
    qsort(numTimes, index, sizeof(Hash *), cmp);

完整代码如下:

二维数组版本:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
typedef struct Hash{
    int times; // 出现频次
    int val; // 数值
    UT_hash_handle hh;
}Hash;
int cmp (const void *s1, const void *s2) {
    Hash *ag1 = *(Hash **)s1;
    Hash *ag2 = *(Hash **)s2;
    return ag1->times < ag2->times ? 1 : -1;
}
int* topKFrequent(int* nums, int numsSize, int k, int* returnSize){
    if (nums == NULL) {
        return NULL;
    }
    Hash *head = NULL;
    Hash *tmp = NULL;
    Hash **numTimes = (Hash **)malloc(sizeof(Hash *) * 5000);
    int index = 0;
    for (int i = 0; i < numsSize; ++i) {
        HASH_FIND_INT(head, &nums[i], tmp);
        if (tmp != NULL) {
            tmp->times++;
        } else {
            // printf("nums[i] = %d\n", nums[i]);
            numTimes[index] = (Hash *)malloc(sizeof(Hash));
            numTimes[index]->val = nums[i];
            numTimes[index]->times = 1;
            HASH_ADD_INT(head, val, numTimes[index]);
            index++;
        }
    }
    qsort(numTimes, index, sizeof(numTimes[0]), cmp);
    int *res = (int *)malloc(sizeof(int) * k);
    memset(res, 0, sizeof(int) * k);
    (*returnSize) = 0;
    for (int i = 0; i < k; ++i) {
        res[(*returnSize)++] = numTimes[i]->val;
    }
    return res;
}

一维数组

// 排序算法
typedef struct Hash{
    int freq;
    int val;
    UT_hash_handle hh;
}Hash;
int cmp(void *s1, void *s2) {
    Hash *arg1 = (Hash *)s1;
    Hash *arg2 = (Hash *)s2;
    return arg1->freq < arg2->freq;
}
int* topKFrequent(int* nums, int numsSize, int k, int* returnSize){
    if (nums == NULL) {
        return NULL;
    }
    (*returnSize) = 0;
    Hash *head = NULL;
    Hash item[numsSize]; // 使用指针数组也可以
    int index = 0;
    for (int i = 0; i < numsSize; ++i) {
        Hash *temp = NULL;
        HASH_FIND_INT(head, &nums[i], temp);
        if (temp != NULL) {
            temp->freq++;
        } else {
            item[index].freq = 1;
            item[index].val = nums[i];
            HASH_ADD_INT(head, val, &item[index]);
            index++;
        }
    }
    qsort(item, index, sizeof(Hash), cmp);
    int *res = (int *)malloc(sizeof(int) * k);
    for (int i = 0; i < k; ++i) {
        res[(*returnSize)++] = item[i].val;
    }
    return res;
}

 最好最好不要用!指针数组 Hash *item[n];

自定义类型查找

当int和str都不能满足要求的时候,我们需要自行定义结构体

typedef struct Pair{
    int x;
    int y;
} Pair;
typedef struct Hash{
    Pair point;
    UT_hash_handle hh;
} Hash;

 ADD

HASH_ADD(hh, head, point, sizeof(Pair), temp);

FIND

HASH_FIND(hh, head, &point, sizeof(Pair), temp);

其余都一样

遍历:

    Hash *cur = NULL;
    HASH_ITER(hh, g_head, cur, temp) {
        printf("cur->point.x = %d, cur->point.y = %d\n", cur->point.x, cur->point.y);
    }

 练习:

874. 模拟行走机器人

#define LEN 4
int direct;

typedef struct Pair{
    int x;
    int y;
} Pair;
typedef struct Hash{
    Pair point;
    UT_hash_handle hh;
} Hash;
Hash *g_head = NULL;

void GoGOPoint(int commands, int *point) {
    Pair step;
    Hash *temp = NULL;
    if (direct == 0) {
        // 北 point[1] += commands;
        step.x = point[0];
        for (int i = 0; i < commands; ++i) {
            step.y = point[1] + 1;
            HASH_FIND(hh, g_head, &step, sizeof(Pair), temp);
            if (temp != NULL) {
                break;
            } else {
                point[1]++;
            }
        }
    } else if (direct == 1) {
        // 东
        step.y = point[1];
        for (int i = 0; i < commands; ++i) {
            step.x = point[0] + 1;
            HASH_FIND(hh, g_head, &step, sizeof(Pair), temp);
            if (temp != NULL) {
                break;
            } else {
                point[0]++;
            }
        }
    } else if (direct == 2) {
        // 南
        step.x = point[0];
        for (int i = 0; i < commands; ++i) {
            step.y = point[1] - 1;
            HASH_FIND(hh, g_head, &step, sizeof(Pair), temp);
            if (temp != NULL) {
                break;
            } else {
                point[1]--;
            }
        }
    } else if (direct == 3) {
        // 西
        step.y = point[1];
        for (int i = 0; i < commands; ++i) {
            step.x = point[0] - 1;
            HASH_FIND(hh, g_head, &step, sizeof(Pair), temp);
            if (temp != NULL) {
                break;
            } else {
                point[0]--;
            }
        }
    }
    return;
}
void MovePoint(int commands, int *point) {
    if (commands == -2) {
        direct = (LEN + direct - 1) % LEN;
    }
    if (commands == -1) {
        direct = (LEN + direct + 1) % LEN;
    }

    if (commands >= 1 && commands <= 9) {
        GoGOPoint(commands, point);
    }

    return;
}

int robotSim(int* commands, int commandsSize, int** obstacles, int obstaclesSize, int* obstaclesColSize){
    if (NULL == commands) {
        return 0;
    }
    direct = 0; // 北 0 1东 2南 3西
    int size = commandsSize;

    int point[2];
    memset(point, 0, sizeof(point));

    // 做一张障碍物地图
    // memset(map, 0, sizeof(map));
    g_head = NULL;
    Hash *temp = NULL;
    for (int i = 0; i < obstaclesSize; i++) {
		Hash *temp = (Hash *)malloc(sizeof(Hash));
		temp->point.x = obstacles[i][0];
		temp->point.y = obstacles[i][1];
		HASH_ADD(hh, g_head, point, sizeof(Pair), temp);
    }

    int res = 0;

    for (int i = 0; i < size; ++i) {
        MovePoint(commands[i], point);
        // printf("com = %d, direct = %d, point[0] = %d, point[1] = %d\n", 
        //         commands[i], direct, point[0], point[1]);
        int dis = (point[0] * point[0]) + (point[1] * point[1]);
        res = fmax(res, dis);
    }

    return res;
}

LC练习

INT 类型习题

1. 两数之和 力扣

typedef struct HashMap {
    int val; // val保存下标
    int key; // key保存值 UT hash 只能用键值进行查找 关键信息放键值
    UT_hash_handle hh; // hash map的头

}HashMap;
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    if (nums == NULL) {
        return NULL;
    }
    returnSize[0] = 2;
    int *res = (int *)malloc(sizeof(int) * 2);
    HashMap *hashHandle = NULL;
    HashMap *tmp = (HashMap *)malloc(sizeof(HashMap));
    tmp->val = -1; 
    tmp->key = INT_MIN;
    for (int i = 0;i < numsSize;++i) {
        int numTmp = target - nums[i];
        HASH_FIND_INT(hashHandle, &numTmp, tmp);
        if (tmp != NULL) {
            res[0] = tmp->val;
            res[1] = i;
            return res;
        }
        tmp = (HashMap *)malloc(sizeof(HashMap));
        tmp->key = nums[i];
        tmp->val = i;
        HASH_ADD_INT(hashHandle, key, tmp);
    }
    returnSize[0] = 0;
    return res;
}

STR类型练习 

49. 字母异位词分组 力扣 

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
#define SIZE 5000
int cmp (const void *s1, const void *s2) {
    return *(char *)s1 > *(char *)s2;
}
typedef struct Hash{
    int index; // res中的下标 res的一级下标
    int count; // 相同元素的个数 res的二级下标
    char keyStr[SIZE]; // key
    int len; // 单词长度
    UT_hash_handle hh;
}Hash;
char *** groupAnagrams(char ** strs, int strsSize, int* returnSize, int** returnColumnSizes){
    // 整体思路 内部qsort 加入到hash中,遇到相同的直接找下标即可,然后遍历hash表
    char ***res = (char ***)malloc(sizeof(char **) * strsSize);
    (*returnSize) = 0;
    returnColumnSizes[0] = (int *)malloc(sizeof(int) * strsSize);
    Hash *head = NULL;
    Hash *headTmp = (Hash *)malloc(sizeof(Hash));
    for (int i = 0; i < strsSize;++i) {
        char tmp[strlen(strs[i]) + 1];
        memset(tmp, 0, sizeof(tmp));
        strcpy(tmp, strs[i]);
        qsort(tmp, strlen(tmp), sizeof(char), cmp);
        HASH_FIND_STR(head, tmp, headTmp);
        if (headTmp == NULL) {
            // 新增加一个
            headTmp = (Hash *)malloc(sizeof(Hash));
            memset(headTmp->keyStr, 0, sizeof(headTmp->keyStr));
            strcpy(headTmp->keyStr, tmp); // 最大的细节 一定要保存排好序的内容
            headTmp->index = (*returnSize);
            headTmp->count = 1;
            headTmp->len = strlen(strs[i]) + 1;
            HASH_ADD_STR(head, keyStr, headTmp);

            res[(*returnSize)] = (char **)malloc(sizeof(char *) * strsSize);
            res[(*returnSize)][0] = (char *)malloc(sizeof(char) * headTmp->len);
            memset(res[(*returnSize)][0], 0, sizeof(char) * headTmp->len);
            memcpy(res[*returnSize][0], strs[i], strlen(strs[i]));
            returnColumnSizes[0][(*returnSize)] = 1;
            (*returnSize)++;
        } else {
            // 找到了
            res[headTmp->index][headTmp->count] = (char *)malloc(sizeof(char) * headTmp->len);
            memset(res[headTmp->index][headTmp->count], 0, sizeof(char) * headTmp->len);
            memcpy(res[headTmp->index][headTmp->count], strs[i], strlen(strs[i]));
            returnColumnSizes[0][headTmp->index] = headTmp->count + 1;
            headTmp->count = headTmp->count + 1;
        }
    }
    return res;
}

 863. 二叉树中所有距离为 K 的结点 力扣

以INT为key值:

#define SIZE 5000
typedef struct Hash {
    int key; // key
    struct TreeNode* father;
    struct TreeNode* self;
    UT_hash_handle hh;
}Hash;
Hash *g_head;
int *g_res;
void GetTreeInfo (struct TreeNode* root, struct TreeNode* father) {
    if (root == NULL) {
        return;
    }
    // 记录每个结点的父亲
    Hash *node = (Hash *)malloc(sizeof(Hash));
    node->key = root->val; // 记录本结点的值
    node->father = father; // 记录父亲
    node->self = root; // 记录自己
    HASH_ADD_INT(g_head, key, node);

    GetTreeInfo(root->left, root);
    GetTreeInfo(root->right, root);
}
void DFS (struct TreeNode* root, struct TreeNode* form, int k, int* returnSize) {
    if (root == NULL) {
        return;
    }
    if (k == 0) {
        g_res[(*returnSize)++] = root->val;
        return;
    }
    if (root->left != form) {
        DFS(root->left, root, k - 1, returnSize); // left
    }
    if (root->right != form) {
        DFS(root->right,root, k - 1, returnSize); // right
    }
    Hash *tmp = NULL;
    HASH_FIND_INT(g_head, &root->val, tmp);
    if (tmp != NULL && tmp->father != form) {
        DFS(tmp->father, root, k - 1, returnSize); // head
    }
}
int* distanceK(struct TreeNode* root, struct TreeNode* target, int k, int* returnSize) {
    if (root == NULL) {
        return NULL;
    }
    g_head = NULL;
    // 遍历一遍树,把每个元素的父结点都记录下来
    GetTreeInfo(root, NULL);
    g_res = (int *)malloc(sizeof(int) * SIZE);
    (*returnSize) = 0;
    // 遍历一遍,找到目标值
    Hash *tmp = NULL;
    HASH_FIND_INT(g_head, &target->val, tmp);
    if (tmp == NULL) {
        return g_res;
    }
    struct TreeNode* begin = tmp->self;
    DFS(begin, NULL, k, returnSize);
    return g_res;
}

整体接口练习 

380. O(1) 时间插入、删除和获取随机元素

typedef struct _HashNode{
    int key;
    UT_hash_handle hh;
} HashNode;
typedef struct {
    HashNode *g_hashNode;
} RandomizedSet;

/** Initialize your data structure here. */

RandomizedSet* randomizedSetCreate() {
    RandomizedSet *obj = (RandomizedSet*)malloc(sizeof(RandomizedSet));
    memset(obj, 0, sizeof(RandomizedSet));
    return obj;
}

/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
bool randomizedSetInsert(RandomizedSet* obj, int val) {
    HashNode *s = NULL;
    HASH_FIND_INT(obj->g_hashNode, &val, s);
    if (s != NULL) {
        return false;
    }
    s = (HashNode*)malloc(sizeof(HashNode));
    s->key = val;
    HASH_ADD_INT(obj->g_hashNode, key, s);
    return true;
}

/** Removes a value from the set. Returns true if the set contained the specified element. */
bool randomizedSetRemove(RandomizedSet* obj, int val) {
    HashNode *hash = NULL;
    HASH_FIND_INT(obj->g_hashNode, &val, hash);
    if (hash == NULL) {
        return false;
    }
    HASH_DEL(obj->g_hashNode, hash);
    free(hash);
    return true;
}

/** Get a random element from the set. */
int randomizedSetGetRandom(RandomizedSet* obj) {
    HashNode *cur = NULL;
    HashNode *tmp = NULL;
    int idx = 0;
    int cnt = 0;
    idx = rand() % (HASH_COUNT(obj->g_hashNode));
    HASH_ITER(hh, obj->g_hashNode, cur, tmp) {
        if (cnt++ >= idx) {
            break;
        }
    }
    return cur->key;
}

void randomizedSetFree(RandomizedSet* obj) {
    HashNode *cur = NULL;
    HashNode *tmp = NULL;
    HASH_ITER(hh, obj->g_hashNode, cur, tmp) {
        HASH_DEL(obj->g_hashNode, cur);
        free(cur);
    }
    free(obj);
}

642. 设计搜索自动补全系统

#define LEN 1000
typedef struct {
    char str[LEN];
    char strHead[2];
    int freq;
    UT_hash_handle hh;
} AutocompleteSystem;

char g_searchHis[LEN] = {0};
int g_size = 0;
AutocompleteSystem *g_head = NULL;

/* 向Hash表中增加元素 */
void AddNode(char *strVal, int freqVal) {
    AutocompleteSystem *temp = NULL;
    temp = (AutocompleteSystem *)malloc(sizeof(AutocompleteSystem));
    memset(temp->str, 0, sizeof(temp->str));
    memset(temp->strHead, 0, sizeof(temp->strHead));
    temp->strHead[0] = strVal[0];
    strcpy(temp->str, strVal);
    temp->freq = freqVal;
    HASH_ADD_STR(g_head, str, temp);
}

AutocompleteSystem* autocompleteSystemCreate(char ** sentences, int sentencesSize, int* times, int timesSize) {
    int row = sentencesSize;
    g_size = row;
    for (int i = 0; i < row; ++i) {
        AddNode(sentences[i], times[i]);
    }
    return g_head;
}

/* 打印函数 */
void Printf() {
    printf("PRINTF\n");
    AutocompleteSystem *curItem = NULL;
    AutocompleteSystem *temp = NULL;
    HASH_ITER(hh, g_head, curItem, temp) {
        printf("curItem->str = %s, curItem->freq = %d\n", curItem->str, curItem->freq);
    }
}

/* 以出现频次作为索引,降序排序,如果频次相同,那么改为以字典序升序排序 */
int cmp(AutocompleteSystem *s1, AutocompleteSystem *s2) {
    if (s1->freq != s2->freq) {
        return s1->freq < s2->freq;
    }
    return strcmp(s1->str, s2->str);
}

char ** autocompleteSystemInput(AutocompleteSystem* obj, char c, int* retSize) {
    // 先排序
    HASH_SORT(g_head, cmp);
    // Printf();
    retSize[0] = 0;
    char **res = (char **)malloc(sizeof(char *) * g_size);

    /* 保存临时输入字符,并转化为字符串,方便后续操作 */
    char cTmp[2] = {0};
    cTmp[0] = c;
    
    if (c == '#') {
        // 之前搜的要记下来,此处全部压入Hash,重复搜索还要增加搜索次数
        AutocompleteSystem *temp = NULL;
        HASH_FIND_STR(g_head, g_searchHis, temp);
        if (temp != NULL) {
            temp->freq++;
        } else {
            AddNode(g_searchHis, 1);
        }
        memset(g_searchHis, 0, sizeof(g_searchHis));
        return res;
    } else {
        strcat(g_searchHis, cTmp);// 记录搜索记录
        AutocompleteSystem *curItem = NULL;
        AutocompleteSystem *temp = NULL;
        HASH_ITER(hh, g_head, curItem, temp) {
            if (retSize[0] == 3) {
                break;
            }
            // 搜索首字母
            char *strTmp = NULL;
            strTmp = strstr(curItem->str, g_searchHis); // 查找当前搜索是否有对应的历史记录
            /* 历史记录中如果存在,那么必须是前缀完全相同strTmp == curItem->str必不可少 */
            if (strTmp != NULL && strTmp == curItem->str) {
                res[retSize[0]] = (char *)malloc(sizeof(char) * (strlen(curItem->str) + 1));
                strcpy(res[retSize[0]], curItem->str);
                retSize[0]++;
            }
        }
    }
    return res;
}

void autocompleteSystemFree(AutocompleteSystem* obj) {
    AutocompleteSystem *curItem = NULL;
    AutocompleteSystem *temp = NULL;
    HASH_ITER(hh, g_head, curItem, temp) {
        HASH_DEL(g_head, curItem);
        free(curItem);
    }
}

/**
 * Your AutocompleteSystem struct will be instantiated and called as such:
 * AutocompleteSystem* obj = autocompleteSystemCreate(sentences, sentencesSize, times, timesSize);
 * char ** param_1 = autocompleteSystemInput(obj, c, retSize);
 
 * autocompleteSystemFree(obj);
*/

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值