Деревья: связанные списки и массивы (эффективность)

Это вопрос задания, на который я затрудняюсь сформулировать ответ.

«Предположим, что дерево может иметь до k дочерних узлов на узел. Пусть v будет средним числом дочерних элементов на узел. Для каких значений v более эффективно (с точки зрения используемого пространства) хранить дочерние узлы в связанный список против хранения в массиве? Почему?"

Я верю, что могу ответить на вопрос "почему?" более или менее на простом английском языке - будет более эффективно использовать связанный список, потому что вместо того, чтобы иметь кучу пустых узлов (т.е. пустых индексов в массиве, если ваше среднее значение ниже максимального), занимая память, вы только выделяете пространство для узла в связанном списке, когда вы фактически вводите значение.

Таким образом, если у вас есть в среднем 6 дочерних элементов, когда ваш максимум равен 200, массив будет создавать пространство для всех 200 дочерних элементов каждого узла при создании дерева, но связанный список будет выделять пространство только для узлов по мере необходимости. Таким образом, со связанным списком используемое пространство будет приблизительно (?) средним; с массивом используемый интервал будет максимальным.

... Я не вижу, когда было бы более эффективно использовать массив. Это вопрос с подвохом? Должен ли я учитывать тот факт, что массив должен иметь ограничение на общее количество узлов при его создании?


person dc.    schedule 08.02.2010    source источник


Ответы (5)


Для многих широко используемых языков массиву потребуется выделить k адресов памяти (данных). Для односвязного списка потребуется 2 адреса на узел (данные и следующий). Для двусвязного списка потребуется 3 адреса на узел.

Пусть n будет фактическим количеством дочерних элементов определенного узла A:

  • Массив использует k адресов памяти.
  • Односвязный список использует 2n адресов
  • В двусвязном списке используется 3n адресов.

Значение k позволяет определить, будут ли 2n или 3n адресов в среднем выгоднее или менее по сравнению с простым сохранением адресов в множество.

person Sam Harwell    schedule 08.02.2010

... Я не вижу, когда было бы более эффективно использовать массив. Это вопрос с подвохом?

Это не вопрос с подвохом. Подумайте о накладных расходах памяти, которые есть у связанного списка. Как реализован связанный список (по сравнению с массивом)?

Кроме того (хотя это выходит за рамки вопроса!), потребление пространства не является единственным решающим фактором на практике. Кэширование играет важную роль в современных процессорах, и хранение отдельных дочерних узлов в массиве вместо связанного списка может значительно улучшить локальность кэша (и, следовательно, производительность дерева).

person Konrad Rudolph    schedule 08.02.2010
comment
Я не уверен, что вы подразумеваете под накладными расходами связанного списка. Вы говорите о памяти, необходимой для ссылок? - person dc.; 08.02.2010
comment
@dc: Хорошо, как реализованы связанные списки? Сколько памяти нужно? - person Konrad Rudolph; 08.02.2010

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

Совет: вы можете выделить весь массив сразу, если хотите, но обычно мы выделяем,
скажем, 4 элемента и изменяем его размер, удваивая размер, когда нам нужно больше места.

person Nick Dandoulakis    schedule 08.02.2010
comment
Однако речь шла исключительно о пространстве, а не о времени. - person Konrad Rudolph; 08.02.2010
comment
@ Конрад Рудольф, действительно. И из-за того, что я не вижу, когда было бы более эффективно использовать массив, я упомянул совет :) - person Nick Dandoulakis; 08.02.2010

Я могу себе представить, что это может быть очень хорошей и очень эффективной идеей во многих сценариях использовать LinkedList, если используемый элемент данных в любом случае имеет внутреннюю логику для предыдущего и следующего элемента, например, TimeTableItem или что-либо, что каким-то образом связано со временем. Они должны реализовывать интерфейс, поэтому реализация LinkedList может использовать это и не должна оборачивать элементы в свои собственные объекты узла. Вставка и удаление были бы здесь намного эффективнее, чем использование реализации List, которая внутренне жонглирует массивами.

person herzmeister    schedule 08.02.2010

Вы предполагаете, что массив не может быть динамически перераспределен. Если это возможно, массив выигрывает, потому что он не должен быть больше, чем k элементов (плюс постоянные накладные расходы), и потому что ему не нужно хранилище для указателей для каждого элемента.

person Mike Dunlavey    schedule 08.02.2010