- •1. Типы структур данных
- •2. Стек
- •Void stack::Push(int NewElement){
- •Int stack::Pop(){
- •If(!Empty){
- •2.1. Применения стека
- •2.1.1. Программный стек
- •Void main(void){
- •2.1.2.1. Обход шахматной доски ходом коня
- •Int I,j; // координаты клетки
- •Int move; // номер хода, которым покидаем клетку
- •Int I,j; // текущие координаты клетки
- •Int V; // указатель стека
- •Int BegMove,k,i2,j2;
- •2.1.2. Реализация рекурсии
- •If(Move(n,I,j,k,&i2,&j2) && !Board[i2][j2]){
- •If(Good){
- •2.1.2.1. Вычисление определенного интеграла
- •Interval Stack[maxstack];
- •2.1.3. Польская инверсная запись (полиз)
- •If(isalpha(z)) return 'б'; // буква – операнд
- •Int Poliz(char *in,char *out){
- •2.1.4. Вычисление выражения, представленного в полиз
- •Контрольные вопросы
- •3. Очередь
- •Контрольные вопросы
- •4. Массивы
- •4.1. Размещение прямоугольных массивов в последовательной памяти
- •4.2. Метод Айлиффа
- •Контрольные вопросы
- •5. Списочные структуры
- •5.1. Односвязный линейный список
- •5.1.1. Представление односвязного списка
- •5.1.2. Операции над односвязным списком
- •!!!!!!5.1.3. Голова списка
- •5.1.4 Циклический список
- •5.1.5. Пример. Сложение многочленов
- •Int px,py,pz; // степени X,y,z
- •Int PowerCmp(node *p, node *q){
- •Void PoliAdd(node *p, node *q){
- •5.2. Двусвязный линейный список
- •Void DeleteUzel(uzel *p){
- •5.3. Ортогональные списки
- •Int Row,Col; // строка и столбец элемента
- •5.4. Списки общего вида
- •5.4.1. Пример. Топологическая сортировка.
- •Int count; // счетчик числа элементов, предшествующих
- •Void TopSort(pair *p, int n_pair, file *result){
- •Void AddToTail(mains *head, mains *V){
- •5.5. Стек свободного пространства
- •Void DeleteNode(node *p, node *s){
- •5.6. Обслуживание свободного пространства
- •5.6.1. Счетчик ссылок
- •5.6.2. Сбор мусора
- •Контрольные вопросы
- •6. Множества
- •Int nElem; // число элементов в множестве
- •Int Elem[maxsize]; // элементы множества
- •Int Element; // номер элемента множества
- •Void Delete(node *p); // удаление узла вслед за p
- •Void setinlist::Delete(node *p){
- •Контрольные вопросы
- •7. Деревья
- •7.1. Бинарные деревья
- •7.2. Обход бинарного дерева
- •Void DirectByPass(node *Root){
- •Void InverseByPass(node *Root){
- •Int Tag; // может принимать значения operation или number
- •7.3. Прошитые деревья
- •Void InverseBypass(node *Root){
- •7.4. Другие представления бинарных деревьев
- •7.5. Представление деревьев общего вида
- •Int nSon; // действительное число сыновей узла
- •7.5.1. Представление деревьев общего вида бинарными деревьями
- •Контрольные вопросы
- •8. Конечный автомат
- •Int State; // текущее состояние
- •Int Class;
- •If(!Found){
- •Контрольные вопросы
- •9. Таблицы
- •9.1. Последовательные таблицы
- •Контрольные вопросы
- •9.2. Сортированные таблицы
- •9.2.1. Алгоритмы поиска в сортированной таблице
- •9.2.1.1. Бинарный поиск (дихотомия)
- •Int BinSearch(int Key, int n, int t[]){
- •Void *bsearch(const void *key, const void *base, size_t nelem, size_t width, int (*fcmp)(const void *a, const void *b ));
- •9.2.2. Вставка и удаление в сортированной таблице
- •9.2.3. Оценка трудоемкости сортировки !!!!!
- •9.2.4. Внутренняя сортировка
- •9.2.4.1. Сортировка подсчетом
- •Void CountSort(int n, int t[]){
- •9.2.4.2. Сортировка простым выбором
- •Void SimpleChoice(int n, int t[]){
- •9.2.4.3. Квадратичный выбор
- •9.2.4.6. Сортировка методом "пузырька"
- •Void BubbleSort(int n, int t[]){
- •9.2.4.7. Сортировка слиянием
- •9.2.4.4. Выбор из дерева
- •9.2.4.5. Сортировка простыми вставками
- •Void InsertSort(int n, int t[]){
- •Void Merge(int n, int *t, int m, int *V, int *r){
- •9.2.4.8. Сортировка фон Неймана
- •Void Join(int a[], int b[], int *left, int *right,
- •Int *kl, int *kr, int Step){
- •9.2.4.9. Сортировка Хоара (1962 г.) !!!!!
- •Int Partition(int m, int n, int t[]){
- •Void Hoar(int m, int n, int t[]){
- •Void qsort(void *base, size_t nelem, size_t width,
- •Int (*fcmp)(const void *, const void *));
- •9.2.4.10. Двоичная поразрядная сортировка
- •Int BitPart(unsigned int Left, unsigned int Right,
- •Void BitSort(unsigned int Left, unsigned int Right,
- •Void BinarySort(int n,unsigned Tab[], unsigned int keylen){
- •9.2.4.11. Цифровая поразрядная сортировка
- •Void DigitalSort(byte *t, int n, int KeyLen){
- •Int *Count;
- •Int *Pos; // позиции расстановки
- •9.2.1. Внешняя сортировка
- •9.2.1.1. Многопутевое слияние и выбор с замещением
- •9.2.1.2. Многофазное слияние
- •9.2.1.3. Фибоначчиево слияние
- •9.2.1.4. Каскадное слияние
- •9.2.1.5. Сортировка в одном файле
- •Контрольные вопросы
- •9.3. Древовидные таблицы
- •Void *Record; // указатель на запись таблицы
- •Int WhatSon; // каким сыном устанавливать новую запись –
- •Int CmpKeys; // результат сравнения ключей
- •Int Info;
- •Int Rank; // для доступа по индексу
- •9.3.1. Оценка трудоемкости поиска в случайном дереве
- •9.3.2. Оптимальные деревья
- •Int Info;
- •9.3.3. Сбалансированные деревья
- •9.3.4.1. Поддержание балансировки
- •9.3.5. Представление линейных списков деревьями
- •Int Info;
- •Int Rank;
- •Контрольные вопросы
- •9.4. Таблицы с прямым доступом
- •9.5. Рассеянные таблицы (Hash)
- •9.5.1. Анализ трудоемкости операций над рассеянной таблицей
- •Контрольные вопросы
- •Литература
- •454091, Г.Челябинск, ул.Свободы, 155/1
9.2.1. Внешняя сортировка
Рассмотренные методы сортировки были рассчитаны на то, что таблица целиком помещается в оперативной памяти и в любой момент открыт доступ к любому элементу таблицы. Внешняя сортировка отличается тем, что время доступа к данным на внешних носителях чрезвычайно велико по сравнению с временем доступа к оперативной памяти.
Предположим, что нужно отсортировать таблицу из 5000 R1-R5000 записей, а в оперативную память помещается не более 1000 записей. Решение может быть следующим – начать с внутренней сортировки каждого из 5 отрезков по 1000 записей, а затем слить полученные сортированные отрезки. Такой процесс – внутренняя сортировка с последующим внешним слиянием – является основой многих методов внешней сортировки.
В качестве введения рассмотрим метод, который можно назвать сбалансированным двухпутевым слиянием. Метод использует 4 файла. В первой фазе упорядоченные отрезки, получаемые внутренней сортировкой, помещаются поочередно в файлы 1 и 2 до тех пор, пока не исчерпаются входные данные. Начальная фаза распределения отрезков размещает пять отрезков следующим образом:
Файл 1: R1 – R1000; R2001 – R3000; R4001 – R5000
Файл 2: R1001 – R2000; R3001 – R4000
Файл 3: пусто
Файл 4: пусто
Затем файла 1 и 2 вновь позиционируем на начало и сливаем отрезки с этих файлов, получая отрезки вдвое более длинные, чем исходные. Эти отрезки попеременно записываются в файлы 3,4. Отрезок R4001 – R5000 в файле 1 не имеет пары для слияния в файле 2. Неявно добавим для создания такой пары в файл 2 фиктивный орезок длины 0. После первого прохода слияния получим:
Файл 1: пусто
Файл 2: пусто
Файл 3: R1 – R2000; R4001 – R5000
Файл 4: R2001 – R4000
Применив тот же алгоритм к файлам 3,4, в файлах 1,2 получим результат:
Файл 1: R1 – R4000
Файл 2: R4001 – R5000
Наконец, после последнего прохода в файле 3 получим R1 – R5000, и сортировка завершена.
Аналогично можно рассмотреть 3-х и более – путевое слияние. Пусть для сортировки выделено N файлов. Разделим их на 2 части – в одной M файлов, в другой - N-M файлов. Распределим исходные отрезки по возможности более равномерно по M файлам первой части и выполним M-путевое слияние, помещая результат слияния поочередно в оставшиеся N-M файлов. Затем выполним N-M – путевое слияние, помещая результаты слияния в файлы первой части.
9.2.1.1. Многопутевое слияние и выбор с замещением
Рассмотрим процесс порождения начальных отрезков, которые затем подвергаются слиянию. Пусть имеется Р возрастающих отрезков. Очевидным способом их слияния является следующий: из первых ключей каждого отрезка выбрать минимальный, соответствующую запись передать на выход и исключить из входных данных, затем этот процесс повторяется. Если Р велико, то целесообразно использовать дерево выбора из Р элементов. Пример 4-х путевого слияния изображен на рис. 39.
Р
ис.39
4х-путевое слияние
Техника выбора с замещением может использоваться на первой фазе внешней сортировки. В этом случае Р выбирается достаточно большим. Каждая запись при выводе замещается очередной записью из исходных данных. Если у новой записи ключ меньше, чем у только что выведенной, то она помечается как не участвующая в дальнейшем выборе, а значение Р уменьшается на единицу и процесс продолжается.
Пример. Пусть исходная последовательность ключей: 2 7 12 3 8 9 4 1 5 11 10 6 и Р=4
Процесс вывода начальных сортированных отрезков иллюстрируется таблицей:
Содержимое памяти |
Вывод |
|||
2 |
7 |
12 |
3 |
2 |
8 |
7 |
12 |
3 |
3 |
8 |
7 |
12 |
9 |
7 |
(4) |
8 |
12 |
9 |
8 |
(4) |
(1) |
12 |
9 |
9 |
(4) |
(1) |
12 |
(5) |
12 |
(4) |
(1) |
(11) |
(5) |
Конец отрезка |
4 |
1 |
11 |
5 |
1 |
4 |
10 |
11 |
5 |
4 |
6 |
10 |
11 |
5 |
… |
В
скобки заключены ключи, не участвующие
в дальнейшем выборе. Таким путем удается
получить упорядоченные последовательности
длиннее Р,
что важно, так как время внешней сортировки
слиянием в значительной мере зависит
от числа начальных отрезков. Э.Ф.Мур
предложил изящный способ доказательства
того, что средняя длина порождаемого
отрезка равна 2Р,
проведя аналогию со снегоочистителем,
движущимся по кругу. Пусть на кольцевую
дорогу непрерывно падают снежинки
(записи). Снежинки исчезают из системы
(записи выводятся), когда они
сбрасываются за пределы дороги. Точки
дороги обозначаются вещественными
числами x
(0
x
1).
Снежинка, падающая в точку х,
соответствует входной записи с ключом
х,
а снегоочиститель имитирует процесс
вывода. В установившемся режиме общее
число снежинок на дороге в точности
равно Р.
Каждый раз, когда снегоочиститель
проходит точку 0,
заканчивается формирование нового
отрезка. На рис.40 изображено поперечное
сечение дороги, когда система находится
в у
становившемся
режиме.
Рис. 39 Аналогия со снегоочистителем
Из рисунка видно, что количество снега, удаляемого за один оборот, вдвое превосходит количество снега, присутствующего на дороге в любой момент.
