C 语言构造hash table 解 LC majority element问题

Leetcode上 majority element这题是 有 时间O(N), 空间O(1)的解的.

https://leetcode.com/problems/majority-element/

用hash table来解则为 时间O(N), 空间O(N). 如果是Java里 用HashMap很方便了. 有位同学问怎么用c语言来构造hash table. 我就随手写了一个:

typedef struct Node {
    int val, count;
} Node;

typedef struct HASH {
    Node *np;
    int size, capacity;
} HASH;

#define N 509

#define HASH_VAL(n) abs((n) % N)

static int ensureCapacity(HASH *hp)
{
    int size, capacity;
    Node *np;

    size = hp->size;
    capacity = hp->capacity;
    if (size < capacity)
        return 0;
    if (capacity == 0)
        capacity = 8;
    else
        capacity <<= 1;
    np = (Node*)realloc(hp->np, capacity * sizeof(Node));
    if (np == NULL)
        return -1;
    hp->capacity = capacity;
    hp->np = np;
    return 0;
}

static void freeHashTab(HASH htab[], int n)
{
    int i;
    for (i = 0; i < n; i++)
        if (htab[i].np)
            free(htab[i].np);
}

int majorityElement(int arr[], int n)
{
    HASH htab[N], *hb;
    int i, j, cur, hval, res;

    memset(htab, 0, N * sizeof(HASH));
    for (i = 0; i < n; i++) {
        cur = arr[i];
        hval = HASH_VAL(cur);
        hb = &htab[hval];
        for (j = 0; j < hb->size; j++)
            if (hb->np[j].val == cur)
                break;
        if (j == hb->size) {
            if (ensureCapacity(hb) == -1)
                goto err;
            hb->np[j].val = cur;
            hb->np[j].count = 1;
            hb->size++;
        } else {
            hb->np[j].count++;
        }
        if (hb->np[j].count > n / 2) {
            res = hb->np[j].val;
            freeHashTab(htab, N);
            return res;
        }
    }

err:
    freeHashTab(htab, N);
    return -1;
}

代码稍微长一点就肯定有bug. 这次我遇到两个问题:

1. 在给数组扩容时, 我一开始的代码是这样:

    hp->np = (Node*)realloc(hp->np, capacity * sizeof(Node));
    if (hp->np == NULL)
        return -1;

这里的问题在于, 若realloc返回NULL, 则原来的内存 不会被清除. 所以这里有一个内存泄露.

2. 需要一个hash函数 把 n映射为 [0, N - 1]. 为简单计, 我的hash函数简单的定义为:

#define N 509
#define HASH_VAL(n) (n) % N

这是不对的. 考虑 n == -1, 则hash值为-1.

再来:

#define HASH_VAL(n) abs(n) % N

貌似可以了吧. 但还是不行, 呵呵, LC上的测试用例设计的非常好. 考虑 n为-2147483648, 则abs(n) = -2147483648.

注: 2147483648超出32位int型范围, 故 abs(-2147483648) 为undefined behavior.

最后改为:

#define HASH_VAL(n) abs((n) % N)
时间: 2024-10-11 01:41:57

C 语言构造hash table 解 LC majority element问题的相关文章

散列表(Hash table)及其构造

散列表(Hash table) 散列表,是根据关键码值(Key value)而直接进行访问的数据结构.它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. 已知的查找方法: 1.顺序查找 O(N) 2.二分查找(静态查找) O(log2N) 3.二叉搜索树 O(h) h为二叉树的高度 平衡二叉树 O(log2N) Q:如何快速搜索到需要的关键字?如果关键字不方便比较怎么办? 查找的本质:已知对象找位置 有序安排对象:全序.半序 直接

数据结构基础-Hash Table详解(转)

理解Hash 哈希表(hash table)是从一个集合A到另一个集合B的映射(mapping). 映射是一种对应关系,而且集合A的某个元素只能对应集合B中的一个元素.但反过来,集合B中的一个元素可能对应多个集合A中的元素.如果B中的元素只能对应A中的一个元素,这样的映射被称为一一映射.这样的对应关系在现实生活中很常见,比如: A  -> B 人 -> 身份证号 日期 -> 星座 上面两个映射中,人 -> 身份证号是一一映射的关系.在哈希表中,上述对应过程称为hashing.A中元

C语言-简单哈希表(hash table)

腾讯三面的时候,叫我写了个哈希表,当时紧张没写好···结果跪了··· 回来后粪发涂墙,赶紧写了一个! 什么都不说了···先让我到厕所里面哭一会··· %>_<% 果然现场发挥,以及基础扎实才是important的! 用链地址法解决冲突的哈希表(C语言,VS2008编写.测试): 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <math.h> 4 #include <string.h>

[译]C语言实现一个简易的Hash table(4)

上一章我们解释了Hash table中最重要的hash函数,并用伪代码和C语言实现了一个我们自己的hash函数,hash函数中碰撞是无法避免的,当发生碰撞时我们改如何有效的处理呢?这章我们就来讲解下. 处理碰撞 hash函数中将无限大的输入映射到有限的输出中,当不同的输入映射到相同的输出时,就会发生碰撞,每个的hash表都会采用不同的方法来处理碰撞. 我们的哈希表将使用一种称为开放地址的双重哈希的技术来处理冲突.双重哈希使用两个散列函数来计算在发生碰撞后存储记录的索引. 双重哈希 当i发生碰撞后

[译]C语言实现一个简易的Hash table(2)

上一章,简单介绍了Hash Table,并提出了本教程中要实现的几个Hash Table的方法,有search(a, k).insert(a, k, v)和delete(a, k),本章将介绍Hash table使用的数据结构. Hash table数据结构 hash表中存储的每一项key-value的数据结构: // hash_table.h typedef struct { char* key; char* value; } ht_item; 我们的hash表中保存着一个指向每一项的指针数组

[译]C语言实现一个简易的Hash table(3)

上一章,我们讲了hash表的数据结构,并简单实现了hash表的初始化与删除操作,这一章我们会讲解Hash函数和实现算法,并手动实现一个Hash函数. Hash函数 本教程中我们实现的Hash函数将会实现如下操作: 输入一个字符串,然后返回一个0到m(Hash表的大小)的数字 为一组平常的输入返回均匀的bucket索引.如果Hash函数不是均匀分布的,就会将多个记录插入到相同的bucket中,这就回提高冲突的几率,而这个冲突就会影响到我们的Hash表的效率. Hash算法 我们将会设计一个普通的字

PHP关联数组与哈希表(hash table) 不指定

PHP中有一种数据类型非常重要,它就是关联数组,又称为哈希表(hash table),是一种非常好用的数据结构. 在程序中,我们可能会遇到需要消重的问题,举一个最简单的模型: 有一份用户名列表,存储了 10000 个用户名,没有重复项: 还有一份黑名单列表,存储了 2000 个用户名,格式与用户名列表相同: 现在需要从用户名列表中删除处在黑名单里的用户名,要求用尽量快的时间处理. 这个问题是一个小规模的处理量,如果实际一点,2 个表都可能很大,比如有 2 亿条记录. 我最开始想到的方法,就是做一

算法导论-散列表(Hash Table)

目录 引言 直接寻址 散列寻址 散列函数 除法散列 乘法散列 全域散列 完全散列 碰撞处理方法 链表法 开放寻址法 线性探查 二次探查 双重散列 随机散列 再散列问题 完整源码(C++) 参考资料 内容 1.引言 如果想在一个n个元素的列表中,查询元素x是否存在于列表中,首先想到的就是从头到尾遍历一遍列表,逐个进行比较,这种方法效率是Θ(n):当然,如果列表是已经排好序的话,可以采用二分查找算法进行查找,这时效率提升到Θ(logn);  本文中,我们介绍散列表(HashTable),能使查找效率

STL hash table, Unordered Contains

STL hash table, Unordered Contain   C++11加入使用hash table实现的Unordered Containers.容器中元素是不排序的,同时我们也不能指定某个元素的位置. 头文件:#include <unordered_set>   unordered_set; unordered_multiset;           #include <unordered_map> unordered_map; unordered_multimap;