Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Основная книга по С++й.doc
Скачиваний:
16
Добавлен:
28.10.2018
Размер:
2.07 Mб
Скачать

Void PrintSearchList (list head, int val)

//Head – указатель на голову списка, str – искомая строка

{

bool lfound = false; // признак того, что строка найдена

tail = &head; //начинаем с головы списка

while (tail != NULL)// если указатель на текущий элемент списка не пуст

{

printf("%d\n", tail->value); //выводим информационное поле списка

if (tail->value = val) lfound = true; //совпадает с искомой строкой?

tail = tail->next; //переходим к следующему узлу списка

}

If (lfound) printf("Элемент в списке найден!");

else printf("Элемент в списке не найден!");

}

list GotoNode (list head, int cnt)

//Cnt – номер узла, начиная с 1, к которому нужно перейти

{

int i = 1;

tail = &head;

while ((tail->next != NULL) && (i < cnt))

{

i++;

tail = tail->next;

}

return(*tail);

}

Стек, очередь, дек

Стеком (англ. stack) называется хранилище данных, в котором можно работать только с одним элементом: тем, который был добавлен в стек последним. Говорят, что стек реализует дисциплину обслуживания LIFO (Last In – First Out, последним пришел – первым ушел). Физически стек может быть реализован на основе массива или на основе односвязанного линейного списка, в котором все операции осуществляются только с головой списка. Этот элемент в стеке называется верхушкой стека и на него указывает указатель стека ptrStack (рис.43). Если указатель стека – пустой, то стек считается пустым.

Стек должен поддерживать следующие операции:

push – добавить (положить) в верхушку стека новый элемент;

pop – извлечь из верхушки стека элемент;

isEmpty – проверка, пуст ли стек;

top – узнать (прочитать) значение верхушки стека (не удаляя ее);

size – узнать количество элементов в стеке;

clear – очистить стек (удалить из него все элементы).

Рис.43. Графическое изображение стека

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

struct st // объявление типа stack

{

char info; информационная часть

struct st *ps; // указатель на предыдущий (более нижний) элемент стека

} stack;

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

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

Пример 35. Представим выражение (a+b)/(c/a*c – e*d) в постфиксном виде:

ОПЗ: ab+ca/c*ed*–/. Вычислим ОПЗ слева на право, при вычислении пользуемся правилом: «в операции участвуют два операнда, расположенные слева от знака операции».

  1. Первое вычисление: R1 = ab+ = a+b, подставляем в исходную строку вместо ab+ вычисленный результат R1 получается ОПЗ: R1ca/c*ed*–/.

  2. Второе действие: R2 = ca/ = c/a

ОПЗ: R1R2c*ed*–/

  1. Третье действие: R3 = R2c* = R2*c = c/a*c

ОПЗ: R1R3ed*–/

  1. Четвертое действие: R4 = ed* = e*d

ОПЗ: R1R3R4–/

  1. Пятое действие: R5 = R3R4 = R3R4 = c/a*ce*d

ОПЗ: R1R5/

  1. Шестое действие: R6 = R1R5/ = R1/R5=(a+b)/(c/a*ce*d)

ОПЗ: R6

ОПЗ вычислено и его значением стало значение выражения R6.

Наиболе известным алгоритмом перевода простого алгебраического выражения в ОПЗ является алгоритм Дейкстры (Э́дсгер Ви́бе Де́йкстра, 1930–2002, – выдающийся нидерландский ученый, идеи которого оказали огромное влияние на развитие компьютерной индустрии). Идея алгоритма основывается на использовании стека и анализе приоритета операций и заключается в следующем:

  1. Исходная строка просматривается посимвольно, слева направо до достижения конца строки.

  2. Если встречается символ операция, то эта операция при определенных условиях помещается в стек (затем при определенных условиях операции выталкиваются в выходную строку).

  3. Если встречаются символы операндов, то они из входной строки поступают сразу в выходную строку.

  4. Если встречается открывающаяся скобка, то она всегда помещается в стек.

  5. Закрывающаяся скобка ни в стек, ни в выходную строку не помещается. Когда она встречается во входной строке, то из стека выталкиваются все символы до первой встречной открывающейся скобки включительно. При этом знаки операций выталкиваются в выходную строку, а открывающаяся скобка просто удаляется из стека.

  6. Необходимо использовать следующие приоритеты операций (табл. 17). Чем больше значение приоритета, тем сильнее операция связывает операнды:

Таблица 17.

Приоритеты операций для вычисления ОПЗ

Операции

(

+

*

/

Приоритет

0

1

1

2

2

  1. Если во входной строке текущий символ – знак операции, то сравниваются приоритеты операций из строки и верхушки стека.

  2. Если приоритет операции из входной строки больше приоритета операции из верхушки стека, то операция из входной строки стека перемещается в стек.

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

  4. При встрече конца входной строки содержимое стека выталкивается в выходную строку.

Пример 36. Напишем программу перевода входной строки в ОПЗ.

/* Описание стpуктуpы(элемента стека) */

struct st

{

char c;

struct st *next;

};

struct st *push(struct st *, char);

/* Пpототипы функций */

char DEL(struct st **);