Чем лучше развернутый связанный список, чем связанный список? - PullRequest
0 голосов
/ 31 января 2019

Я изучал книгу «Структура данных и простые алгоритмы», но я запутался, изучая «Сравнение связанных списков и развернутых связанных списков» ...

Что такое издержки?Почему он заявляет только 8 байтов служебной информации для массива 100 элементов?

Para from book

Ответы [ 3 ]

0 голосов
/ 31 января 2019

В обычном связанном списке, 1 узел имеет 1 элемент и 2 указателя (8 байт), 2 указателя являются накладными расходами, поскольку это не ваши данные.В развернутом связанном списке 1 узел имеет 100 элементов и 2 указателя (8 байт), следовательно, 8-байтовые служебные данные для 100 элементов.

0 голосов
/ 31 января 2019

Я думаю, что книга содержит серьезную ошибку в определении struct LinkedBlock.Давайте вернемся к этому позже и начнем с:

что такое издержки?

struct ListNode предназначен для хранения одного целого числа , но кроме тогоцелое число каждого узла имеет два указателя.Таким образом, для каждого узла вам нужно выделить 1 целое число + 2 указателя.Давайте предположим, что 4-байтовое целое и 4-байтовый указатель.Таким образом, каждому узлу потребуется 4 + 2x4 = 12 байтов.Таким образом, чтобы сохранить 1 элемент ваших реальных данных (1 целое число), вам нужно выделить 12 байтов.Вы потратили 8 байтов на указатели.Эти 8 «потраченных впустую» байтов называются издержками.Они используются только для бухгалтерии - не для данных.

Но это еще хуже ... При распределении динамической памяти (что вы обычно делаете при использовании связанного списка) возникают некоторые дополнительные издержки.Распределителю может потребоваться немного дополнительной памяти для каждого malloc для хранения информации о malloc.Другая проблема заключается в том, что malloc редактируемая память может быть выровнена по некоторому фиксированному размеру блока (например, 16 или 32 байта), поэтому, если вы выделяете 20 байтов, нет никакого способа использовать оставшиеся 12 байтов - они теряются.Это то, что книга называет «накладными расходами».«Расходы на выделение ресурсов» зависят от системы, но книга предполагает 8 дополнительных байтов служебных данных от каждого malloc.

Так что теперь каждый malloc 'ed struct ListNode занимает:

4 байтадля целого числа

8 байтов для 2 указателей

8 байтов для накладных расходов на выделение

Всего 20 байтов, где 4 байта для ваших данных и 16 байтов для заголовка.Таким образом, для каждого целого числа, которое вам нужно сохранить, вам понадобится 20 байтов.И если вы хотите хранить 1000 целых чисел, вы в конечном итоге тратите 16 КБ на служебные данные, чтобы хранить 4 КБ данных.

Теперь вернемся к 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 'могут содержать 100 целых чисел (соответствующих 400 байтам), ваши накладные расходы составляюттолько 28 байтов.Другими словами - в среднем вы используете 4,28 байта для каждого целого числа.Сравните это с первым методом, в котором для каждого целого числа требовалось 20 байтов.

Почему он указывает только 8 байтов служебной информации для массива 100 элементов?

Это произошло потому, чтомассив был выделен в одном вызове, и предполагается, что каждый вызов malloc имеет накладные расходы на выделение 8 байтов.

0 голосов
/ 31 января 2019

Накладные расходы - это все, что не является частью данных, которые вы хотите сохранить.Как и указатели на следующий и предыдущий элемент.

Список блокировок представляет собой список массивов.Каждый массив содержит несколько элементов.В принципе весь ваш список может состоять из одного блочного узла с массивом всех ваших элементов.Поэтому меньше накладных расходов.

Немного сбивает с толку то, что заголовок в LinkedBlock указывает на ListNode - он должен указывать на любые данные (без указателей prev и next).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...