Рубрики
Uncategorized

[[Красный – это 5 источников обучения] Таблица прыжков с трамплина 2019-04-16

Автор оригинала: David Wong.

Виноград Все видео: https://segmentfault. com/a/11…

Представьте себе следующий сценарий:

Interviewer: We have an ordered array of 2, 5, 6, 7, 9. We need to look up 7 and design an algorithm.
Candidate: At first glance, I believe everyone will see that it is dichotomy, O (logN) is over.
Interviewer: So what about changing this number into a linked list (2 - > 5 - > 6 - > 7 - > 9)?
Candidate: It's simple, binary tree, the same logN.
Interviewer: Then please write the complete code by hand!
Examinee: pawn

Представьте, что вам дают бумагу для набросков, ручку, редактора. Можете ли вы мгновенно реализовать красно-черное дерево или дерево AVL? Это тяжело. На это требуется время. Это требует много деталей. Очень сложно ссылаться на кучу деревьев, таких как алгоритмы и структуры данных, а также на код в Интернете.

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

Как это решить? Во-первых, таблица находится в исходном состоянии без каких-либо элементов, аналогично следующему рисунку: Итак, давайте продолжим и вставим элемент 2, и он станет таким. Затем мы бросаем монетку, и она оказывается положительной. Затем мы вставляем 2 в слой L2 следующим образом: продолжайте бросать монету, и результат будет противоположным. Затем вставка элемента 2 прекращается. Структура таблицы вставки показана на рисунке выше. Далее давайте вставим элемент 5. Как и элемент 2, теперь вставьте элемент 5 в слой L1 следующим образом: Далее продолжайте бросать монеты. Если он положительный, он поднимается на уровень выше. В противном случае это прекратится. Продолжайте вставлять другие новые элементы. Итак, наконец, то, что мы делаем, показано на рисунке ниже. Таким образом, создается список пропусков. Конечно, из-за его небольшого размера результат может оказаться не идеальным столом для прыжков. Но если количество элементов n очень велико, студенты, изучавшие теорию вероятностей, знают, что структура итоговой таблицы должна быть очень близка к идеальной

Далее давайте рассмотрим вставку. Нам нужно вставить 4. Что мы можем сделать? Начните с верхнего уровня, чтобы найти предыдущее значение каждого узла, превышающее 4, затем бросьте монету, случайным образом выберите количество слоев и вставьте его. Например, это значение равно 4. Затем вставьте его, как показано на следующем рисунке.

Мы обнаружили, что он добавит новый слой и соединит те же уровни. Затем операция вставки завершается.

Операция удаления: Операция удаления аналогична операции вставки, включая следующие три шага: 1. Найдите узел, который необходимо удалить 2, удалите узел 3 и отрегулируйте указатель.

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

1. Зачем вы кладете монеты? Давайте сначала объясним процесс подбрасывания монет: количество слоев узлов таблицы переходов ограничено 64 (до redis 5.0-32). Если вы хотите бросать монеты 64 раза подряд в 64 слоя, у вас должно быть достаточно узлов. redis ограничивает вероятность подбрасывания монеты до 1/4, поэтому вероятность достижения 64 слоев равна (1/2)^ 128, как правило, единице. Максимальная память, которую может иметь 64-разрядный компьютер, не может хранить так много zskiplistNode, поэтому верхний предел для базового использования 64 слоев достаточно высок, независимо от того, насколько он высок, нет необходимости тратить память головного узла. Поэтому монеты помещаются для экономии памяти, сохраняя данные как можно меньше.

2. Что такое измеритель прыжка? Где его использовать? Skiplist-это упорядоченная структура данных. Он может быстро получать доступ к узлам, поддерживая несколько указателей на другие узлы в каждом узле. Таблицы переходов поддерживают поиск узлов со средней сложностью O (logN) и наихудшей сложностью O (N). В большинстве случаев эффективность таблиц переходов сопоставима с эффективностью балансовых деревьев, а реализация таблиц переходов проще, чем у балансовых деревьев. Redis использует таблицы переходов в качестве одной из базовых реализаций ключей упорядоченного набора. Если упорядоченный набор содержит больше элементов или если элементы элементов в упорядоченном наборе являются более длинными строками, Redis использует таблицы переходов в качестве базовых реализаций упорядоченных наборов. Есть ли много мест, где прыжковые метры так хороши в Redis? Ответ-Нет. Redis использует таблицы переходов только в двух местах. Один из них заключается в реализации ключей упорядоченного набора, другой-в использовании их в качестве внутренних структур данных в узлах кластера. Кроме того, таблицы переходов больше не используются в Redis.

3. Как работает счетчик прыжков? Давайте взглянем на исходный код списков пропусков:

typedef struct zskiplistNode {
            SDS ele; // element
            Double score; //score
            Strct zskiplistNode * backward; // Back Pointer, which is used to access nodes from the end of the table to the head of the table, is different from the forward pointer, which can jump more than one node at a time. Each node has only one Back Pointer.
            struct zskiplistLevel {
                Strct zskiplistNode * forward; // forward pointer, each layer has a pointer to the end of the table. Used to access nodes from the head to the end of the table.
                Unigned long span; // span, the span of the layer is used to record the distance between two nodes. The longer the span between two nodes, the farther they are; the span of the node pointing to NULL is 0.
            } level[];   
        } zskiplistNode;
        // The level array of the jump table can contain multiple elements, each of which contains a pointer to other nodes, through which the program can speed up access.
        // Generally speaking, the more layers there are, the faster access to other nodes will be.
        // Each time a new jump table node is created, the program randomly generates a value between 1 and 64 as the size of the level array according to the power law (the larger the number, the smaller the probability of occurrence) which is the height of the layer.
    typedef struct zskiplist {
        Strct zskiplistNode * header, * tail; // Header and Tail Pointer
        Unsigned long length; // number of nodes
        Int level; // Layer number of nodes with the largest number of layers
    } zskiplist;

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

What else? When we orderly set Zset code in gdb, we find that the program will create a dictionary dict before creating skiplist. So what is the function of this dict? The function of dict is a hashtable, which maps the relationship between elements and the score in zset. With this mapping table, the fractional time complexity of finding an element becomes O (1).

4. Причины, по которым redis использует таблицы переходов вместо балансовых деревьев Skplist и элементы различных деревьев равновесия (таких как AVL, красно-черное дерево и т. Д.) Расположены по порядку, в то время как хэш-таблицы-нет. Таким образом, хэш-таблица может выполнять поиск только по одному ключу, что не подходит для поиска по диапазону. Поиск диапазона относится к нахождению всех узлов, размер которых находится между двумя указанными значениями.

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

Вставка и удаление сбалансированного дерева может привести к корректировке поддерева. Логика вставки и удаления списка пропусков сложна. Для вставки и удаления skiplist нужно только изменить указатели соседних узлов, и операция проста и быстра.

Список пропусков более гибок, чем дерево баланса, с точки зрения использования памяти. Вообще говоря, каждый узел сбалансированного дерева содержит два указателя (указывающих на левое и правое поддеревья соответственно), в то время как skiplist содержит среднее количество указателей 1/(1-p) на узел в зависимости от размера параметра P. Если, как и реализация в Redis,/4, среднее количество указателей на узел составляет 1,33, что более выгодно, чем сбалансированное дерево.

Временная сложность поиска одного ключа, списка пропусков и дерева баланса составляет O (log n), что примерно одинаково; в то время как хэш-таблица сохраняет низкую вероятность конфликта значений хэша, временная сложность поиска близка к O (1), а производительность выше. Таким образом, различные структуры карт или словарей, которые мы обычно используем, в основном основаны на хэш-таблицах.

Список пропусков намного проще, чем дерево баланса, с точки зрения сложности реализации алгоритма.

Наконец, научитесь применять, знайте, что такое skiplist, нам также нужно знать, как его используют старые владельцы, вы можете подумать о Redis ZADD, ZRANGE, ZRANGEBYSCORE и других командах, как его использовать.

Если вы хотите узнать больше об анализе исходного кода таблицы переходов, рекомендуется прочитать таблицу переходов в Примечаниях по обучению Redis 2018-05-29 изучение исходного кода redis.