C 哈希表与链表

C 哈希表与链表,c,linked-list,hashtable,C,Linked List,Hashtable,所以我想做一个足球(美国足球)游戏模拟器,我想在一个数据结构中存储一系列游戏,问题是我试着用数组来做,但是因为它修复了sise,我不得不调整它的大小,调整大小可能会很痛苦,加上它没有那么有效 然后我看到有链表,你可以很容易地添加或删除一个元素,使它比数组更好,但问题是,要访问一个元素,你必须进行线性搜索,即O(N) 但后来我发现你可以使用一个哈希表,我的老师(我在做一个大学项目)给出了一个哈希表算法,它使用链表,具有双重哈希、线性探测和外部链接 在某种程度上,哈希表可以对链表进行极大的优化,因为

所以我想做一个足球(美国足球)游戏模拟器,我想在一个数据结构中存储一系列游戏,问题是我试着用数组来做,但是因为它修复了sise,我不得不调整它的大小,调整大小可能会很痛苦,加上它没有那么有效

然后我看到有链表,你可以很容易地添加或删除一个元素,使它比数组更好,但问题是,要访问一个元素,你必须进行线性搜索,即O(N)

但后来我发现你可以使用一个哈希表,我的老师(我在做一个大学项目)给出了一个哈希表算法,它使用链表,具有双重哈希、线性探测和外部链接

在某种程度上,哈希表可以对链表进行极大的优化,因为u可以在O(1)中访问它的元素,但问题是它的大小是固定的,因此最终需要调整大小(这也需要花费更多的内存和时间来扩展它)

那么我应该选择使用链表还是哈希表呢


感谢您的帮助。

如果发生哈希冲突,哈希表的复杂性不会自动为O(1),哈希表通常由数组(O(log(n))或链表(O(n))支持(尽管在这种情况下,n会减少为发生冲突的元素数)

必须根据更普遍的操作选择策略:

  • 您仍然可以使用数组并过度分配其大小,只有在达到某个阈值时才会增长和收缩,如果对数组进行排序,则可以执行二进制搜索,这将具有O(log(n))复杂性
  • 您可以使用(平衡的?)树,它与链表一样灵活,wold在删除/插入/读取(O(log(n))时提供了良好的性能平衡

但是如果你的老师给你提供了一个散列算法,你会更明智地使用老师提供的材料。

如果散列冲突发生,则散列表的复杂性不会自动为O(1),散列表通常由数组(O(log(n))或链表(O(n))支持(尽管在这种情况下,n会减少为发生冲突的元素数)

必须根据更普遍的操作选择策略:

  • 您仍然可以使用数组并过度分配其大小,只有在达到某个阈值时才会增长和收缩,如果对数组进行排序,则可以执行二进制搜索,这将具有O(log(n))复杂性
  • 您可以使用(平衡的?)树,它与链表一样灵活,wold在删除/插入/读取(O(log(n))时提供了良好的性能平衡
但是如果你的老师给你提供了一个散列算法,你会更明智地使用老师提供的材料

[…]我想在一个数据结构中存储一系列游戏,问题是我试图用数组来存储,但由于它修复了sise

在C语言中,有指针,因此可以动态分配对象序列

我不得不调整它的大小,调整大小可能会很痛苦

为什么会痛?您可以很容易地这样做:

#include <stdlib.h>
struct game {
    int example_field;
};

int main(void) 
{
    struct game *pgames = NULL;
    size_t ngames = 0;

    for (size_t i = 0; i < 10; ++i) {
        struct game g = { i };

        // Add game
        pgames = realloc(pgames, (ngames + 1)* sizeof(struct game));
        pgames[ngames++] = g;
    }

    free(pgames);
    return EXIT_SUCCESS;
}
#include <stdlib.h>
struct game {
    int example_field;
};

int main(void) 
{
    struct game *pgames = NULL;
    size_t ngames = 0, cgames = 0; // cgames is the storage capacity

    for (size_t i = 0; i < 10; ++i) {
        struct game g = { i };

        // Add game
        if (ngames == cgames) {
            cgames = cgames * 2 + 1;
            pgames = realloc(pgames, cgames * sizeof(struct game));
        }
        pgames[ngames++] = g;
    }

    free(pgames);
    return EXIT_SUCCESS;
}
#包括
结构游戏{
int示例_字段;
};
内部主(空)
{
结构游戏*pgames=NULL;
尺寸=0;
对于(尺寸i=0;i<10;++i){
结构对策g={i};
//添加游戏
pgames=realloc(pgames,(ngames+1)*sizeof(struct game));
pgames[ngames++]=g;
}
免费(pgames);
返回退出成功;
}
加上它没有那么有效

这是你的主要错误。在你衡量效率之前不要谈论效率。如果你有办法衡量你的表现,那就太好了。如果你没有,不要假设。计算复杂性不同于效率。你的计算复杂性模型忽略了硬件是如何实现的:缓存、分支预测、向量指令

我以前的代码尽可能简单,但每个元素需要一次重新分配。你可以像这样做得更好:

#include <stdlib.h>
struct game {
    int example_field;
};

int main(void) 
{
    struct game *pgames = NULL;
    size_t ngames = 0;

    for (size_t i = 0; i < 10; ++i) {
        struct game g = { i };

        // Add game
        pgames = realloc(pgames, (ngames + 1)* sizeof(struct game));
        pgames[ngames++] = g;
    }

    free(pgames);
    return EXIT_SUCCESS;
}
#include <stdlib.h>
struct game {
    int example_field;
};

int main(void) 
{
    struct game *pgames = NULL;
    size_t ngames = 0, cgames = 0; // cgames is the storage capacity

    for (size_t i = 0; i < 10; ++i) {
        struct game g = { i };

        // Add game
        if (ngames == cgames) {
            cgames = cgames * 2 + 1;
            pgames = realloc(pgames, cgames * sizeof(struct game));
        }
        pgames[ngames++] = g;
    }

    free(pgames);
    return EXIT_SUCCESS;
}
#包括
结构游戏{
int示例_字段;
};
内部主(空)
{
结构游戏*pgames=NULL;
size\u t ngames=0,cgames=0;//cgames是存储容量
对于(尺寸i=0;i<10;++i){
结构对策g={i};
//添加游戏
如果(ngames==cgames){
cgames=cgames*2+1;
pgames=realloc(pgames,cgames*sizeof(结构游戏));
}
pgames[ngames++]=g;
}
免费(pgames);
返回退出成功;
}
然后我看到有链表,你可以很容易地添加或删除一个元素,使它比数组更好

“轻松”只是调用一个函数。与使用动态序列/数组没有区别。链表并不比数组“更好”。一切都取决于您将执行的操作。根据我的经验,我从未观察到列表的性能比动态序列更好。测量,然后选择

但问题是,要访问元素u,必须进行线性搜索,即O(N)

不,要搜索,必须进行线性搜索。你多久搜索一次

但后来我发现你可以使用一个哈希表,我的老师(我在做一个大学项目)给出了一个哈希表算法,它使用链表,具有双重哈希、线性探测和外部链接

这看起来很简单…:-)

在某种程度上,哈希表可以对链表进行极大的优化,因为u可以在O(1)中访问其元素

有时候

但问题是它的规模是固定的

没有必要

正因为如此,它最终需要调整大小(这也需要花费更多的内存和时间来扩展它)

所以它不是固定的

那么我应该选择使用链表还是哈希表呢

我的建议?使用动态分配的虚拟企业