кислород эффективного кодирования

1656565935 kislorod effektivnogo kodirovaniya

Тьяго Антунес

tcwFlKPuIAmf9FmE4RgcthAtBNcixfie9KM0

Много раз вы хотите сохранить информацию в своей программе и получить доступ к ней много раз. И вы часто храните его в очень простой структуре данных: массиве. И часто это работает очень хорошо! Но иногда это требует только а много времени окончить.

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

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

kN9uEnU437d1O1pcz8DzlWjz3wjqyJuxJah0
Да… Какой?

Итак, что такое структура данных?

Согласно Википедии:

у структура данных это формат организации и хранения данных, обеспечивающий эффективный доступ и модификацию»

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

Деревья достаточно сложны, чтобы быть очень быстрыми в том, что они делают, но достаточно просты, чтобы их можно было понять. И одна вещь, в которой они действительно хороши, это находить значение с минимальным использованием памяти.

Но как измерить, как эффективна структура данных на самом деле?

Вы когда-нибудь видели какие-то странные обозначения, которые люди используют онлайн, например O(n)? Это называется Big O Notation, и это стандартный способ оценки производительности структур и алгоритмов. Большое О, которое мы используем, является представлением худшего сценария: иметь что-то такое, что O(n) (с п количество элементов внутри) означает, что в худшем случае на это нужно время пчто действительно хорошо.

Внутри скобок мы написали п что является эквивалентом написания выражения y = x → . Он масштабируется пропорционально. Но иногда мы имеем разные выражения:

  • O(1)
  • O(log(n))
  • O(n)
  • O(n²)
  • O(n³)
  • О(н!)
  • O(e^n)

Чем ниже результат функции, тем эффективнее структура.
Есть несколько видов деревьев. Мы будем говорить о BST (деревья двоичного поиска) и AVL (автобалансированные деревья), которые обладают разными свойствами:

Yv-dffABeNKNVMXCEwjPU7tSrLoNILfBnHk7
Как видите, деревья AVL гораздо эффективнее, но гораздо сложнее!

Ладно, вы говорили обо всех этих странных обозначениях… так как работают деревья?

Название дерево происходит от его реального изображения: оно имеет корни, листья и ветви, и часто его изображают так:

Kan51et5e844FH0GbUNDMl8R2Hyb2Ck1-1xB
Обратите внимание, что 6 не лист, потому что он не находится в конце ветки!

Есть несколько конфессий, которые мы используем, а именно родители и дети с уникальными отношениями. Если x является отцом y потом y является ребенком x. На этом изображении 2 родительское для 5, затем 5 дочернее для 2. Каждый узел — каждая позиция со значением — может иметь только 1 родительского и 2 дочерних.

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

Бинарные деревья поиска

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

  • Если узлов нет, то первое введенное значение становится корень деревья.
  • Если есть узлы, то вставка выполняется следующими шагами: начиная с корня, если вводимое значение меньше текущего узла, пройдите через левую ветвь, иначе — через правую. Если вы находитесь на пустом месте, то ваша ценность имеет место!

В начале это может показаться несколько запутанным, но давайте напишем некоторый псевдокод, чтобы упростить его:

//This code won't compile in any language (that I know of) and only serves to demonstrate how the code would look like
def insert(Node n, int v) {    if n is NULL:        return createNode(v)    else if n.value < v:        n.right = insert(n.right, v)    else:        n.left = insert(n.left, v)    return n}

Что здесь происходит? Сначала проверяем, пустое ли место, где мы сейчас находимся. Если это так, мы создаем узел в этом месте с помощью функции createNode. Если он не пуст, мы должны увидеть, где мы должны разместить наш узел.

Эта демонстрация показывает, как это работает:

vGugwFtmjnxPoUkwaz4eMfXCyeeR3NfDqAid
Источник: http://www.mathwarehouse.com/programming/gifs/binary-search-tree.php

Таким образом, мы можем искать любое значение в дереве, не проходя через все узлы. Прекрасно!

Но это не всегда так хорошо, как на картинке выше. А если мы получим что-нибудь подобное?

9Ws05JR1XZhWP2S7Sq1oTQsBSDBow4oMUNCl
Ой, самый плохой сценарий!

В этом случае поведение дерева заставляет вас пройти через все узлы. Вот почему в самом худшем случае эффективность BST равна O(n), что делает его медленным.
Удалить из BST также легко:

  • Если у узла нет детей → удалите узел
  • Если узел имеет один дочерний узел → подключите родительский узел к его дочернему узлу и удалите узел
  • Если узел имеет 2 дочерних → замените его наиболее дочерним (крайним левым дочерним элементом) → смотрите изображение ниже
5FzpxzchOVtImfMifRlVUi2fgao-0NnMAzvW
Удаление числа 12 производится путем замены 12 на 9

Итак, теперь вы знаете все, что вам нужно о BST. Достаточно круто, а?

Но что если бы ты захотел ВСЕГДА имеете эффективное дерево? Что ты сделал бы?

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

Дерево AVL – это самобалансирующее дерево, имеющее определенные операции (так называемые вращения), позволяющие дереву оставаться. сбалансированный. Это означает, что каждый узел дерева будет иметь разницу высота между двумя его дочерними ветвями в пределах 1.

Благодаря этому дерево всегда будет иметь высоту log(n) (n — количество элементов), что позволяет вам искать элементы действительно эффективным способом.

UM1ijtzuMAJwnE0T47fU9ip84GDmF81nYBwC
Есть 11 элементов, а высота 4. Это означает, что приложение сделает максимум 4 поиска вниз! Это действительно эффективно, поскольку каждый нижний уровень содержит двойное количество элементов верхнего уровня.

Итак, теперь вы видите, какие хорошие и идеально сбалансированные деревья. Но как их сделать – настоящий вопрос. Я вспомнил это слово глубина раньше, поэтому давайте сначала разберемся.

95E-aGZFvGqAVy8BXaXga6fI-3Neol-5SQGV
Лист имеет высоту 0, а нелистовой узел имеет высоту максимума его дочерних элементов плюс 1.

Высота – это то, что позволяет нам понять, сбалансировано ли наше дерево или нет. И с его помощью мы можем определить, где проблема, и применить функции балансировки: вращение. Это действительно простые функции, которые состоят из обмена узлами между собой, чтобы устранить разницу высоты, но поначалу они могут выглядеть очень странно.

Существует 4 операции:

  • Вращение влево
  • Вращение вправо
  • Вращение влево-вправо
  • Вращение вправо-влево
gsNUXSbb3fP-OXM8Z9rLc1MW-Sfqiz7MljHP
Узел, где рост ребенка был больше 1, испытывает вращение (представьте себе пустое место с высотой -1, если вы вычислите его: баланс(6) = 1 — -1 = 2)

Вау, это было странно… как работают вращения?

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

Попытайтесь создать собственные деревья на этом веб-сайте: https://www.cs.usfca.edu/~galles/visualization/AVLtree.html

Он позволяет динамично наблюдать за вращениями и является отличным инструментом!
Случаев всего четыре, потому понять их будет легко.

8A62BNYoUXowG9koNOoAROgeQubxvXWHPUqM
Вращение вправо-влево. Это не более 2 основных оборотов!

Это все, что сейчас!

Деревья достаточно легко понять и с практикой вы сможете легко с ними работать. Применение их в вашем коде является основным ключом для повышения эффективности ваших программ.

Если у вас возникли вопросы относительно чего-то, с чем вы не поняли, не согласны или хотели бы предложить, не стесняйтесь связаться со мной через Twitter или по электронной почте!

Электронная почта: tiago.melo.antunes [at] техника [dot] ulisboa [dot] пт

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *