- •Билет №8 Вычисления с вещественными числами и машинное эпсилон №8
- •Машинное эпсилон может быть вычислено с помощью следующей программы:
- •Билет №9 Общая схема итерации и №9 рекуррентные вычисления
- •Вычисления с целыми числами
- •Билет№10 Схема интерации. Вычисление частичной суммы (вещ числа) №10
- •Общая формулировка задания
- •Пример выполнения задания
- •Вопрос №12 . Основные правила аналитической верификации программ №12
- •Вопрос №14 Ограничивающая ф-ция оператора цикла.Примеры №14
- •Билет№15. Теорема о цикле, его инварианте и ограничивающей функции №15
- •Билет №17 Теорема о цикле repeat- until ,его инварианте и ограничивающей его ф-ции. Аннотирование цикла и понимание аннотации №17
- •Вопрос№18 Алгоритм анализа двоичной записи натурального числа в двоичной сист счисления №18
- •Последовательности и файлы
- •Индуктивные функции
- •Стационарные значения индуктивных функций
- •Индуктивные расширения функций
- •Примеры задач с индуктивными функциями
- •Кванторы и запись утверждений о массивах
- •Правила вывода для цикла с параметром
- •Примеры программ работы с массивами
- •Решение последовательными обменами
- •Задача перестановки сегментов разной длины (второе решение)
- •Задача перестановки сегментов разной длины (третье решение)
- •Билет№35 Задача о равнинах (с испол массива) №35
- •Линейный поиск
- •Оптимизация программы бинарного поиска
- •Билет№44 Массивы в качестве параметров:открытые массивы №44 Сведения о массивах в языке Паскаль
- •Билет№45 Двумерные (многомерные массивы). Индексация. Исполбзование процедур. Задача: о МиниМаксе(матрица как массив строк) №45 обработка двухмерных массивов
Задача перестановки сегментов разной длины (второе решение)
Пусть заданы отрезок массива a[m..n) и индекс k: m < k < n. Требуется переставить местами два прилегающих сегмента a[m..k) и a[k..n). Запишем предутверждение и постутверждение этой задачи:
Pred: (m < k < n) & (a[m..n) = A[m..n)),
Post: (s = m + n k) & (a[m..s) =
= A[k..n)) & (a[s..n) = A[m..k))
и изобразим их в виде картинок:
|
m |
k |
n |
Pred: a: |
Сегмент 1 |
Сегмент 2 |
& (m < k < n) |
|
m |
s |
n |
Post: a: |
Сегмент 2 |
Сегмент 1 |
& (s = m + n k) |
Иногда такую перестановку сегментов называют циклическим сдвигом на k m позиций влево (обычно при m = 1).
Рассмотрим решение этой задачи, опирающееся на использование процедуры SwapEq перестановки сегментов равной длины из 4.6.1.
Представим последовательность = am am+1 ... an1 в виде конкатенации двух подпоследовательностей = am am+1 ... ak1 и = ak ak+1 ... an1, т. е. = . Сначала рассмотрим ситуацию, когда Length( ) < Length( ), т. е. k m < n k. Выделим в конце последовательности часть, равную по длине последовательности : = 1 2 , где 1 = ak ak+1 ... as1 и 2 = as as+1 ... an1, а Length( ) = k m = Length( 2 ) = n s, т. е. s = m + n k. Тогда исходное состояние массива описывается картинкой
|
m |
k |
s |
n |
a: |
|
1 |
2 |
|
Используя процедуру SwapEq, переставим сегменты равной длины, содержащие и 2, и получим состояние, описываемое картинкой
|
m |
k |
s |
n |
a: |
2 |
1 |
|
|
Далее можно завершить решение задачи, переставив сегменты, содержащие 2 и 1, т. е. решив аналогичную задачу перестановки сегментов применительно к отрезку массива a[m..s), меньшему, чем исходный отрезок a[m..n).
Рассмотрим теперь ситуацию, когда Length( ) > Length( ), т. е. k m > n k. Состояние до вызова процедуры SwapEq описывает картинка
-
m
s
k
n
a:
1
2
а состояние после вызова картинка
-
m
s
k
n
a:
2
1
Затем, как и в первом случае, нужно переставить сегменты, содержащие 2 и 1. В обеих рассмотренных ситуациях процесс следует продолжать, пока не будут получены сегменты равной длины, после чего решение задачи завершается заключительным применением процедуры SwapEq.
Учтем следующее:Во-первых, заметим, что в обеих рассмотренных ситуациях после применения процедуры SwapEq граница сегментов k не изменилась, но от исходного отрезка a[m..n) перешли в первой ситуации к отрезку a[m..s), содержащему очередную пару переставляемых сегментов, а во второй ситуации к отрезку a[s..n). Во-вторых, удобно левую m и правую n границы обрабатываемого отрезка отсчитывать от границы k переставляемых сегментов, зная их длины p и q, т. е. m = k p и n = k + q. Пересчет длин p и q осуществляется просто: в первой ситуации следует выполнить q := q p, а во второй p := p q. Используя переменные p и q, запишем инвариант цикла:
|
m |
k p |
k |
k + q |
n | |
a: |
Обрабо тано |
Переставить с a[k..k + q] |
Переставить с a[k p..k] |
Обработано |
& (0 < p k m) | |
|
|
|
|
& (0 < q n k) |
|
В итоге программу перестановки сегментов разной длины записываем следующим образом:
p := k m; q := n k;
{bound: max(p,q)}
while p q do
if p > q then begin SwapEq(a, k p, k, q);
p := p q
end
else {p < q}
begin SwapEq(a, k p, k + q p, p);
q := q p
end;
{end-while}
SwapEq(a, k p, k, p)
Заметим, что если из этой программы удалить все вызовы процедуры SwapEq, то получим алгоритм Евклида для вычисления НОД(p, q).
Билет№34 Задача перестановки сегментов массива разной длины.Решение испол. Вспом проц обращения сегмента №34
Пусть дана последовательность mn = am am+1 ... an1. Определим функцию обращения последовательности Rev( mn ) = an1 an2 ... am+1 am. Запишем заголовок процедуры обращения сегмента массива:
procedure Reverse( var a: Vector; m, n: Index);
{Pred: (Low(a) m) & (m < n High(a) + 1) & a[m..n) = A[m..n) }
{Post: (Low(a) m)&(m < n High(a) + 1) & a[m..n) = Rev(A[m..n))}
Утверждение a[m..n) = Rev(A[m..n)) можно детализировать: ( i: m i < n: a[i] = A[(m + n 1) i]).
Индекс эл-та A[(m + n 1) i]) определен здесь из следующих соображений. Рассмотрим картинку
-
m
n
a:
i j
Ясно, что первыми должны поменяться местами эл--ты с номерами i = m и j = n 1. То же относится к следующей паре эл-тов с номерами i = m + 1 и j = n 2, затем к паре i = m + 2 и j = n 3 и т. д. При этом, очевидно, будет сохраняться соотношение i + j = const = m + n 1, или j = const i.
Инвариантом цикла обменов может быть утверждение
|
m |
i |
j |
|
n |
a : |
Обменены |
|
|
Обменены |
&(m i < k) & (i + j = m + n 1) & |
|
|
|
& (k = (m + n) div 2) |
Если m + n чётное, то k начало правой половины массива, а если m + n нечётное, то k в точности средний элемент сегмента a[m..n).
Теперь в качестве тела процедуры Reverse можно написать
var k, i, j: Index;
begin
k := (m + n) div 2;
j := n;
for i := m to k 1 do begin j := j 1; a[i] a[j] end;
end {Reverse}
Индуктивным утверждением цикла, соответствующим приведенной картинке, является
P([m..i]) (a[m..i] = Rev(A[j..n)) & (a[j..n) = Rev(A[m..i])) (a(i..j) = A(i..j))& (m i < k) & (i + j = m + n 1) & (k = (m + n) div 2).