Словарь <Tkey, TValue>, Список <T> и реализация/время выполнения других коллекций

105
10

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


    Dictionary<TKey, TValue>
    List<T>
    Queue<T>
    Stack<T>
    и др.

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


Конечно, если кто-то чувствует, что он может предоставить эту информацию в этой теме, вы более чем рады!

спросил(а) 2020-03-25T19:46:17+03:00 2 месяца назад
1
Решение
75

О List<T>:


List<T> имеет два свойства: Capacity и Count, которые помогают уточнить, когда происходит изменение размера. Capacity - длина внутреннего массива в любой момент времени, а Count - количество элементов, добавленных в список. Если у вас есть оценка количества элементов, которые будут добавлены в список, Capacity может быть инициализирован (путем выбора соответствующего конструктора), что приведет к уменьшению или отсутствию изменений и, следовательно, повышению производительности.


Изменение размера (т.е. создание нового большего массива и копирование элементов один за другим в новый массив) происходит, когда вызывается метод Add<T>() и массив уже заполнен (Count == Capacity). Емкость нового массива удваивается (изначально, если он не задан пользователем, он начинается с 0, затем 4, а затем удваивается каждый раз, когда требуется больше места):


List<int> list = new List<int>();
//Capacity = 0, Count = 0

list.Add(52);
//Capacity = 4, Count = 1

list.Add(34);
list.Add(2);
list.Add(87);
//Capacity = 4, Count = 4

list.Add(56);
//Capacity = 8, Count = 5


Для больших n сложность времени для добавления нового элемента амортизируется константа O (1). Индекс поиска по индексу является постоянным O (1), а вставка или удаление элемента по заданному индексу является линейной O (n), поскольку она включает перенос остальной части элементы одной позиции (соответственно справа или слева). пространство, используемое для внутреннего массива, конечно, линейно относится к элементам массива, варьируется от n до 2n (или, если это имеет смысл: Math.Pow(2, Math.Ceiling(Math.Log(n, 2))):).

О Queue<T> и Stack<T>:


Изменение размера внутреннего массива Queue и Stack работает так же, как описано для List<T>. Общие операции эффективны O (1) (внутренне индексы сохраняются для элементов заголовка и хвоста очереди). Таким образом, задержка элемента в очереди или нажатие в стек требует амортизированного постоянного времени, dequeuing/poping требует постоянного времени.


О Dictionary<TKey, TValue>:


Словарь работает по-другому, и он хорошо описан здесь.

ответил(а) 2020-03-25T20:05:30.227832+03:00 2 месяца назад
54

Точные детали реализации каждой из них потребуют длительного объяснения (для каждого). Вместо этого я буду отсылать вас к книге Дж. Альбахари С# 5.0 В двух словах.


Однако я могу дать вам таблицу для рассмотрения памяти/времени для общих операций для диктонарных классов. Это время работы в миллисекундах, для выполнения 50 000 операций с словарем с целыми ключами и значениями на ПК с частотой 1,5 ГГц.


Type                Internal         Retrieve by     Memeory         Speed Random        Speed Seq        Speed Retrieval 
Structure Index? Overhead Insertion Insertion by Key
Unsorted
Dictionary<T> Hashtable No 22 30 30 20
Hashtable Hashtable No 38 50 50 30
ListDictonary Linked List No 36 50,000 50,000 50,000
OrderedDictionary Hashtable + Yes 59 70 70 40
Array
Sorted
SortedDictionary Red-Black No 20 130 100 120
<K, V> Tree
SortedList <K, V> 2xArray Yes 2 3,300 30 40
SortedList 2xArray Yes 27 4,500 100 180

Извините, я не могу предоставить это для других, которые вам нужны.


Надеюсь, это будет полезно.

ответил(а) 2020-03-25T19:46:17+03:00 2 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема