Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Za4et Amelina.doc
Скачиваний:
10
Добавлен:
28.03.2015
Размер:
109.06 Кб
Скачать
  1. ПРОЦЕДУРЫ И ФУНКЦИИ

В языке Паскаль существует два вида подпрограмм: процедура (PROCEDURE ) и функция ( FUNCTION ). Процедуры и функции в Паскале объявляются в разделе описания за разделом переменных. Параметры, записываемые в обращении к подпрограммам, называются фактическими; параметры, указанные в описании подпрограмм - формальными. Фактические параметры должны соответствовать формальным по количеству, порядку следования и типу. Параметры, объявленные в основной (главной) программе, действуют в любой подпрограмме и называются глобальными. Процедуры используются в случаях, когда в подпрограмме необходимо получить несколько результатов. В языке Паскаль существует два вида процедур: процедуры с параметрами и без параметров. Обращение к процедуре осуществляется по имени процедуры, за которым могут быть указаны фактические параметры. Все формальные параметры являются локальными для данной процедуры и глобальными для каждой процедуры в ней. Функции в Паскале. Функция может иметь собственные локальные константы, типы, переменные, процедуры и функции. Описание функций в Паскале аналогично описанию процедур. Отличительные особенности функций: - результат выполнения - одно значение, которое присваивается имени функции и передается в основную программу; - имя функции может входить в выражение как операнд.

Пример 3. Написать подпрограмму-функцию степени аx, где a, х – любые числа. Воспользуемся формулой: аx = ex ln a

program p2; var f, b, s, t, c, d : real; { глобальные параметры} function stp (a, x : real) : real; var y : real; { локальные параметры} begin y := exp (x * ln ( a)) ; stp:= y;{присвоение имени функции результата вычислений подпр-мы} end; { описание функции закончено } begin {начало основной программы } d:= stp (2.4, 5); {вычисление степеней разных чисел и переменных }

writein (d, stp (5,3.5)); read (f, b, s, t); c := stp (f, s)+stp (b, t); writeln (c); end.

  1. ОПИСАНИЕ ПРОЦЕДУРЫ. ОПЕРАТОР ПРОЦЕДУРЫ.

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

Пример 1. Процедура без параметров, которая печатает строку из 60 звездочек.

procedure pr; var i : integer ; begin for i :=1 to 60 do write (‘ * '); writeln; end.

Пример 2. Процедура c параметрами. Даны 3 различных массива целых чисел (размер каждого не превышает 15). В каждом массиве найти сумму элементов и среднеарифметическое значение.

program proc; var i , n , sum: integer; sr : real; procedure work (r:integer; var s:integer; var s1:real); {процедура work} var mas : array [1..15] of integer ; { объявление массива мas} j : integer; begin s:=0; for j:=1 to r do begin {ввод элементов массива mas} write(' Vvedite element - ', j,': '); read (mas[j]); s:=s+mas [j]; end; s1:=s/r; end; begin { главная программа} for i:=1 to 3 do begin write ('Vvedite razmer ',i, ' masiva: '); readln(n); work (n, sum, sr); {вызов процедуры work} writeln ('Summa elementov = ',sum); writeln ('Srednearifmeticheskoe = ',sr:4:1); end; readln; end.

Результат работы программы: В программе трижды вызывается процедура work, в которой формальные переменные r, s, s1 заменяются фактическими n, sum, sr. Процедура выполняет ввод элементов массива, вычисляет сумму и среднее значение. Переменные s и s1 возвращаются в главную программу, поэтому перед их описанием ставится служебное слово var. Локальные параметры mas, j действуют только в процедуре. Глобальные - i, n, sum, sr доступны во всей программе.

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

  1. ЛОКАЛЬНЫЕ И ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ.

Каждый модуль (процедура, функция, программа) состоит из заголовка (procedure…, function…, program…) и блока.Если блок какой-либо процедуры p1 содержит внутри процедуру p2, то говорят, что p2 вложена в p1.Пример.procedure p1(x: real; var y: real);

var c: integer;

procedure p2(var z: real);…………………….end;

begin …………………….end;

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

procedure t1;var y1, y2: real;

procedure sq1;var a, b, c, d: real;

begin{ Переменные a, b, c, d являются локальными для sq1,область их действия – процедура sq1 }

……………………………………end;

begin{Переменные y1, y2 - нелокальные для sq1,бласть их действия – t1 и sq1}

end;

Константы, переменные, типы, описанные в блоке program, называются глобальными. Казалось бы, проще иметь дело вообще только с глобальными переменными, описав их все в program. Но использование локальных переменных позволяет системе лучше оптимизировать программы, делать их более наглядными и уменьшает вероятность появления ошибок.

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

  1. Описывать идентификаторы в том блоке, где они используются, если это возможно.

  2. Если один и тот же объект (переменная, тип, константа) используются в двух и более блоках, то описать этот объект надо в самом внешнем из них, содержащем все остальные блоки, использующие данный объект.

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

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

4. ПАРАМЕТРЫ ПРОЦЕДУР И ФУНКЦИЙ. СПОСОБЫ ПЕРЕДАЧИ ПАРАМЕТРОВ В ПРОЦЕДУРЫ ФУНКЦИИ.

Такие параметры в списке формальных параметров представляются ключевыми словами procedure и function.Примеры.

procedure p(procedure a);

Здесь процедура p имеет один параметр-процедуру a.

procedure q(function s: real; b: real);

Процедура q имеет два параметра: параметр-функцию s и параметр-значение b.

procedure q(function f(i: integer): real);

Здесь формальный параметр f – функция от одного целого аргумента, результат f – вещественный.

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

Обратиться к процедуре q(function f(i: integer): real) можно так: q(sinus(k)); где sinus(k) есть sin(k). Если k имеет тип integer, тогда sinus(k) – типа real. Это совпадает с типами i и f в заголовке q. Нельзя, однако, обратиться к q с функцией abs(k), а именно q(abs(k)); в этом случае тип формального параметра f – real, а тип фактического abs(k) – integer, т.е. формальный и фактический параметры не совпадают по типу.

Существует два механизма передачи параметров в процедуру или функцию.

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

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

Параметры, передаваемые по ссылке, называют параметрами-переменными, а параметры, передаваемые по значению, - параметрами-значениями.

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

function rtt(var x:real; y:real):integer;

Здесь x передается по ссылке, а y- по значению. Синтаксис описания функции будет рассмотрен ниже.

procedure myproc(var x, y: real);

Здесь оба параметра (x) и (y) передаются по ссылке. При составлении списка параметров и выборе способа их передачи необходимо учитывать их назначение. Выходные параметры должны быть переданы по ссылке, а входные могут быть переданы по ссылке и по значению.

  1. НЕТИПИЗИРОВАННЫЕ ПАРАМЕТРЫ.

Нетипизированные параметры обычно используются в случае, когда тип данных несущественен. Такие ситуации чаще всего возникают при разного рода копированиях одной области памяти в другую, например, с помощью процедур BLOCKREAD, BLOCKWRITE, MOVE и т.п. Нетипизированные параметры в сочетании с механизмом совмещения данных в памяти можно использовать для передачи подпрограмме одномерных массивов переменной длины (этот способ можно использовать в Турбо Паскале версии 6.0 и более ранней, в которых нет открытых массивов). В примере 8.4 функция NORMA вычисляет норму вектора, длина которого меняется случайным образом. Стандартная константа MAXINT содержит максимальное значение целого типа INTEGER и равна 32767. Следует учесть, что при обращении к функции NORMA массив X помещается в стек и передается по ссылке, поэтому описание локальной переменной А в виде одномерного массива максимально возможной длины в 65532 байта (встроенная константа MAXINT определяет максимально возможное значение типа INTEGER и равна 32767), совпадающего с X, на самом деле не приведет к выделению дополнительного объема памяти под размещение этой переменной. Иными словами, переменная А - фиктивная переменная, размер которой никак не влияет на объем используемой памяти. С таким же успехом можно было бы объявить ее в виде массива из одного элемента, правда, в этом случае необходимо позаботиться об отключении контроля выхода индекса за границы диапазона. Пример 8.4 const NN = 100; {Максимальная длина вектора} var а : array [1..NN] of Real; i, j, N : Integer; {----------------} Function Norma (var x; N: Integer) : Real; var a : array [1..2*MaxInt div SizeOf (Real) ] of Real absolute x; i : Integer; s : Real; begin {Norma} s := 0; for i := 1 to N do s := s + sqr (a [i] ) ; Norma := sqrt(s) end {Norma} ; {-------------------} begin {main} for i := 1 to 10 do begin N := Random (NN) + 1; {Текущая длина вектора} for j := 1 to N do a [ j ] : = Random ; WriteLn ('N = ', N:2,норма=',Norma(a, N):10:7) end end {main} . Как видно из рассмотренного примера, передача одномерных массивов переменной длины не вызывает никаких трудностей. Сложнее обстоит дело с многомерными массивами, однако и в этом случае использование описанного приема (нетипизированный параметр и совмещение его в памяти с фиктивной переменной) все-таки проще, чем описанная в гл. 6 индексная арифметика. Еще раз напомню, что в случае многомерных массивов их элементы располагаются в памяти так, что при переходе от младших адресов к старшим наиболее быстро меняется самый правый индекс массива.

  1. ДИРЕКТИВЫ, ИСПОЛЬЗУЕМЫЕ ПРИ ОПИСАНИИ ПРОЦЕДУР И ФУНКЦИЙ.

Процедуры NEAR вызываются с помощью вызова ближнего типа и содержат ближний возврат управления. Вы должны вызывать их только в том же сегменте, в котором они определены. Вызов ближнего типа заносит адрес возврата в стек и устанавливает указатель инструктор (IP) в значение смешения процедуры. Поскольку сегмент кода(CS) не изменяется, процедура должна находиться в том же сегменте, что и вызывающая программа. Когда процессор обнаруживает возврат ближнего типа, он извлекает из стека адрес возврата и снова устанавливает в него IP. Сегмент кода не изменяется. Процедура FAR вызывается с помощью вызова дальнего типа и содержит возврат дальнего типа. Процедуры FAR вы можете вызывать вне сегмента, в котором они определяются. Вызов FAR заносит в стек адрес в виде сегмента и смещения, а затем устанавливает CS:IP в адрес процедуры. Когда процессор обнаруживает возврат дальнего типа, он извлекает из стека сегмент и смещение адреса возврата и устанавливает в него CS:IP.

Расстояние (NEAR или FAR), используемое в процедуре по умолчанию, определяется текущей выбранной моделью. Для моделей TINY, SMALL и COMPACT по умолчанию процедура будет ближней (NEAR). Для всех других моделей по умолчанию выбирается расстояние FAR. Если вы не используете упрощенные директивы определения сегментов, то по умолчанию процедура всегда будет ближней (NEAR).

7. НЕОБХОДИМОСТЬ И ПРЕИМУЩЕСТВА МОДУЛЬНОГО ПРОГРАММИРОВАНИЯ. СТРУКТУРА МОДУЛЯ В ЯЗЫКЕ ПАСКАЛ.

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

UNIT <имя>;

INTERFACE

<интерфейсная часть>

IMPLEMENTATION<часть реализации (исполняемая часть)>

BEGIN<часть инициализации (инициирующая часть)>END.

Заголовок модуля состоит из зарезервированного слова UNIT и следующего за ним имени модуля. Имя модуля служит для его связи с другими модулями и основной программой. Эта связь устанавливается специальным предложением USES <список модулей>

Интерфейсная часть открывается зарезервированным словом INTERFACE. В этой части содержаться объявления всех глобальных объектов модуля, которые должны стать доступными основной программе и/или другим модулям.

Исполняемая часть начинается зарезервированным словом IMPLEMENTATION и содержит описания подпрограмм, объявленных в интерфейсной части. В ней могут объявляться локальные для модуля объекты – вспомогательные типы, константы, переменные и блоки, а также метки, если они используются в инициирующей части.

Описанию подпрограммы, объявленной в интерфейсной части модуля, в исполняемой части должен предшествовать заголовок, в котором можно опускать список формальных переменных, т.к. они уже описаны в интерфейсной части. Но если заголовок подпрограммы приводится в полном виде, т.е. со списком формальных параметров и объявлением результата, он должен совпадать с заголовком, объявленным в интерфейсной части.

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

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

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

Преимущества модульного программирования:

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

-позволяет придать программе иерархическую структуру, что положительно сказывается на ее восприятии;

-обеспечивает независимость компонент системы, т.е. позволяет их независимую разработку и отладку;

- модули скрывают детали внутренней реализации пр-р или ф-ий(инкапсуляция на уровне модуля – это ограничение доступа).

Для языка Pascal использование модулей необходимо при разработке больших программ из-за существующего ограничения на размер одного программного модуля в 64 килобайта.

8. РЕКУРСИЯ

Подпрограммы в Паскале могут обращаться сами к себе. Такое обращение называется рекурсией.

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

Рассмотрим математическую головоломку из книги Ж. Арсака «Программирование игр и головоломок».

Построим последовательность чисел следующим образом: возьмем целое число i>1. Следующий член последовательности равен i/2, если i четное, и 3 i+1, если i нечетное. Если i=1, то последовательность останавливается. Математически конечность последовательности независимо от начального i не доказана, но на практике последовательность останавливается всегда.

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

Пример программы с использованием рекурсии

Program Arsac;

Var first: word;

Procedure posledov (i: word);

Begin

Writeln (i);

If i=1 then exit;

If odd(i) then posledov(3*i+1) else posledov(i div 2);

End;

Begin

Write (‘ введите первое значение ’); readln (first);

Posledov (first);

Readln ;

End.

Программист разрабатывает программу, сводя исходную задачу к более простым. Среди этих задач может оказаться и первоначальная, но в упрощенной форме. Например, для вычисления F( N) может понадобиться вычислить F( N-1). Иными словами, частью алгоритма вычисления функции будет вычисление этой же функции.

Алгоритм, который является своей собственной частью, называется рекурсивным. Часто в основе такого алгоритма лежит рекурсивное определение.

Пример рекурсивного алгоритма N! = ( N-1)!* N, если N=0, то N!= 1

Любое рекурсивное определение состоит из двух частей. Одна часть определяет понятие через него же, другая часть – через иные понятия.

  1. РЕКУРСИЯ И ИТЕРАЦИЯ.

Рекурсия - это такой способ организации обработки данных, при котором программа вызывает сама себя непосредственно, либо с помощью других программ. В программировании рекурсия — вызов функции (процедуры) из неё же самой, непосредственно (простая рекурсия) или через другие функции (сложная рекурсия), например, функция A вызывает функцию B, а функция B — функцию A. Количество вложенных вызовов функции или процедуры называется глубиной рекурсии. В основе рекурсивного вычислительного процесса лежит рекурсивный цикл, который реализуется через вызов рекурсивной процедуры, причем каждая активация рекурсивной процедуры эквивалентна одному проходу итеративного цикла While. Общая схема рекурсивного цикла: Procedure Рекурсивный_Цикл (…);

begin

if < условие цикла >

thenbegin

< тело рекурсивного цикла; >

Рекурсивный_Цикл (…); end;end;

Итерация - способ организации обработки данных, при котором определенные действия повторяются многократно, не приводя при этом к рекурсивным вызовам программ. Когда какое-то действие необходимо повторить большое количество раз, в программировании используются циклы. В основе итеративного вычислительного процесса лежит итеративный цикл While, Repeat-Until, For. Наиболее общим является цикл While:

While < условие цикла > do < тело цикла >;

Существует два важных положения, известных в математике и в программировании, определяющих соотношение между итерацией и рекурсией:

- Любой итеративный цикл может быть заменен рекурсией.

Рекурсия не всегда может быть заменена итерацией.

  1. ЛИНЕЙНЫЙ ПОИСК

Суть линейного поиска состоит в том, что поочерёдно сверяются значения элементов массива с искомым значением, пока не достигнут конец массива. Допустим, x - искомое значение в массиве A целых чисел размера N элементов.

Условиями поиска являются:

  1. проверка выхода за границы массива (i ⇐ N)

  2. проверка, является ли текущий элемент искомым (A[i] <> x)

Итак, алгоритм таков:

Установить счётчик в начальное положение

Цикл Пока (не достигнут конец массива) И (Элемент массива не явдяется искомым) Выполнять

Увеличение счётчика

или на Паскале:

i := 1;

while (i <= N) And (A[i] <> x) do

Inc (i);

Таким образом, искомый элемент x считается найденным в массиве A, если индекс позиции i находится в пределах 1..N. Если же i > N, то элемент не был найден в массиве.

  1. ПОИСК ДЕЛЕНИЕМ ПОПОЛАМ (ДВОИЧНЫЙ ПОИСК)

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

Условие окончания:

·Элемент найден, т.е. а[i]=х.

·Весь массив просмотрен, а элемента не обнаружено.

While (i<n) and (a[i]<>x) do i:=i+1;

Инвариант цикла, т.е. условие, выполняющееся перед каждым увеличением индекса i: (0≤i<n) and (k: 0≤k<i; a[k]≠x).

Условие окончания: ((i=n) or (a[i]=x)) and (k: 0≤k<i; a[k]≠x).

Это условие не только указывает на желаемый результат, но и также оно говорит, что элемент найден с минимальным значением индекса.

Равенство i=n свидетельствует о том, что совпадения не было. Очевидно, что окончания цикла гарантировано и за конечное число шагов мы можем достичь предела n.

Если нам известна дополнительная информация о данных, например, что они упорядочены, то поиск можно сделать более эффективным.

Основная идея: выбрать случайные элементы a[m] и сравнить с аргументом поиска х, если он равен х, то конец поиска, если меньше х, то все элементы с индексами меньше или равно m можно исключить из рассмотрения, если же он больше х, то исключаются элементы с индексом больше или равно m.

Выбор m совершенно произволен и корректность алгоритма от него не зависит, но на эффективность влияет. Самый оптимальный вариант – средний элемент, т. к. на каждом шаге исключается половина массива. Задача исключить из дальнейшего поиска, каким бы ни был результат сравнения, как можно большее число элементов, поэтому оптимальным является выбор среднего элемента. В результате максимальное число сравнений имеет порядок log N. Т.о. приведенный алгоритм существенно эффективнее линейного, т.к. там ожидаемое число сравнений равно N/2.

Быстрый алгоритм построен на инварианте

(для любого K: 0<=k< α: ak<x)& (для любого K: r<=k<n : ak =>x)

Поиск продолжается пока обе секции не накроят массив целиком.

L:=0; R:=N;

While L<R do Begin M:=(L+R) div 2 If a[m]<x then L:=m+1 Else R:=m; Условие окончания L=>R.

  1. СОРТИРОВКА

Под сортировкой понимается процесс перестановки объектов данного множества в определенном порядке. Цель сортировки – облегчить последующий поиск элементов в отсортированном множестве.

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

Метод сортировки называется устойчивым если относительный порядок элементов с одинаковыми ключами не меняется при сортировке.

Устойчивость сортировки бывает желательна, если элементы уже упорядочены по каким-то вторичным ключам, т.е. по свойствам отраженным в первичном ключе.

Сортировка простыми включениями. Элементы условно разделяются на готовую последовательность а0..аi-1 и входную последовательность аi..аn. На каждом шаге, начиная с i=2 и затем увеличивая i на единицу берут i-тый элемент входной последовательности и передают в готовую последовательность вставляя его на подходящее место.

При поиске подходящего места удобно чередовать сравнения и пересылки, т.е. как бы «просеивать» сравнивая его с очередным элементом аg и либо вставлять х, либо пересылать аg вправо и продвигаться налево.

«Просеивание» может закончиться при двух различных условиях: Найдем элемент аg с ключом меньшим чем х; Достигнут левый конец готовой последовательности. Это типичный пример цикла с двумя условиями окончания поэтому можно применить известный метод барьера. Для этого установим барьер а0:=x.

  1. СОРТИРОВКА ПРОСТЫМ ВЫБОРОМ.

Основана на следующем правиле: Выбираем элемент с наименьшим ключом, Он меняется местами с первым элементом массива. Эти операции повторяются с оставшимися (n-1) элементом, потом с (n-2) элементом, пока не останется один наибольший элемент.

Сортировка простым выбором противоположна сортировке простыми включениями: при сортировке простыми включениями рассматривается один элемент входной последовательности и все элементы готового массива для нахождения места включения. А при сортировке простым выбором рассматриваются все элементы входного массива для нахождения наименьшего элемента и один очередной элемент направляется в готовую последовательность.

Обычно алгоритм сортировки простым выбором предпочтительнее сортировки простыми включениями, хотя в случае, когда ключи заранее отсортированы или почти рассортированы, сортировка простыми включениями все же работает несколько быстрее.

14. СОРТИРОВКА ПРОСТЫМ ОБМЕНОМ (МЕТОД ПУЗЫРЬКА)

Основана на принципе сравнения и обмена пары соседних элементов до тех пор пока не будут рассортированы все элементы.

Число сравнений и пересылок равняется N2.

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

  1. ШЕЙКЕР-СОРТИРОВКА

Если менять направление следующих друг за другом проходов в сортировки простым обменом (метод пузырька), то получается алгоритм Шейкер сортировки.

const n=20; var a:array [1..n] of integer; i,j,l,k,x,r:integer; begin l:=2; r:=n; k:=n; repeat for j:=r downto l do if a[j-1]>a[j] then begin

x:=a[j-1]; a[j-1]:=a[j]; a[j]:=x; k:=j; end; l:=k+1; for j:=l to r do if a[j-1]>a[j] then begin x:=a[j-1]; a[j-1]:=a[j]; a[j]:=x; k:=j; end;

r:=k-1 until l>r; end;

Число сравнений и пересылок равняется N2.

  1. СОРТИРОВКА С РАЗДЕЛЕНИЕМ (БЫСТРАЯ СОРТИРОВКА)

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

Рассмотрим следующий алгоритм: Выберем случайным образом некоторый элемент массива (X). Просмотрим массив, двигаясь слева направо, пока не найдем элемент ai>x , а затем просмотрим его справа налево, пока не найдем aj < x . Поменяем их местами и продолжим процесс просмотра с обменом, пока оба просмотра не встретятся где-то в середине массива. Наша цель не только разделить массив на 2 части, но и отсортировать его. Разделив массив, надо сделать тоже самое с полученными частями, затем с частями этих частей, пока каждая часть не будет содержать 1 элемент.

Анализ быстрой сортировки : в лучшем случае число сравнений n*log n, число обменов – (n / 6) * log n. Но при небольших n эффективность невелика. В наихудшем случае, когда в качестве x выбирается наибольшее значение в подмассиве, эффективность становится порядка n*n. (В отличие от пирамидальной сортировки, у которой даже в наихудшем случае эффективность n*log n).

  1. 18. Ссылочные типы. Динамические структуры данных.

Статическими величинами называются такие, память под которые выделяется во время компиляции и сохраняется в течение всей работы программы. Например, к глобальным  переменным память отводится в начале выполнения программы, и существуют они в течение всего периода работы программы. Для локальных переменных память отводится при вызове подпрограммы , а при выходе из нее она  освобождается , то есть распределение памяти в обоих случаях производится автоматически. В Pascal существует способ выделения памяти под данные, который называется динамическим. Раздел оперативной памяти, распределяемый статически, называется статической памятью; динамически распределяемый раздел памяти называется динамической памятью (динамически распределяемой памятью).

Работа с динамическими величинами связана с использованием еще одного типа данных — ссылочного типа. Величины, имеющие ссылочный тип, называют указателями. Указатель содержит адрес поля в динамической памяти, хранящего величину определенного типа. Сам указатель располагается в статической памяти. Адрес величины — это номер первого байта поля памяти, в котором располагается величина. Размер поля однозначно определяется типом. Величина ссылочного типа (указатель) описывается в разделе описания переменных следующим образом:

Var <идентификатор> : ^<имя типа>;

Вот примеры описания указателей:

Type Mas1 = Array[1..100] Of Integer;

Var P1 : ^Integer;P2 : ^String;Pm : ^Mas1;

Память под динамическую величину, связанную с указателем, выделяется в результате выполнения стандартной процедуры NEW. (NEW(<указатель>);) В качестве ссылочного выражения можно использовать указатель; ссылочную функцию (т.е. функцию, значением которой является указатель); константу Nil. Nil — это зарезервированная константа, обозначающая пустую ссылку. В Паскале имеется стандартная процедура, позволяющая освобождать память от данных, потребность в которых отпала. DISPOSE(<указатель>);

Динамическое распределение памяти активно используется в большом количестве приложений ( причины динамического распределения памяти):

- Управление большим объемом данных.

При этом используется динамическая область памяти, которая называется Куча (heap) – это вся память, которую ваша операционная система делает доступной и которая не используется кодом программы, сегментом данных и сегментом стека. Размер Кучи необходимо контролировать различными способами.

-Управление данными неизвестного размера.

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

-Использование временных буферов данных.

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

-Динамические структуры данных. Динамические переменные можно организовать в различные структуры. Для этого для каждого объекта такой структуры создать тип запись. И эта запись содержит один или более указателей на другие объекты этой структуры.

  1. СОЗДАНИЕ И УНИЧТОЖЕНИЕ ДИНАМИЧЕСКИХ ПЕРЕМЕННЫХ.

procedure TForm1.Button1Click(Sender: TObject); var

p1,p2,p3: Integer; // указатели на переменные типа integer

begin

// создадим динамические переменные типа integer

// (выделим память для динамических переменных)

New(p1);

New(p2);

New(p3);

р1^ := 5;

р2^ := 3;

р3^ := р1^ + р2^;

ShowMessage('Сумма чисел равна ' + IntToStr(р3^));

// уничтожим динамические переменные

// (освободим память, занимаемую динамическими переменными)

Dispose(p1);

Dispose(р2);

Dispose(р3);

end;

В начале работы процедура создает три динамические переменные. Две переменные, на которые указывают p1 и р2, получают значение в результате выполнения инструкции присваивания. Значение третьей переменной вычисляется как сумма первых двух.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]