Песни о Паскале - [91]

Шрифт
Интервал

Вы принимаете эту формулу? Тогда перейдем к процедуре быстрой сортировки по имени QuickSort (Quickly – «быстро», Sort – «сортировка»). Вот она вместе с проверяющей её программой.


>{ P_43_2 QuickSort – Быстрая сортировка }


>const CSize=10; { размер массива }

>type TNumbers = array [1..CSize] of Integer;

>var Arr : TNumbers;


>      { Процедура быстрой сортировки }

>procedure QuickSort(var arg: TNumbers; aL, aR: Integer);

>var

>      L, R : integer; { левый и правый индексы }

>      M, T : Integer; { среднее значение и временное хранилище }

>begin

>      { Начальные значения левого и правого индексов }

>      L:= aL; R:= aR;

>      { Вычисляем среднее по трём (порог для сравнения ) }

>      M:= (arg[L] + arg[(L + R) div 2] + arg[R]) div 3;

>      repeat       { Цикл встречного движения }

>      { Пока левый элемент меньше среднего,

>      двигаем левый индекс вправо }

>      while arg[L] < M do L:=L+1;

>      { Пока правый элемент больше среднего,

>      двигаем правый индекс влево }

>      while arg[R] > M do R:=R–1;

>      { После остановки сравниваем индексы }

>      if L <= R then begin

>      { Здесь индексы ещё не "встретились", поэтому,

>      если левый элемент оказался больше правого,

>      меняем их местами }

>      if arg[L]>arg[R] then begin

>      t:= arg[L]; arg[L]:= arg[R]; arg[R]:= t;

>      end;

>      { Индексы «делают шаг» навстречу друг другу }

>      L:=L+1; R:=R-1;

>      end;

>      until L > R; { пока индексы не "встретятся" }

>      { если левая часть не отсортирована, то сортируем её }

>      if R > aL then QuickSort(arg, aL, R);

>      { если правая часть не отсортирована, то её тоже сортируем }

>      if L < aR then QuickSort(arg, L, aR);

>      { выход после сортировки обеих частей }

>end;

>      { Процедура распечатки массива, arg – строка сообщения }

>procedure ShowArray(const arg: string);

>var i: integer;

>begin

>      Writeln(arg);

>      for i:=1 to CSize do Writeln(Arr[i]);

>      Readln;

>end;

>var i: integer;

>begin       {--- Главная программа ---}

>      { Заполняем массив случайными числами }

>      for i:=1 to CSize do Arr[i]:=1+Random(1000);

>      ShowArray('До сортировки:');

>      QuickSort(Arr, 1, CSize);

>      ShowArray('После сортировки:');

>end.


Взгляните на параметры процедуры QuickSort. Вместе со ссылкой на массив, в процедуру передаются левая (aL) и правая (aR) границы сортируемой части массива (индексы). В процедуре вычисляется вес среднего арбуза по выбранной нами формуле и организуется поочередное встречное движение левого и правого индексов.

Самое интересное происходит после «встречи» индексов, когда массив разбит на две части. Удивительно, что теперь снова дважды вызывается та же самая процедура QuickSort: сначала для левой части массива, а затем – для правой (эти операторы выделены курсивом). Вспомните, – точно так же поступали и фермеры при сортировке арбузов.

«Так там фермеры, а здесь Паскаль! Позволено ль процедуре вызывать саму себя?» – слышу недоверчивый вопрос. Мы свыклись с тем, что из одной процедуры вызывают другую, из второй, – третью и так далее. Но чтобы саму себя? Это ж змея, глотающая свой хвост! Не оттого ли запутался фермер Лефт?

О рекурсии и стеке

Такой самовызов процедур называют рекурсией. «У попа была собака…» – помните? Это рекурсия, познакомимся с нею ближе (с рекурсией, а не собакой).

Легко заметить, что повторные вызовы процедуры QuickSort выполняются с другими значениями левой и правой границ. Чем глубже вызов, тем уже эти границы. С некоторого момента условия (R > aL) и (L < aR) перестают выполняться, и происходит выход из процедуры, – здесь фермеры возвращаются к несортированным частям массива. Таким образом, при выходе мы снова попадаем в эту же процедуру, но в другое место – следующее за вызовом. Окончательный выход из процедуры в главную программу случится только по завершении сортировки всего массива!

Напрашивается вопрос: какова судьба локальных переменных и параметров при повторных входах в процедуру? Ведь они изменятся, а это должно нарушить работу процедуры. Параметры и локальные переменные действительно изменяются, но это не путает алгоритм. Почему?

Разгадка в том, что при каждом входе в процедуру для её параметров и локальных переменных выделяется новый участок памяти. Теперь это будут уже другие параметры и локальные переменные, но с прежними названиями. Однако предыдущие их значения не теряются, а сохраняются в памяти, называемой стеком (Stack).

Что такое стек и как он работает? Случалось ли вам паковать рюкзак или глубокую сумку? Тогда вы знакомы со стеком. Все, что уложено в рюкзак, будет извлекаться из него в обратном порядке. Так же устроен и стек: при каждом вызове процедуры память для параметров и локальных переменных выделяется на его вершине. Эти новые значения временно закрывают предыдущие значения параметров, и так происходит при каждом входе в процедуру.

При выходе из неё последние значения параметров и локальных переменных удаляются с вершины стека, и тогда вновь открываются ранее скрытые. Так процедура «вспоминает» о неоконченной работе, и продолжает действия с параметрами, сохраненными в стеке ранее. В некоторый момент стек пустеет (когда все вещи из рюкзака вынуты), и тогда происходит окончательный выход из процедуры в главную программу.


Рекомендуем почитать
Столократия

15/09/2017rusamlib.ruhttp://samlib.rusamlib.ru2017-09-15 11:40:17http://samlib.ru/w/wbirjuk/zver_kc20doc.shtmlsamlib59bb91f724b474.929370741.0Бирюк В.Зверь Лютый. Книга 20. СтолократияЗверьлютыйКнига 20. СтолократияЧасть 77. "Увидишь клад, какого не..."Глава 419-- Шолом алейхем.-- Алейхем ашшалом. Э-э-э...-- Ну и что вы хочите сказать этим своим бесконечным "э-э-э", которое звучит как призыв взволнованной беременной овцы к заезжему акушеру в тот волнительный момент, когда уже поздно и опорос пошёл?-- Уважаемые! Я не знаю об чём вы тут спорите, но ехать уже пора!-- Золотые слова.


Новая религия

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


Сказки на ночь. Всем хочется на бал

Формула чудес такова: один слушатель в возрасте до шести лет, один чтец, возраст упустим, с интерсными взглядами на жизнь и чувтсвом юмора, хорошее классическое чтиво в современной интерпретации. Правильные слова — и вот вам чудеса и приключения: брутальные принцы, моложавые короли, вредные феи-крестные, злопамятные мачехи и многие другие личности. Готовьте тыкву, мы собираемся на бал!


Ряска Правды

Люди до смерти боятся нечисти, обходят болото стороной. Нечисть, в свою очередь, презрительно фыркает, воротит нос и выбираться из чащоб не спешит. Впрочем, везде встречаются мечтатели — неправильную кикимору по имени Златеника тянет прочь, на свободу. Когда на берегу болота откуда ни возьмись является очаровательный принц, Ника принимает его деловое предложение. Вот только болото не отпускает так просто. Да и люди так просто не принимают. Во дворце гадюк больше, чем на топи. А если ещё и помочь темному магу…


Новороссия. Год войны

Предлагаемая книга посвящена событиям в Новороссии. Её героям и её жертвам. Предпринята попытка подробно рассмотреть первый год донбасской войны, от государственного переворота в Киеве до подписания вторых Минских соглашений. Читатель сможет ближе познакомиться с геополитической и экономической подоплёкой украинской трагедии, давшей старт очередной попытке Запада развалить и колонизировать Россию.


Оверклокеры

Их девиз – «ничто не истинно, всё дозволено». Они оперируют самой конвертируемой валютой в мире – лайком – и практически круглосуточно находятся онлайн. Пионеры новой эры синтеза человека и компьютера, они не видят смысла своей жизни без гаджетов и Интернета, порой даже не догадываясь, что страдают зачастую неизлечимыми психическими расстройствами. И уж тем более не подозревают, какую жертву в будущем им придётся принести на алтарь собственного тщеславия. Их много, и имя им – Оверклокеры.