Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

информатика_2 / Программирование_С

.pdf
Скачиваний:
85
Добавлен:
16.03.2016
Размер:
2.31 Mб
Скачать

pt = & st_var;

// ставим указатель на экземпляр стека;

 

// далее работаем только через указатель

clrscr();

printf( "Положим в стек элементы (прекращение — 0): \n");

ClearStack( pt );

 

do

// заполнение стека

{

 

scanf("%d", &st_el);

}

while (Push( pt , st_el ) && (st_el != 0)); // функция Push возвращает

// данные об успехе/неуспехе // попытки

//while ( (st_el != 0) && Push( pt , st_el )); // проверьте этот вариант; в

//каком случае завершающий 0

//будет положен в стек?

printf( "В стеке:\n");

while (Pop( pt , &st_el )) // выталкивание и печать

//элементов стека

//функция Pop возвращает

//данные об успехе/неуспехе

//попытки

printf("%d ", st_el);

return 0;

}

void ClearStack( STACK * pt_st )

{

pt_st–>top = 0;

}

//ставим указатель на дно

//стека; нет необходимости

//«чистить» мусор, поскольку

//при проталкивании новых

//элементов они заменят

//старые

int StackIsFull( STACK * pt_st )

{

if (pt_st–>top >= ST_SIZE ) return TRUE;

121

else

return FALSE;

}

 

int StackIsEmpty( STACK * pt_st )

 

{

 

if (pt_st–>top == 0)

 

return TRUE;

 

else

 

return FALSE;

 

}

 

int Push( STACK * pt_st, int new_el )

 

{

 

if (! StackIsFull( pt_st ))

// есть ли место?

{

 

pt_st–>elem[pt_st–>top] = new_el;

// доступ к индексу массива

 

// через указатель на стек

pt_st–>top++;

// продвижение индекса после

return TRUE;

// проталкивания элемента

 

}

 

else

 

return FALSE;

 

}

 

int Pop( STACK * pt_st, int * new_el )

 

{

 

if (! StackIsEmpty( pt_st ))

// есть ли элементы?

{

 

pt_st->top--;

 

*new_el = pt_st–>elem[pt_st–>top];

// возвращаем вытолкнутый

return TRUE;

// элемент

 

}

 

else

 

return FALSE;

 

}

 

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

122

2.1.1.1. Задачи на стек на основе массива

2.1.1.1.1. Изменение порядка элементов стека (целые числа) на обратный Реализовать стек на основе массива, тип данных — целые числа. Прикладная задача:

исходный стек заполняется из входного потока, затем программа меняет порядок элементов стека на обратный.

2.1.1.1.2. Изменение порядка элементов стека (строки) на обратный Реализовать стек на основе массива, тип данных — строки символов. Прикладная задача:

исходный стек заполняется из входного потока, затем программа меняет порядок элементов стека на обратный.

2.1.1.1.3. Смена местами половин стека (целые числа) Реализовать стек на основе массива, тип данных — целые числа. Прикладная задача:

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

2.1.1.1.4. Смена местами половин стека (строки)

Реализовать стек на основе массива, тип данных — строки символов. Прикладная задача:

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

2.1.1.1.5. Удаление элементов стека, больших заданного Реализовать стек на основе массива, тип данных — целые числа. Прикладная задача:

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

2.1.1.1.6. Удаление элементов стека, больших по длине заданной Реализовать стек на основе массива, тип данных — строки символов. Прикладная задача:

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

2.1.2. Очередь на основе массива

Очередь (queue) является структурой, реализующей иной, по сравнению со стеком, принцип хранения данных: FIFO — first in, first out (первым вошел — первым вышел).

Очередь с элементами типа int можно представить себе так (рис. 2.2):

Основные функции:

добавить элемент в хвост,

удалить элемент из головы.

123

Вспомогательные функции:

очередь пуста: да / нет,

очередь полна: да / нет.

Рис. 2.2. Очередь на основе массива

В соответствии с житейскими представлениями, изъятие элемента с головы должно привести к перемещению всех остальных элементов на одну ячейку массива, что совершенно нерационально с точки зрения программирования. Гораздо удобнее поддерживать два указателя (индекса элемента) — head (на голову очереди) и tail — на хвост (рис. 2.2, а). При изъятии элемента из головы и добавлении элемента в хвост указатели head и tail перемещаются соответствующим образом.

Особый интерес вызывает ситуация, когда хвост уже заполнен, однако перед головой еще имеется свободное пространство. В этом случае уместно организовать переход указателя хвоста на первый свободный элемент массива, тем самым «закольцовывая» эту структуру (рис. 2.2, б). Таким образом использование ограниченной статической памяти будет наиболее рациональным.

124

Следует еще остановиться на различении ситуаций очередь-полна и очередьпуста (рис. 2.2, в,г). Мы не можем свести обе ситуации к равенству указателей, поскольку ситуации станут неразличимы. Одно из возможных решений – условиться считать равенство указателей признаком ситуации очередь-пуста, а их различие на единицу — признаком ситуации очередь-полна.

Ввиду вышесказанного, очередь на основе массива можно представить в виде кольцевой структуры (рис. 2.3.):

Рис. 2.3. Кольцевая очередь на основе массива

Интерес здесь вызывает разве что организация перехода индекса головы или хвоста через границу массива (см. текст программы).

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

#include <stdio.h>

#include <conio.h>

#define Q_SIZE 10

#define TRUE –1

#define FALSE 0

struct QUEUE {

 

// определение очереди

int

elem[Q_SIZE];

 

int

head,

// индекс головы

};

tail;

// индекс хвоста

 

 

void ClearQue( QUEUE * pt_q );

// очистка очереди

125

int QueIsFull( QUEUE * pt_q );

// проверка заполненности очереди

int QueIsEmpty( QUEUE * pt_q );

// проверка пустоты очереди

int NewQueInd(int old_ind);

// новый индекс с учетом перехода

 

// через последний элемент массива

int AddInQue( QUEUE * pt_q, int new_el );

// добавление элемента в хвост

int GetFromQue( QUEUE * pt_q, int * new_el ); // удаление элемента из

//головы

void main()

 

{

 

QUEUE q_var;

// создаем экземпляр очереди

QUEUE * q_pt;

// создаем указатель на очередь

int q_el;

// целое число – элемент очереди

q_pt = & q_var;

// ставим указатель на экземпляр очереди

clrscr();

 

printf( " Поставим в очередь элементы (остановка - 0): \n");

ClearQue( q_pt );

do

// заполнение очереди

{

 

scanf("%d", &q_el);

}

while (AddInQue( q_pt , q_el ) && (q_el != 0)); // функция AddInQue

// возвращает данные об // успехе/неуспехе // попытки

printf( "В очереди были элементы: \n");

while (GetFromQue( q_pt , &q_el )) // удаление и печать

// головного элемента

// функция GetFromQue // возвращает данные об

// успехе/неуспехе попытки

printf("%d ", q_el);

}

void ClearQue( QUEUE * pt_q )

126

{

pt_q–>tail = 0;

// оба индекса — в начале

 

// массива, чистить который нет

pt_q–>head = 0;

// необходимости

 

}

int QueIsFull( QUEUE * pt_q )

{

if (pt_q–>head == NewQueInd(pt_q–>tail)) // в кольцевой структуре нет

// свободных ячеек

return TRUE; else

return FALSE;

}

int QueIsEmpty( QUEUE * pt_q )

{

if (pt_q–>tail == pt_q–>head)

// индексы головы и хвоста

return TRUE;

 

// совпали, очередь пуста

 

 

 

else

 

 

 

return FALSE;

 

 

 

}

 

 

 

int NewQueInd(int old_ind)

// «закольцовывание» индекса

{

// головы или хвоста

 

 

 

if (old_ind < Q_SIZE)

 

 

 

return old_ind + 1;

 

 

 

else

 

 

 

return 0;

 

 

 

}

 

 

 

int AddInQue( QUEUE * pt_q, int new_el )

 

{

 

 

 

if (! QueIsFull( pt_q ))

 

 

// есть ли место?

{

 

 

 

pt_q–>elem[pt_q–>tail] = new_el;

// доступ к индексу массива

// через указатель на хвост pt_q–>tail = NewQueInd(pt_q–>tail); // продвижение индекса после

// добавления в хвост

return TRUE;

}

127

else

return FALSE;

}

 

int GetFromQue( QUEUE * pt_q, int * new_el )

 

{

 

if (! QueIsEmpty( pt_q ))

// есть ли элементы?

{

 

* new_el = pt_q–>elem[pt_q–>head];

// возвращаем элемент

 

// головы

pt_q–>head = NewQueInd(pt_q–>head);

// новый индекс головы

return TRUE;

 

}

 

else

 

return FALSE;

 

}

 

2.1.2.1. Задачи на очередь на основе массива

2.1.2.1.1. Изменение порядка элементов очереди (целые числа) на обратный Реализовать очередь на основе массива, тип данных — целые числа. Прикладная задача:

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

2.1.2.1.2. Изменение порядка элементов очереди (строки) на обратный Реализовать очередь на основе массива, тип данных — строки символов. Прикладная задача:

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

2.1.2.1.3. Смена местами половин очереди (целые числа) Реализовать очередь на основе массива, тип данных —- целые числа. Прикладная задача:

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

2.1.2.1.3. Смена местами половин очереди (строки)

Реализовать очередь на основе массива, тип данных — строки символов. Прикладная задача:

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

2.1.2.1.4. Удаление элементов очереди, больших заданного Реализовать очередь на основе массива, тип данных — целые числа. Прикладная задача:

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

128

2.1.2.1.5. Удаление элементов очереди, больших по длине заданной Реализовать очередь на основе массива, тип данных — строки символов Прикладная задача:

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

2.1.3. Двусторонняя очередь (DEQ) на основе массива

Естественным расширением структуры очереди является дек — DEQ (Double Ended Queue), то есть двусторонняя очередь (рис. 2.4). Ее система функций приведена ниже.

Основные функции:

добавить элемент слева,

удалить элемент слева,

добавить элемент справа,

удалить элемент справа.

Вспомогательные функции:

дек пуст: да / нет,

дек полон: да / нет.

Дек с элементами типа int представить себе так (рис. 2.4):

Рис. 2.4. Двусторонняя очередь на основе массива

Как и простая очередь, дек реализуется на основе массива с двумя указателями; однако и добавлять, и изымать элементы здесь можно и справа, и слева. Это небольшое усовершенствование делает дек почти универсальной структурой, поскольку его частными случаями являются лево-и правосторонняя очередь, лево-и правосторонний стек.

Например, функции правосторонней очереди реализуются на основе функций дека так:

очередь_вправо:

добавить элемент слева,

удалить элемент справа.

129

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

2.1.3.1. Задачи на двустороннюю очередь

2.1.3.1.1. Изменение порядка элементов очереди (целые числа) на обратный Реализовать DEQ на основе массива, тип данных — целые числа. Прикладная задача:

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

2.1.3.1.2. Изменение порядка элементов очереди (строки) на обратный Реализовать DEQ на основе массива, тип данных — строки символов. Прикладная задача:

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

2.1.3.1.3. Смена местами половин очереди (целые числа) Реализовать DEQ на основе массива, тип данных — целые числа. Прикладная задача:

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

2.1.3.1.4. Смена местами половин очереди (строки)

Реализовать DEQ на основе массива, тип данных — строки символов. Прикладная задача:

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

2.1.3.1.5. Удаление элементов очереди, больших заданного Реализовать DEQ на основе массива, тип данных — целые числа. Прикладная задача:

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

2.1.3.1.6. Удаление элементов очереди, больших по длине заданной Реализовать DEQ на основе массива, тип данных — строки символов. Прикладная задача:

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

2.1.4. Множество на основе массива

Множество относится к первичным, или неопределимым объектам математики; на уровне интуиции можно сказать, что множество — это совокупность некоторых объектов (тут же возникает вопрос — а что такое

совокупность?). Объект либо входит в множество ("принадлежит множеству"),

либо нет; он не может входить в множество дважды. В этом отличие множеств от

130

Соседние файлы в папке информатика_2