Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
1 Программирование на Паскаль.doc
Скачиваний:
20
Добавлен:
26.04.2019
Размер:
1.18 Mб
Скачать

Эффективность

В отличие от рекурсивного алгоритма, верхним пределом для которого можно смело считать наборы длиной в 50 предметов, итеративный алгоритм способен обработать до 5 000 различных весов (общее количество предметов может быть гораздо больше).

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

Быстрая сортировка2

Возвратимся теперь к методам сортировки массивов, которым была посвящена лекция 4. Наиболее эффективный способ сортировки остался тогда не рассмотренным по причине того, что самая удобная его реализация подразумевает рекурсию.

Алгоритм Быстр

  1. Возьмем в сортируемом массиве срединный элемент: x:=a[(1+N)div 2];

  2. Будем производить следующие действия:

    1. начав с левого конца массива, будем перебирать его компоненты до тех пор, пока не встретим элемент a[i], больший х;

    2. начав с правого конца массива, будем перебирать его компоненты до тех пор, пока не встретим элемент a[j], меньший х;

    3. поменяем местами элементы a[i] и a[j];

до тех пор, пока не произойдет "рандеву". В результате массив будет разделен на две части. В левой части окажутся все компоненты, меньшие х, а в правой - большие х.

Теперь применим эти же действия к левой и к правой части массива - рекурсивно.

Реализация алгоритма Быстр

type index = 1..N;

var a: array[index] of integer;

procedure quicksort(l,r:index);

var i,j: index;

x,z: integer;

begin

i:= l;

j:= r;

x:= a[(l+r)div 2];

repeat

while a[i]< x do inc(i);

while a[j]> x do dec(j);

if i <= j

then begin

z:= a[i];

a[i]:= a[j];

a[j]:= z;

inc(i);

dec(j);

end;

until i>j;

if l<j then quicksort(l,j);

if i<r then quicksort(i,r);

end;

begin {тело программы}

...

quicksort(1,n);

...

end.

Эффективность алгоритма Быстр

Алгоритм Быстрой сортировки имеет в среднем1) сложность N*log N и, следовательно, относится к улучшенным методам сортировки массивов (см. лекцию 4). Кроме того, даже среди улучшенных методов упорядочения Быстрая сортировка дает наилучшие результаты по времени (для относительно больших входных последовательностей - начиная с N = 100).

Конечно же, существует и итеративный вариант алгоритма Быстрой сортировки, который еще более эффективен. Мы предлагаем читателям построить его самостоятельно.

Адреса и указатели. Списочные структуры данных Статически выделяемая память

Для того, чтобы лучше понять специфику динамически выделяемой памяти, рассмотрим сначала ее "антипод" - память, распределяемую статически.

Такое выделение памяти используется всякий раз при объявлении "обычных" переменных в разделе var. Каждая переменная обладает двумя атрибутами: именем и описанием.

var a: integer;

Описание переменной нужно для того, чтобы компилятор знал, сколько ячеек памяти необходимо выделить для ее хранения. Память под статическую переменную выделяется один раз (до начала работы программы), и затем до конца работы выделенная область памяти считается "занятой" - никакая другая информация не может быть записана в эту ячейку.

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

Адреса

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

При страничной организации памяти адреса являются составными и состоят из номера сегмента памяти и смещения ячейки относительно начала этого сегмента.

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

Для обращения к статически заданной переменной можно использовать как ее имя, объявленное в разделе var, так и ее физический адрес.

Например, "адрес" одной и той же географической точки можно записать по-разному: "49°47' северной широты и 86°36' восточной долготы" или просто "вершина пика Белуха Восточная1)".

Указатели

Для того чтобы хранить (цифровые) адреса, нужны особые переменные. Их называют указателями и относят к специальному типу данных.

Описание указателей

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

var <имя_указателя>: ^<тип_адресуемой_переменной>;

Например:

var p: ^integer;

q: ^real;

s: ^array[1..10] of byte;

Кроме того, существуют универсальные нетипизированные указатели, которые могут хранить адрес переменной любого типа:

var <имя_указателя>: pointer;

Операции с указателями

Определение адреса

Физический адрес любой переменной можно узнать при помощи стандартной функции addr(<имя_переменной>):<указатель> или унарной операции @<имя_переменной>.

В зависимости от значения директивы компилятора {$T}, результатом операции @ будет либо типизированный указатель (если установлено {$T+}), тип которого будет определен в соответствии с типом использованной переменной, либо нетипизированный указатель pointer (если установлено {$T-}).

Результат функции addr() совместим с указателями любых типов:

p:= addr(x); {x: real; p: ^byte)