В отличие от рекурсивного алгоритма, верхним пределом для которого можно смело считать наборы длиной в 50 предметов, итеративный алгоритм способен обработать до 5 000 различных весов (общее количество предметов может быть гораздо больше).
Другие примеры сравнения рекурсивных и нерекурсивных алгоритмов, решающих одну и ту же задачу, будут приведены в лекции 12.
Возвратимся теперь к методам сортировки массивов, которым была посвящена лекция 4. Наиболее эффективный способ сортировки остался тогда не рассмотренным по причине того, что самая удобная его реализация подразумевает рекурсию.
Возьмем в сортируемом массиве срединный элемент: x:=a[(1+N)div 2];
Будем производить следующие действия:
начав с левого конца массива, будем перебирать его компоненты до тех пор, пока не встретим элемент a[i], больший х;
начав с правого конца массива, будем перебирать его компоненты до тех пор, пока не встретим элемент a[j], меньший х;
поменяем местами элементы 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).
Конечно же, существует и итеративный вариант алгоритма Быстрой сортировки, который еще более эффективен. Мы предлагаем читателям построить его самостоятельно.
10. Лекция: Адреса и указатели. Списочные структуры данных
Для того, чтобы лучше понять специфику динамически выделяемой памяти, рассмотрим сначала ее "антипод" - память, распределяемую статически.
Такое выделение памяти используется всякий раз при объявлении "обычных" переменных в разделе var. Каждая переменная обладает двумя атрибутами: именем и описанием.
var a: integer;
Описание переменной нужно для того, чтобы компилятор знал, сколько ячеек памяти необходимо выделить для ее хранения. Память под статическую переменную выделяется один раз (до начала работы программы), и затем до конца работы выделенная область памяти считается "занятой" - никакая другая информация не может быть записана в эту ячейку.
Имя переменной позволяет обращаться в процессе работы программы к той ячейке памяти, которая была выделена под эту переменную на этапе компиляции.