展开的链表比链表如何好?

时间:2019-01-31 14:01:59

标签: c linked-list overhead

我在学习《简化数据结构和算法》这本书,但是在学习《比较链接列表和展开的链接列表》时却感到困惑...

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

Para from book

3 个答案:

答案 0 :(得分:3)

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

阻止列表是数组列表。每个数组包含许多元素。原则上,您的整个列表可以包含一个块节点,其中包含所有元素的数组。这样的开销就更少了。

LinkedBlock中的头指向ListNode有点令人困惑-它应该指向任何数据(没有上一个和下一个指针)。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

  

什么是开销?

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

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

因此,现在每个malloc'ed struct ListNode都占:

4个字节为整数

8个字节(用于2个指针)

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个字节。 (指针,指针,整数,分配开销)

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

总共有428个字节。

但是,由于malloc的数据可以容纳100个整数(相当于400个字节),因此开销仅为28个字节。换句话说-平均每个整数使用4.28个字节。将其与第一种方法每个整数需要20个字节的方法进行比较。

  

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

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