【问题标题】:How is unrolled linked list better than linked list?展开的链表比链表更好吗?
【发布时间】:2019-06-25 00:18:54
【问题描述】:

我正在学习“数据结构和算法变得简单”这本书,但在学习“比较链接列表和展开链接列表”时我感到困惑......

什么是开销? 为什么他只为 100 个元素的数组说明 8 个字节的开销?

【问题讨论】:

  • 每个节点将占用 8 个字节(两个 4 字节指针),而不是 100 个元素的 8 个字节。
  • 寻找listnode和listblock的区别...它们指的是什么?
  • 我认为书中有错误。 struct LinkedBlock 似乎是错误的。你检查过这本书的更新/更高版本吗?
  • @4386427 这是本书的最新版本
  • 大家的共识似乎是你的书还有一些不足之处。

标签: c linked-list overhead


【解决方案1】:

开销是不属于您要存储的数据的所有内容。就像指向下一个和上一个元素的指针一样。

阻止列表是一个数组列表。每个数组包含许多元素。原则上,您的整个列表可以由一个带有所有元素数组的块节点组成。所以开销更少。

LinkedBlock 中的 head 指向 ListNode 有点令人困惑——它应该指向任何数据(没有 prev 和 next 指针)。

【讨论】:

  • 我从未听说过与列表一起使用的术语“展开”。在我的书中,这个术语通常是为循环保留的。有人吗?
  • 我也没有。
  • 天哪。展开列表。
【解决方案2】:

我认为这本书对struct LinkedBlock 的定义存在严重错误。让我们稍后再谈,并开始:

什么是开销?

struct ListNode 设计用于存储一个整数,但除了整数之外,每个节点还有两个指针。因此,对于每个节点,您需要分配 1 个整数 + 2 个指针。让我们假设 4 字节整数和 4 字节指针。所以每个节点将需要 4 + 2x4 = 12 个字节。因此,为了存储 1 项真实数据(即 1 个整数),您需要分配 12 个字节。您在指针上浪费了 8 个字节。这 8 个“浪费”的字节称为开销。它们仅用于簿记 - 不用于数据。

但它变得更糟......当分配动态内存时(通常在使用链表时这样做),会有一些额外的开销。分配器可能需要为每个malloc 提供一点额外内存来存储有关malloc 的信息。另一个问题是malloc ed 内存可能与某些固定块大小(例如 16 或 32 字节)对齐,因此如果分配 20 字节,则无法使用剩余的 12 字节 - 它们被浪费了。这就是本书所说的“分配开销”。 “分配开销”取决于系统,但本书假设每个 malloc 有 8 个额外开销字节。

所以现在每个malloc 'ed struct ListNode 占用:

4 个字节的整数

2 个指针 8 个字节

8 字节用于分配开销

总共 20 个字节,其中 4 个字节用于数据,16 个字节用于开销。因此,对于您需要存储的每个整数,您需要 20 个字节。如果你想存储 1000 个整数,你最终会浪费 16kb 的开销来存储 4kb 的数据。

现在回到struct LinkedBlock。在书中它是这样的:

struct LinkedBlock {
    struct LinkedBlock *next;
    struct LinkedNode *head;
    int nodeCount;
};

我很确定书中有一个错误,它应该看起来像这样:

struct LinkedBlock {
    struct LinkedBlock *next;
    int *dataArray;
    int nodeCount;
};

使用方法如下:

struct LinkedBlock pNode = malloc(sizeof(struct LinkedBlock));
pNode->dataArray = malloc( 100 * sizeof(int) );

第一个 malloc 需要 4 + 4 + 4 + 8 = 20 个字节。 (指针、指针、int、分配开销)

第二个malloc 需要 4 * 100 + 8 = 408 字节。 (100 int,分配开销)

所以总共有 428 个字节。

但是,由于malloc'ed 数据可以保存 100 个整数(对应于 400 个字节),因此您的开销只有 28 个字节。换句话说 - 每个整数平均使用 4.28 个字节。将其与每个整数需要 20 个字节的第一种方法进行比较。

为什么他只为 100 个元素的数组声明 8 个字节的开销?

这是因为数组是在一次调用中分配的,并且每个 malloc 调用都假定有 8 个字节的分配开销。

【讨论】:

  • 我认为分配开销甚至是讨论的一部分,这令人困惑。据我们所知,所有数据和节点都可以预先静态分配。 “阻止列表”节省空间这一点并没有实际意义,而且它会减少很多混乱。作者可能还会提到结构填充并进一步混淆讨论。
  • @Aksel 我有点同意。作者可以通过包含“分配开销”轻松证明这一点,而不会使事情变得更复杂。我还没有读过那本书,这里发布的页面让我觉得这样做值得。
【解决方案3】:

在普通链表中,1 个节点有 1 个元素和 2 个指针(8 个字节),2 个指针是开销,因为它不是您的数据。在展开的链表中,1 个节点有 100 个元素和 2 个指针(8 个字节),因此 100 个元素的开销为 8 个字节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-11
    • 2013-05-03
    • 1970-01-01
    • 2013-11-25
    • 2017-04-03
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    相关资源
    最近更新 更多