- •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
Контрольные вопросы
Какие объекты помещаются в программный стек при входе в функцию?
Как изменяется указатель программного стека при выходе из функции?
Что происходит с программным стеком при рекурсивном обращении функции к самой себе?
Напишите обратную польскую запись для выражения
Напишите послед овательность операций и состояние стека в процессе вычисления значения выражения, представленного польской записью из предыдущего примера.
3. Очередь
Очередью называют одномерную структуру данных с дисциплиной обслуживания "первый пришел – первый ушел". Такую дисциплину обслуживания также называют FIFO (First In – First Out), что означает то же самое. Все включения в очередь делаются на одном конце, а все исключения – на другом. Очередь может быть представлена массивом или списком. В этом разделе рассматривается представление очереди массивом (рис 1).
Рис 2. Очередь в массиве
Простейшее решение состоит в том, чтобы иметь два указателя для начала и конца очереди - F и R. F указывает место на начало очереди; R указывает на последний элемент очереди.
При самом простодушном подходе к выполнению операций включение и исключение выполняются следующим образом:
/* Поместить в очередь */ R=R+1; X[R]=Y;
/* Взять из очереди */ F=F+1; Y=X[F];
Заметим, что в процессе выполнения серии включений и исключений, очередь будет ”ползти” вдоль памяти, так как F и R непрерывно увеличиваются. Это означает чрезвычайно расточительное использование памяти. Проблему можно решить, отводя под очередь M позиций и неявно замыкая её в кольцо, так, что за последней позицией следует первая. Пусть очередь представлена структурой:
#define M 8 // длина массива, отводимого под очередь
struct QUEUE{
int Q[M]; // массив, используемый для хранения очереди
int F; // ИНДЕКС первого элемента очереди
int L; // ИНДЕКС ПОСЛЕДНЕГО
bool IsEmpty; // признак пустой очереди
};
QUEUE T; // экземпляр очереди над которой выполняются операции
Тогда включение и исключение примут вид:
/* Поместить в очередь */
T.L=(T.L==M-1) ? 0 : T.L+1;
if(!T.IsEmpty && T.F==T.L){
Переполнение();
}
T.Q[T.L]=x;
T.IsEmpty=false;
// взять из очереди
int z;
bool fl=T.F==T.L;
if(!T.IsEmpty){
z=T.Q[T.F];
T.F=T.F==M-1 ? 0 : T.F+1;
T.IsEmpty=fl;
} else {
Пусто();
}
// z – извлеченное из очереди значение
Здесь Переполнение и Пусто – подпрограммы, обрабатывающие соответствующие ситуации. Ситуация Пусто не является аварийной. В ситуации Переполнение программа должна либо перераспределить память под очередь, либо прекратить работу.
Контрольные вопросы
По каким правилам элементы помещаются в очередь и удаляются из очереди?
Как избежать перемещения очереди по памяти?
Вычислите значение U1000000, если Un=Un-1+2Un-2-3Un-3 и U0=U1=U2=U3=1
4. Массивы
4.1. Размещение прямоугольных массивов в последовательной памяти
В
качестве примера рассмотрим трёхмерный
прямоугольный массив
(3 слоя по 4 строки по 5 элементов в строке).
Такой массив можно представить в виде
параллелепипеда (рис 3.). Предположим,
что элементы массива следуют в памяти
в лексикографическом порядке, то
есть так, что первым изменяется последний
индекс. Такой порядок используется в
большинстве алгоритмических языков,
но есть и исключения, например, Фортран.
Порядковый номер элемента массива
A[i][j][k] можно вычислить по формуле:
i |
* |
Объем слоя |
+ |
j |
* |
Длина строки |
+ |
k |
В общем случае описание массива может иметь вид:
A[i1:j1][i2:j2]…[in:jn]
где im, jm – нижняя и верхняя граница индекса в m-м измерении. Каждый раз, когда программа обращается к элементу массива, она должна вычислить его адрес по заданным индексам k1,k2…kn. Функция упорядочения, которая это делает, имеет вид:
где L – искомый адрес; b – начальный адрес массива (адрес его 1-го элемента); Dm – объем m-го сечения массива (слоя, строки…) в байтах. В общем случае функцию упорядочения можно записать в виде:
,
где
Константу с называют базовым адресом массива, который определяется как адрес возможно несуществующего элемента массива, у которого все индексы равны нулю.
Пример: для массива с границами индексов 3:5,1:4,0:1 имеем:
D3=1
D2=(j3-i3+1)*D3=2
D1=(j2-i2+1)*D2=8
с=b-(i1*D1+i2*D2+i3*D3)=26*(b-1)
И функция упорядочения имеет вид:
L=25*(b-1)+8*k1+2*k2+k3
Функция упорядочения строится компиляторами автоматически. Исходные данные о массиве представляются обычно в виде информационного вектора массива:
IA=(n, число элементов, C, D1, D2,…Dn, i1, j1, i2, j2,…in, jn)
