Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Шпаргалка по программированию.DOC
Скачиваний:
50
Добавлен:
01.05.2014
Размер:
1.9 Mб
Скачать

Задача перестановки сегментов разной длины (второе решение)

Пусть заданы отрезок массива a[m..n) и индекс k: m k n. Требуется переставить местами два прилегающих сегмента a[m..k) и a[k..n). Запишем предутверждение и постутверждение этой задачи:

Pred: (m < k < n) & (a[m..n) = A[m..n)),

Post: (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 = q. Пересчет длин p и q осуществляется просто: в первой ситуации следует выполнить := q  p, а во второй  := p  q. Используя переменные p и q, запишем инвариант цикла:

m

 p

k

k + q

n

a:

Обрабо

тано

Переставить

с a[k..q]

Переставить с

a[ 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  Reversevar  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)) можно детализировать: ( im  i < n: a[i] = A[(m + n  1)  i]).

Индекс эл-та A[(m + n  1)  i]) определен здесь из следующих соображений. Рассмотрим картинку

m

n

a:

 

i j

Ясно, что первыми должны поменяться местами эл--ты с номерами i = m и j = n  1. То же относится к следующей паре эл-тов с номерами m + 1 и j = n  2, затем к паре i = m + 2 и j = n  3 и т. д. При этом, очевидно, будет сохраняться соотношение j = const = m + n  1, или j = const  i.

Инвариантом цикла обменов может быть утверждение

m

i

j

n

a :

Обменены

Обменены

&(m  k) & (i  + m + n  1) &

& (k = (m + ndiv 2)

Если m + n чётное, то k  начало правой половины массива, а если m + n нечётное, то  в точности средний элемент сегмента a[m..n).

Теперь в качестве тела процедуры Reverse можно написать

var  k, i, j: Index;

begin

k := (m + ndiv 2;

j := n;

for  i := m  to k  1 do  begin j := j  1;  a[i]  a[jend;

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 + ndiv 2).