Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
методички.C++ / Конспект Лекций - Части 1,2.pdf
Скачиваний:
270
Добавлен:
24.02.2016
Размер:
1.97 Mб
Скачать

2)формирование информационной части info;

3)если i = 0, то освобождаем захваченную память для созданного элемента (delete t;) и возвращаем NULL, т.е. формирование очереди закончилось.

4)иначе, т.е. i 0, формируем информационную часть и, используя адресную часть только что созданного элемента, опять обращаемся к функции input:

t -> Next = input();

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

4. Динамическая структура данных – СТЕК

Рассмотрим алгоритмы работы со списковыми динамическими данными на примере структуры под названием «СТЕК».

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

Вход

 

3

2

1

 

 

 

 

Выход «Вершина стека»

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

Максимальное число элементов стека не должно ограничиваться, т.е. по мере вталкивания в стек новых элементов, память под него должна динамически запрашиваться и освобождаться также динамически при удалении элемента из стека. Таким образом, стек – динамическая структура данных, состоящая из переменного числа элементов одинакового типа.

Состояние стека рассматривается только по отношению к его вершине, а не по отношению к количеству его элементов, т.е. только вершина стека характеризует его состояние.

Операции, выполняемые над стеком, имеют специальные названия: push – добавление элемента в стек (вталкивание);

pop – выталкивание элемента из стека, верхний элемент стека удаляется (не может применяться к пустому стеку).

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

113

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

Ниже приведены основные словесные алгоритмы для работы со стеком.

Алгоритм формирования первых 2-х элементов

1. Описать структуру переменной (рекомендуется шаблон структуры описывать глобально):

struct Stack

info

Next

 

 

 

struct Stack {

int info; Stack *Next;

};

2.Объявить два указателя на структуру:

Stack *begin (вершина стека), *t (текущий элемент);

3. Стек пуст, поэтому вершина в NULL: begin = NULL; (такое значение необходимо для первого вталкиваемого в стек элемента); графически это можно изобразить так:

begin NULL

4. Захват памяти под первый (текущий) элемент: t = new Stack;

формируется конкретный адрес (А1) для первого элемента, т.е. t равен А1. 5. Считываем информацию (i1);

а) формируем информационную часть: t -> info = i1;

t

info = i1

Next

 

 

 

б) значение вершины – в адресную часть (там был NULL) t -> Next = begin;

6. Вершину стека переносим на созданный (1-ый) элемент: begin = t;

получили:

begin (=A1) info =i1 NULL

7. Опять захватываем память (под второй элемент): t = new Stack;

имеем конкретный адрес (A2) для второго элемента, т.е. по шагам 8. Считываем для него информацию (i2);

а) формируем информационную часть: t -> info = i2;

114

б) в адресную часть – значение вершины, т.е. адрес предыдущего (первого) элемента (А1):

t -> Next = begin;

t (=A2) info = i2 Next = A1

9. Вершину стека снимаем с первого и устанавливаем на новый элемент

(A2):

begin = t;

получим:

begin (=A2)

Info=i2

Next=A1

 

Info=i1

Next=NULL

 

 

 

 

 

 

Алгоритм добавления текущего элемента

1.Захват памяти под текущий элемент (формирование конкретного адреса).

2.Формирование информационной части.

3.Формирование адресной части:

в адресную часть значение вершины;

в вершину значение адреса нового элемента.

Алгоритм извлечения элемента из стека

Рассмотрим данный алгоритм с обработкой и уничтожением.

1. Используя вершину стека, выдавливаем последний занесенный элемент: t = begin;

2.Обрабатываем информационную часть (t ->i nfo) (выводим на экран).

3.Вершине стека присваиваем значение адресной части, т.е. вершину переставляем на следующий элемент: begin = t->Next;

4.Уничтожаем обработанный элемент, т.е. освобождаем занятую под него память: delete t;

Для первых двух элементов рассмотрим подробно:

begin=A2

i2 Next=A1

 

i1 NULL

 

t

1)t = begin;

2)t -> info; например, печать i

3)begin = t -> Next; ,т.е. begin равен A1

begin

t

 

 

i2

Next=A1

 

 

 

 

i1

NULL

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4)delete t;

А теперь давайте рассмотрим алгоритмы решения конкретного примера.

115

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

В программе должна получиться следующая структура данных:

begin

ik

p

 

ik-1

 

...

 

 

i1

NULL

 

 

 

 

 

 

 

 

 

 

 

Декларируем структурный тип данных глобально: struct Stack {

int info; Stack *Next; } ;

Формирование стека из k элементов

1.Декларируем объекты int i, kol = 0; где i – дополнительная переменная, kol – счетчик элементов;

Stack *begin = NULL, (стек пуст) *t;

2.Начало бесконечного цикла, например while(1)

а) считывание информации для текущего элемента (ввод i); б) если i<0 выход из цикла – break;

в) захват памяти под текущий элемент: t = new Stаck;

г) формирование информационной части t -> info = i;

д) значение вершины стека заносим в адресную часть текущего элемента (для первого элемента NULL):

t -> Next = begin;

е) вершину стека переставляем на начало только что созданного элемента: begin = t;

ж) счетчик элементов увеличиваем на единицу: kol++;

3.Конец цикла.

4.Вывод сообщения: «Kol elementov =… ».

Просмотр стека

1.Устанавливаем текущий указатель на вершину. Проверяем, не пуст ли стек. Если begin=NULL, то стек пуст (выдаем сообщение, и либо завершаем работу, либо переходим на его формирование).

2.Если стек не пуст начинаем цикл, выполняя до тех пор, пока t != NULL, т.е. не дошли до последнего.

а) выводим на печать информационную часть: printf(“\n Элемент: %d”, t -> info);

б) переставляем текущий указатель на следующий элемент:

116

t = t -> Next;

3. Конец цикла.

Поиск максимального элемента

1. Устанавливаем указатель текущего элемента на вершину: t = begin;

(можно проверить, не пустой ли стек).

2. Положим, что максимальный – это элемент вершины: int max = t -> info;

int nom_max = k; – номер элемента вершины, т.е. последнего. 3. Начало цикла, используем конструкцию do-while: do (выполнять)

а) begin = t -> Next; – переставляем вершину стека на следующий элемент, а указатель t остался на k-ом;

б) проверяем, если (t->info > max), заменяем max=t->info; и nom_max=k;

в) освобождаем память просмотренного элемента t : delete t;

г) t = begin; теперь и вспомогательный указатель устанавливаем на следующий элемент и уменьшаем номер текущего элемента: k--;

4.Конец цикла, выполняющегося до тех пор пока t != NULL.

5.Вывод на экран найденных значений max и nom_max.

Т.е. для данной конструкции:

1-ый прогон:

begin

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...

 

 

 

 

 

t

 

 

 

ik

 

pk

 

 

 

 

 

 

ik-1

 

pk-1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k

 

 

 

 

 

 

 

 

k-1

 

 

 

 

 

 

 

 

 

 

 

 

 

2-ой прогон:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

t

 

 

 

 

 

 

 

begin

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ik

 

pk

 

 

 

 

ik-1

 

 

pk-1

 

 

 

 

 

ik-2

 

pk-2

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k

 

 

 

 

 

 

k-1

 

 

 

 

 

k-2

 

 

 

 

Завершится цикл тогда, когда p1 станет равно NULL (на предпоследнем ша-

ге Uk=NULL).

Текст программы может быть следующим:

#include <stdio.h> #include <conio.h>

struct Stack { // Описание структурного типа Stack int info;

Stack *Next;

117

} ;

 

void main(void) {

 

Stack *begin = NULL, *t;

 

int i, kol = 0;

 

while (1) {

// Формирование стека

printf(" Input info : ");

 

scanf("%d", &i);

 

if(i<0) break;

// Выход из while(1)

t = new Stack;

 

t -> info = i;

 

t -> Next = begin;

 

begin = t;

 

kol++;

 

}

 

 

printf("\n Kol elementov = %d", k);

//====================== Просмотр стека ===================

t = begin;

// Установили текущий указатель на вершину if(t == NULL)

{

 

printf("\n NO Steck!");

return;

}

 

i = k;

 

while (t != NULL) {

 

printf(“\n Element

%d: %d”, i--, t -> info);

t = t -> Next;

// Текущий указатель на следующий элемент

}

 

//====================== Поиск максимума ================

t = begin; // Установили текущий указатель на вершину int max = t -> info;

int nom_max = k; do {

begin = t -> Next; if (t->info > max) {

max = t->info; nom_max = k;

}

 

delete t;

// Освобождаем память

t = begin;

 

k--;

 

} while (t != NULL);

 

printf(“\n Max = %d , number = %d ”, max, nom_max); getch();

}

118

Пример использования стека для проверки правильности расстановки скобок в арифметическом выражении.

Скобки расставлены верно, если:

а) число открывающихся и закрывающихся скобок совпадает; б) каждой открывающейся скобке соответствует закрывающаяся скобка.

Для выражения: ( А – ( В + С ) – D / ( A + C ) – нарушено первое условие, а для выражения: ( A – B ) + C ) – ( D / ( A + C ) – нарушено второе условие.

Алгоритм анализа следующий:

Просматриваем выражение слева направо.

1.Если обнаружена открывающая скобка, то записываем ее в стек.

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

3.Если теперь обнаружена открывающаяся скобка, то анализируем содержимое стека:

а) если стек пуст, то открывающая скобка отсутствует и выражение составлено неверно, выводим сообщение об этом и завершаем работу;

б) если стек не пуст, выбираем скобку – она открывающая, обе скобки выбрасываем из рассмотрения.

4.После того, как будет просмотрено все выражение, проверяем стек и, если он не пустой, то баланс скобок нарушен и выражение составлено неверно, выводим сообщение об этом и завершаем работу.

По такому принципу работают все компиляторы, проверяя арифметические выражения, вложенные блоки {...}, вложенные циклы и т.п.

Пример выражения:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

( x + ( y – ( a + b ) ) * c – ( d + e ) ) * k

 

 

 

 

 

 

 

1

2

 

3

4 5

6

 

7 8

 

 

begin = NULL

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(

 

(

 

(

 

 

(

 

(

 

(

 

(

 

 

 

 

 

 

 

 

(

 

(

 

 

(

 

 

 

(

 

 

 

 

 

 

 

 

 

 

 

 

(

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

2

 

3

 

 

4

 

5

 

6

 

7

9

 

 

119

Соседние файлы в папке методички.C++