- •Оглавление
- •Введение
- •Раздел 1. Основные структуры данных
- •Тема 1. Введение в структуры данных. Динамическое распределение памяти
- •Классификация структур данных
- •1.2. Переменные-указатели и динамическое распределение памяти.
- •Например, указатели на простейшие базовые типы вводятся следующим образом:
- •Var pStr1,pStr2 :TpString; {переменные-указатели на строки}
- •1.3. Дополнительные вопросы использования переменных-указателей
- •1.4. Контрольные вопросы по теме
- •Тема 2. Структуры данных “стек” и “очередь”
- •2.1. Что такое стек и очередь?
- •2.2. Статическая реализация стека
- •2.3. Динамическая реализация стека
- •{Ссылочный тип для адресации элементов стека}
- •2.4. Статическая реализация очереди
- •2.5. Динамическая реализация очереди
- •{Ссылочный тип для адресации элементов очереди}
- •2.6. Практические задания
- •2.7. Контрольные вопросы по теме
- •Тема 3. Основы реализации списковых структур
- •3.1. Структуры данных типа “линейный список”
- •3.2. Первый способ статической реализации списка.
- •3.3. Второй способ статической реализации списка.
- •3.4. Управление памятью при статической реализации списков
- •3.5. Динамическая реализация линейных списков
- •3.6. Практические задания
- •3.7. Контрольные вопросы по теме
- •Тема 4. Усложненные списковые структуры
- •4.1. Двунаправленные линейные списки
- •4.2. Комбинированные структуры данных: массивы и списки указателей
- •4.3. Комбинированные структуры данных: массивы и списки списков
- •4.4. Практические задания.
- •4.5. Контрольные вопросы по теме
- •Тема 5. Основные понятия о древовидных структурах
- •5.1. Основные определения
- •5.2. Двоичные деревья
- •5.3. Идеально сбалансированные деревья
- •5.4. Практические здания
- •5.5. Контрольные вопросы по теме
- •Тема 6. Реализация поисковых деревьев
- •Двоичные деревья поиска.
- •6.2. Добавление вершины в дерево поиска
- •6.3. Удаление вершины из дерева поиска
- •6.4. Практические задания
- •Контрольные вопросы по теме
- •Тема 7. Дополнительные вопросы обработки деревьев. Графы.
- •Проблемы использования деревьев поиска
- •7.2. Двоичные деревья с дополнительными указателями
- •7.3. Деревья общего вида (не двоичные).
- •Представление графов
- •Практические задания
- •Контрольные вопросы по теме
- •Раздел 2. Алгоритмы сортировки и поиска
- •Тема 1. Классификация методов. Простейшие методы сортировки
- •1.1. Задача оценки и выбора алгоритмов
- •1.2. Классификация задач сортировки и поиска
- •1.3. Простейшие методы сортировки: метод обмена
- •1.4. Простейшие методы сортировки: метод вставок
- •1.5. Простейшие методы сортировки: метод выбора
- •1.6. Практическое задание
- •1.7. Контрольные вопросы по теме
- •Тема 2. Улучшенные методы сортировки массивов
- •2.1. Метод Шелла
- •2.2. Метод быстрой сортировки
- •2.3. Пирамидальная сортировка
- •2.4. Практическое задание
- •2.5. Контрольные вопросы по теме
- •Тема 3. Специальные методы сортировки
- •3.1. Простейшая карманная сортировка.
- •3.2. Карманная сортировка для случая повторяющихся ключей
- •3.3. Поразрядная сортировка
- •3.4. Практическое задание
- •3.5. Контрольные вопросы по теме
- •Тема 4. Поиск с использованием хеш-функций
- •4.1. Основные понятия
- •4.2. Разрешение конфликтов: открытое хеширование
- •4.3. Разрешение конфликтов: внутреннее хеширование
- •4.4. Практические задания
- •4.5. Контрольные вопросы по теме
- •Тема 5. Внешний поиск и внешняя сортировка
- •5.1. Особенности обработки больших наборов данных
- •5.2. Организация внешнего поиска с помощью б-деревьев.
- •5.4. Поиск элемента в б-дереве.
- •5.5. Добавление вершины в б-дерево
- •5.6. Удаление вершины из б-дерева
- •5.7. Внешняя сортировка
- •5.8. Практические задания
- •5.9. Контрольные вопросы по теме
- •Основные термины и понятия
- •Литература
3.2. Карманная сортировка для случая повторяющихся ключей
Рассмотренный метод можно обобщить следующим образом. Пусть по-прежнему ключи могут иметь значения только от 1 до n, но во входном наборе каждое значение может повторяться любое число раз, в том числе и ноль. Пусть исходный массив содержит m элементов, причем m>n. В этом случае с одним и тем же ключом может быть связано несколько элементов, и их нельзя поместить в одну ячейку результирующего массива.
Очевидным решением является использование вспомогательных списков для хранения элементов с одинаковыми ключами. Тем самым, приходим к использованию комбинированной структуры данных, а именно – массиву списков. Каждая ячейка массива соответствует одному конкретному значению ключа в диапазоне от 1 до n и хранит указатель на связанный список одноключевых элементов.
Тогда прежде всего надо распределить элементы входного набора по ячейкам результирующего массива в соответствии со значениями ключей, создавая и дополняя при необходимости вспомогательные списки. После этого, если требуется получить общий результирующий отсортированный набор данных, можно объединить все списки, добавляя в конец одного списка начало другого. Это легко реализуется, если в каждой ячейке результирующего массива хранить не только адрес первого элемента списка, но и адрес последнего элемента.
Пример. Пусть задан следующий входной набор из 15 элементов с диапазоном изменения ключей от 1 до 5 (в скобках указан ключ элемента):
а1(4), а2(2), а3(5), а4(1), а5(4), а6(3), а7(4), а8(3), а9(5), а10(1), а11(3), а12(2), а13(2), а14(5), а15(3)
Тогда эти элементы будут распределены следующим образом:
-
ключ
у
а4
а10
казатели1
начало
к
а2
а12
а13
онец2
начало
к
а6
а8
а11
а15
онец3
начало
конец
4
н
а1
а5
а7
ачалоконец
5
н
а3
а9
а14
ачалоконец
После объединения списков получим:
а4, а10, а2, а12, а13, а6, а8, а11, а15, а1, а5, а7, а3, а9, а14
Для программной реализации необходимо объявить массив указателей и ссылочный тип для поддержки списков. Дополнительные затраты памяти связаны в первую очередь с реализацией дополнительных списков, т.к. общее число элементов в этих списках равно m, а кроме того для каждого элемента надо 4 байта для адресных полей. Трудоемкость данного метода оценивается соотношением O(m+n), а при m>>n становится пропорциональной числу элементов m.
3.3. Поразрядная сортировка
Данный метод является обобщением карманной сортировки. Пусть известно, что каждый ключ является k–разрядным целым числом. Например, если k = 4, то все ключи находятся в диапазоне 0000 – 9999. Смысл поразрядной сортировки заключается в том, что k раз повторяется карманная сортировка. На первом шаге все ключи группируются по младшей цифре (разряд единиц). Для этого в каждом ключе выделяется младшая цифра и элемент помещается в соответствующий список-карман для данной цифры. Потом все списки объединяются и создается новый массив, в котором элементы упорядочены по младшей цифре ключа. К этому массиву опять применяется карманная сортировка, но уже по более старшей цифре (разряд десятков): в каждом ключе выделяется вторая справа цифра и элементы распределяются по соответствующим спискам. Потом списки объединяются в массив, где элементы будут упорядочены уже по двум младшим цифрам. Процесс распределения по все более старшим цифрам с последующим объединением повторяется до старшей цифры (разряд k).
Поскольку цифр всего 10, то для реализации метода необходим вспомогательный массив из 10 ячеек для хранения адресов соответствующих списков.
Пример. Пусть имеется исходный набор из 15-ти двухразрядных ключей (k=2):
56, 17, 83, 09, 11, 27, 33, 02, 16, 45, 08, 37, 66, 99, 90
Первый шаг: выделяем младшую цифру и распределяем ключи по десяти спискам:
ключ 56 в список для цифры 6, ключ 17 в список для цифры 7, ….., ключ 16 опять в список для цифры 6 и т.д.
-
0
1
2
3
4
5
6
7
8
9
901102834556170809
33162799
6637
Объединяем списки: 90, 11, 02, 83, 33, 45, 56, 16, 66, 17, 27, 37, 08, 09, 99
В этом наборе ключи упорядочены по младшей цифре
Второй шаг: выделяем старшую цифру (десятки) и распределяем ключи по своим спискам:
ключ 90 в список для 9, ключ 11 в список для 1, ключ 02 в список для 0 и т.д.
-
0
1
2
3
4
5
6
7
8
9
02112733 4556668390
08163799
0917
Объединение этих списков дает отсортированный набор:
02, 08, 09, 11, 16, 17, 27, 33, 37, 45, 56, 66, 83, 90, 99
Для программной реализации необходимо объявить десятиэлементный массив и ссылочный тип для организации списков. Удобно вместе с началом каждого списка хранить указатель на его последний элемент, что упрощает как добавление новых элементов в конец списка, так и объединение отдельных списков. Внешний цикл алгоритма повторяется k раз (разрядность ключа). Каждый раз внутри этого цикла необходимо:
обнулить все 20 указателей
циклом по числу элементов (m) распределить элементы по своим спискам, выделяя в ключе необходимую цифру
циклом по 10 объединить списки в новый набор данных
В целом, поразрядная сортировка не эффективна при малых объемах входных данных, но чем больше этот объем, тем выше эффективность метода. Трудоемкость пропорциональна объему входных данных, что лучше чем у быстрой сортировки. Платой за это являются дополнительные затраты памяти для поддержки вспомогательных списков.
Интересно отметить, что данный метод очень хорошо подходит для современных архитектур вычислительных систем с конвейерной обработкой данных и использованием нескольких процессоров.