Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Различные авторы Весь текст 991.22 Kb

Программирование в теоремах и задачах

Предыдущая страница Следующая страница
1 ... 31 32 33 34 35 36 37  38 39 40 41 42 43 44 ... 85
    | | end;
    | end else if state = IntPart then begin
    | | if Digit (Next) then begin
    | | | state := IntPart; Move;
    | | end else if Next = '.' then begin
    | | | state := DecPoint; {после десятичной точки}
    | | | Move;
    | | end else begin
    | | | state := Accept;
    | | end;
    | end else if state = DecPoint then begin
    | | if Digit (Next) then begin
    | | | state := FracPart; Move;
    | | end else begin
    | | | state := Error; {должна быть хоть одна цифра}
    | | end;
    | end else if state = FracPart then begin
    | | if Digit (Next) then begin
    | | | state := FracPart; Move;
    | | end else begin
    | | | state := Accept;
    | | end;
    | end else if
    | | {такого  быть не может}
    | end;
    end;

Заметьте,  что присваивания state:=Accept и state:=Error не соп-
ровождаются сдвигом (символ, который не может быть частью числа,
не забирается).

     Приведенная программа не запоминает  значение  прочитанного
числа.

     5.2.2. Решить предыдущую задачу с дополнительным требовани-
ем: если прочитанный кусок является десятичной записью, то в пе-
ременную val:real следует поместить ее значение.

     Решение.  При  чтении дробной части используется переменная
step - множитель при следующей десятичной цифре.

    state := Initial; val:= 0;
    while (state <> Accept) or (state <> Error) do begin
    | if state = Initial then begin
    | | if Next = ' ' then begin
    | | | state := Initial; Move;
    | | end else if Digit(Next) then begin
    | | | state := IntPart; {после начала целой части}
    | | | val := DigitValue (Next);
    | | | Move;
    | | end else begin
    | | | state := Error;
    | | end;
    | end else if state = IntPart then begin
    | | if Digit (Next) then begin
    | | | state := IntPart; val := 10*val + DigitVal(Next);
    | | | Move;
    | | end else if Next = '.' then begin
    | | | state := DecPoint; {после десятичной точки}
    | | | step := 0.1;
    | | | Move;
    | | end else begin
    | | | state := Accept;
    | | end;
    | end else if state = DecPoint then begin
    | | if Digit (Next) then begin
    | | | state := FracPart;
    | | | val := val + DigitVal(Next)*step; step := step/10;
    | | | Move;
    | | end else begin
    | | | state := Error; {должна быть хоть одна цифра}
    | | end;
    | end else if state = FracPart then begin
    | | if Digit (Next) then begin
    | | | state := FracPart;
    | | | val := val + DigitVal(Next)*step; step := step/10;
    | | | Move;
    | | end else begin
    | | | state := Accept;
    | | end;
    | end else if
    | | {такого  быть не может}
    | end;
    end;

     5.2.3. Та же задача, если перед  число  может  стоять  знак
"минус" или знак "плюс" (а может ничего не стоять).

     Формат  чисел  в этой задаче обычно иллюстрируют такой кар-
тинкой:

   -----      ---------
---| + |---->-| цифра |-------->--------------------->
 | -----  | | --------- | |                      |
 | -----  | |           | | -----     ---------  |
 |-| - |--| |----<------| |-| . |->---| цифра |--|
 | -----  |                 -----   | --------- |
 |        |                         |-----<-----|
 |--->----|


     5.2.4.  Та же задача, если к тому же после числа может сто-
ять показатель степени десяти, как  в  254E-4  (=0.0254)  или  в
0.123E+9 (=123000000). Нарисуйте соответствующую картинку.

     5.2.5. Что надо изменить в программе  задачи  5.2.2,  чтобы
разрешить пустые целую и дробную части (как в '1.', '.1' или да-
же '.' - последнее число считаем равным нулю)?

     Мы  вернемся  к  конечным автоматам в главе 10 (Сравнение с
образцом).
     Глава 6. Типы данных.

     6.1. Стеки.

     Пусть Т - некоторый тип. Рассмотрим (отсутствующий в паска-
ле)  тип "стек элементов типа Т". Его значениями являются после-
довательности значений типа Т.

     Операции:

Сделать_пустым (var s: стек элементов типа Т).
Добавить (t: T; var s: стек элементов типа Т).
Взять (var t: T; var s: стек элементов типа Т).
Пуст (s: стек элементов типа Т): boolean
Вершина (s: стек элементов типа Т): T

     (Мы пользуемся обозначениями, наполняющими паскаль, хотя  в
паскале типа "стек" нет.) Процедура "Сделать_пустым" делает стек
s  пустым.  Процедура  "Добавить" добавляет t в конец последова-
тельности  s.  Процедура  "Взять"  определена,  если  последова-
тельность  s непуста; она забирает из неё последний элемент, ко-
торый становится значением переменной t. Выражение "Пуст(s)" ис-
тинно, если последовательность s пуста.  Выражение  "Вершина(s)"
определено, если последовательность s непуста, и равно последне-
му элементу последовательности s.
     Мы  покажем,  как моделировать стек в паскале и для чего он
может быть нужен.

     Моделирование ограниченного стека в массиве.

     Будем считать, что количество элементов в стеке не  превос-
ходит  некоторого  числа  n. Тогда стек можно моделировать с по-
мощью двух переменных:
        Содержание: array [1..n] of T;
        Длина: integer;
считая, что в стеке находятся элементы Содержание [1],...,Содер-
жание [длина].

     Чтобы сделать стек пустым, достаточно положить
        Длина := 0

     Добавить элемент t:
         {Длина < n}
         Длина := Длина+1;
         Содержание [Длина] :=t;

     Взять элемент в переменную t:
         t := Содержание [Длина];
         Длина := Длина - 1;

     Стек пуст, если Длина = 0.

     Вершина стека равна Содержание [Длина].

Таким образом, вместо переменной типа стек в программе на паска-
ле можно использовать две переменные Содержание и  Длина.  Можно
также определить тип стек, записав

    const N = ...
    type  stack = record
                    Содержание: array [1..N] of T;
                    Длина: integer;
                  end;

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

        procedure Добавить (t: T; var s: stack);
        begin
        | {s.Длина , N}
        | s.Длина := s.Длина + 1;
        | s.Содержание [s.Длина] := t;
        end;

     Использование стека.

     Будем рассматривать последовательности открывающихся и зак-
рывающихся круглых и квадратных скобок ( ) [ ]. Среди всех таких
последовательностей  выделим правильные - те, которые могут быть
получены по таким правилам:

        1) пустая последовательность правильна.
        2) если А и В правильны, то и АВ правильна.
        3) если А правильна, то [A] и (A) правильны.

     Пример. Последовательности (), [[]], [()[]()][]  правильны,
а последовательности ], )(, (], ([)] - нет.

     6.1.1.  Проверить правильность последовательности за время,
не превосходящее константы, умноженной на её длину.  Предполага-
ется, что члены последовательности закодированы числами:
         (   1
         [   2
         )  -1
         ]  -2

     Решение. Пусть a[1]..a[n] - проверяемая последовательность.
Рассмотрим  стек,  элементами  которого  являются  открывающиеся
круглые и квадратные скобки (т. е. 1 и 2).
     Вначале стек делаем пустым. Далее просматриваем члены  пос-
ледовательности  слева  направо.  Встретив  открывающуюся скобку
(круглую или квадратную), помещаем её в стек. Встретив  закрыва-
ющуюся,  проверяем, что вершина в стеке - парная ей скобка; если
это не так, то можно утверждать, что  последовательность  непра-
вильна,  если  скобка  парная, то заберем её (вершину) из стека.
Последовательность правильна,  если  в  конце  стек  оказывается
пуст.
        Сделать_Пустым (s);
        i := 0; Обнаружена_Ошибка := false;
        {прочитано i символов последовательности}
        while (i < n) and not Обнаружена_Ошибка do begin
        | i := i + 1;
        | if (a[i] = 1) or (a[i] = 2) then begin
        | | Добавить (a[i], s);
        | end else begin  {a[i] равно -1 или -2}
        | | if Пуст (s) then begin
        | | | Обнаружена_Ошибка := true;
        | | end else begin
        | | | Взять (t, s);
        | | | Обнаружена ошибка := (t <> - a[i]);
        | | end;
        | end;
        end;
        Правильно := (not Обнаружена_Ошибка) and Пуст (s);

       Убедимся  в  правильности  программы. (1) Если последова-
тельность построена по правилам, то программа даст  ответ  "да".
Это легко доказать индукцией по построению правильной последова-
тельности.  Надо проверить для пустой, для последовательности AB
в предположении, что для A и B уже проверено - и для  последова-
тельностей [A] и (A) - в предположении, что для A уже проверено.
Для  пустой  очевидно.  Для AB действия программы происходят как
для A и кончаются с пустым стеком; затем все происходит как  для
B.  Для  [A]  сначала  помещается  в стек открывающая квадратная
скобка и затем все идет как для A - с той разницей, что в глуби-
не стека лежит лишняя скобка. По  окончании  A  стек  становится
пустым  - если не считать этой скобки - а затем и совсем пустым.
Аналогично для (A).
     (2) Покажем, что если программа завершает работу с  ответом
"да",  то последовательность правильная. Рассуждаем индукцией по
длине последовательности. Проследим за состоянием стека  в  про-
цессе работы программы. Если он в некоторый промежуточный момент
пуст, то последовательность разбивается на две части, для каждой
из  которых  программа дает ответ "да"; остается воспользоваться
предположением индукции и определением правильности. Пусть  стек
все  время  непуст.  Это значит, что положенная в него на первом
шаге скобка будет вынута на последнем шаге. Тем самым, первый  и
последний символы последовательности - это парные скобки, и пос-
ледовательность имеет вид (A) или [A], а работа программы (кроме
первого  и  последнего  шагов) отличается от ее работы на A лишь
наличием лишней скобки на дне стека (раз ее не вынимают, она ни-
как не влияет на работу программы). Снова ссылаемся на предполо-
жение индукции и определение правильности.

     6.1.2. Как упростится программа, если известно, что в  пос-
ледовательности могут быть только круглые скобки?

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

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

     Решение. Стеки должны расти с концов массива навстречу друг
другу: первый должен занимать места
        Содержание[1] ... Содержание[Длина1],
а второй  -
        Содержание[n] ... Содержание[n - Длина2 + 1]
(вершины обоих стеков записаны последними).

     6.1.4. Реализовать k стеков с элементами типа T, общее  ко-
личество  элементов в которых не превосходит n, с использованием
массивов суммарной длины C*(n+k), затрачивая на каждое  действие
со  стеками (кроме начальных действий, делающих все стеки пусты-
ми) время, ограниченное некоторой константой.

     Решение. Применяемый метод называется "ссылочной реализаци-
ей". Он использует три массива:
        Содержание: array [1..n] of T;
        Следующий: array [1..n] of 0..n;
        Вершина: array [1..k] of 0..n.
     Массив Содержание будем изображать как n ячеек  с  номерами
1..n,  каждая  из которых содержит элемент типа T. Массив Следу-
ющий изобразим в виде стрелок, проведя стрелку из i  в  j,  если
Следующий[i] = j. (Если Следующий[i] = 0, стрелок из i не прово-
дим.) Содержимое s-го стека (s из 1..k)  хранится  так:  вершина
Предыдущая страница Следующая страница
1 ... 31 32 33 34 35 36 37  38 39 40 41 42 43 44 ... 85
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (1)

Реклама