Алгоритмы и структуры данных
8.51K subscribers
283 photos
8 links
По всем вопросам: @altmainf

Уважаемый менеджер: @altaiface
Download Telegram
Метод обработки коллизий — метод открытой адресации (Двойное хеширование)

В этом методе приращения зондирующей последовательности вычисляются с использованием другой хэш-функции. Мы используем другую хеш-функцию h2(x) и ищем слот i*h2(x) в i-м повороте.

Пусть h(x) будет индексом слота, вычисленным с использованием хеш-функции.

Если слот h(x) % S заполнен, мы пробуем (h(x) + 1*h2(x)) % S
Если (h(x) + 1*h2(x)) % S также заполнено, то (h(x) + 2*h2(x)) % S
Если (h(x) + 2*h2(x)) % S также заполнено, то мы пробуем (h(x) + 3*h2(x)) % S
Понимание вычислительной сложности

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

Вот несколько способов найти ручку и порядок О:
1. O(n^2): Вы идете и спрашиваете первого человека в классе, есть ли у него ручка. Кроме того, вы спрашиваете этого человека о других 99 людях в классе, есть ли у них эта ручка и так далее. Это то, что называется O(n^2).
2. O(n): пойти и опросить каждого ученика индивидуально — это O(N).
3. O(log n): Теперь делим класс на две группы и спрашиваем: «Ручка на левой или на правой стороне класса?» Затем берем эту группу, и снова делим на две, спрашиваем еще раз и так далее. Повторяем процесс, пока у нас не останется один ученик, у которого будет ручка. Это то, что подрузамивается под O (log n).
Вычислительная сложность алгоритма для нахождения суммы двух чисел
Вычислительная сложность для алгоритма всех элементов списка/массива
Вычислительная сложность для алгоритма суммы всех элементов матрицы
Массивы

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

В языке C массив имеет фиксированный размер, что означает, что после того, как ему присвоен размер, его нельзя изменить.

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

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

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

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

1. Определите текущий размер массива.
2. Выделите память для нового массива, размер которого на один элемент больше текущего массива.
3. Скопируйте элементы исходного массива до нужной позиции в новый массив.
4. Добавьте новый элемент в нужную позицию в новом массиве.
5. Скопируйте оставшиеся элементы исходного массива после нужной позиции в новый массив.
6. Освободите память, занятую исходным массивом.
7. Обновите переменную массива, чтобы она указывала на новый массив.

Сложность: O(n), n - размер массива
Удаление элемента в массиве

Удаление элемента из несортированного массива включает в себя следующие шаги:

1. Найдите индекс удаляемого элемента с помощью линейного поиска.
2. Если элемент не найден, выведите сообщение и выйдите.
3. Сместите элементы после точки удаления на одну позицию влево.

Сложность: O(n), n - размер массива
Генерация подмассивов с использованием рекурсии

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

1. Остановитесь, если мы достигли конца массива
2. Увеличьте конечный индекс, если начало стало больше, чем конец.
3. Вывести подмассив от начала индекса до конца и увеличьте начальный индекс.

Сложность: O(n^2), n - размер массива
MO’s Algorithm

Представляет собой метод, используемый для эффективного ответа на запросы диапазона в массиве или последовательности.

Термин «МО» происходит от инициалов его изобретателей Миккеля Торупа и Питера М. Олсена.

Шаги алгоритма:
1. Сортируйте запросы по блоку, которому они принадлежат, а внутри блока — по их правой конечной точке.
2. Инициализируйте два указателя для представления текущего диапазона рассматриваемых элементов.
3. Выполните итерацию отсортированных запросов, соответствующим образом корректируя указатели для включения или исключения элементов из текущего диапазона.
4. По мере обработки каждого запроса алгоритм сохраняет ответ на запрос диапазона.

Сложность: O((N+Q)⋅*sqrt(N)), где N — размер массива и Q — количество запросов.
Связанный список

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

В отличие от массивов, связанные списки не требуют смежных ячеек памяти, что обеспечивает динамическое выделение и эффективную вставку и удаление.

Связанный список состоит из узлов, и каждый узел содержит данные и ссылку на следующий узел в последовательности.

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

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

Эта двунаправленная связь позволяет осуществлять обход как в прямом, так и в обратном направлении.

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

Добавление узла в начало двусвязного списка можно выполнить с помощью следующих шагов:

1. Создайте новый узел с заданными данными.
2. Установите следующий указатель нового узла на текущий заголовок списка.
3. Установите предыдущий указатель нового узла на NULL (так как это новая голова).
4. Если текущая голова не равна NULL, установите предыдущий указатель текущей головки на новый узел.
5. Обновите указатель головы, чтобы он указывал на новый узел.

Сложность: O(1)
Добавление узла в конец двусвязного списка

Добавление узла в конец двусвязного списка можно выполнить с помощью следующих шагов:

1. Создайте новый узел с заданными данными.
2. Если двусвязный список пуст (хвост имеет значение NULL), установите указатели заголовка и хвоста на новый узел.
3. Если двусвязный список не пуст:
3.1 Установите следующий указатель текущего хвоста на новый узел.
3.2 Установите предыдущий указатель нового узла на текущий хвост.
3.3 Обновите указатель хвоста, чтобы он указывал на новый узел.

Сложность: O(n)
Добавление узла между двумя узлами в двусвязном списке

Добавление узла между двумя узлами двусвязного списка можно выполнить с помощью следующих шагов:

1. Создайте новый узел с заданными данными.
2. Установите следующий указатель нового узла на следующий узел.
3. Установите предыдущий указатель нового узла на предыдущий узел.
4. Обновите указатель следующего узла предыдущего узла, чтобы он указывал на новый узел.
5. Если следующий узел не равен NULL, обновите предыдущий указатель следующего узла, чтобы он указывал на новый узел.

Сложность: O(1)
Циклический связанный список

Тип связанного списка, в котором последний узел списка указывает на первый узел, образуя замкнутый цикл или круг.

В отличие от традиционного связанного списка, где последний узел указывает на значение null или None, циклический связанный список создает соединение между последним и первым узлами.

Такая циклическая структура дает преимущества в определенных сценариях, например, упрощенный обход и эффективное управление данными в цикле.
Циклический двусвязный список

Cтруктура данных, сочетающая в себе функции как циклических, так и двусвязных списков.

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

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

Чтобы вставить узел в начало списка, выполните следующие действия:

1. Создайте узел, скажем, T.
2. Сделайте T -> следующий = последний -> следующий.
3. последний -> следующий = Т.
Добавление узла в конец циклического связного списка

Чтобы вставить узел в конец списка, выполните следующие действия:

1. Создайте узел, скажем, T.
2. Сделайте T -> следующий = последний -> следующий;
3. последний -> следующий = Т.
4. последний = Т.