книги / Технологии разработки объектно-ориентированных программ на язык C++. Основы структурного программирования на алгоритмическом языке C++
.pdf
|
из массива |
qu.push(mas[i]); |
|
cout << "Очередь после добавления: "; |
|
print(qu); |
// Печать очереди |
Подробнее: в цикле (строки 1–4) все элементы очереди переносятся в массив. Затем добавляются первые три элемента (строки 5–6) из массива, после добавляются три новых элемента (строки 7–8) и оставшиеся три из массива (строки 9–10). Очередь печатается.
Пример выполнения работы программы:
5 7 5 10 5 4 3 10 1 4
Очередь после удаления: 5 10 5 4 3 10 Очередь после добавления: 5 10 5 2 9 6 4 3 10
14.12. Реализация очереди через структуры
Рассмотрим решение задачи в гл. 3, реализованное через структуры.
Структура очередь имеет минимум два поля: ключ (значение, которое будет хранить элемент очереди) и указатель на следующий элемент очереди.
struct Queue { int data; Queue* next;
};
Данная структура имеет имя queue и содержит два поля: int data, queue* next.
Создание очереди:
Queue* make_queue(int n, queue* &first, queue* &last) { if (n == 0) return NULL;
Queue* p = new Queue; // Выделение памяти под один элемент
p->data = rand() % 10 + 1;
p->next = NULL; /* Так как он первый, то он ни на что не указывает */
161
first = p; |
// Новый элемент является первым |
last = p; |
// И последним |
for (int i = 2; i <= n; i++) { Queue* h = new queue;
// Выделение памяти для нового элемента
h->data = |
rand()%10 + 1; |
||
h->next = |
p; |
// Указываем на следующий элемент |
|
last = h; |
|
/* |
Показываем, что введенный |
|
|
|
элемент стал последним */ |
p = last; |
|
// |
Перешли к последнему элементу |
}
return first;
}
Подробнее: в строке 4 присваивается первый элемент. Затем в цикле от 2 до n (начальное количество элементов в очереди) присваиваются остальные элементы. В строке 9 выделяется память для нового элемента. Затем в строке 11 указателю нового элемента присваивается указатель на последний элемент в очереди, в строке 12 указателю на последний элемент присваивается указатель на новый элемент. В строке 15 указатель на первый элемент возвращается.
Вывод очереди на экран:
void PrintQueue(Queue* last) { |
/* Печать очереди без |
|
удаления элементов */ |
Queue* p = last; |
// p указывает на |
|
последний элемент |
while (p != NULL) { // Печать с конца очереди |
|
cout << p->data << " "; |
// Печать |
p = p->next; |
// Переход к следующему |
|
элементу |
}
cout << endl;
}
Подробнее: параметром передается указатель на последний элемент очереди. В строке 2 указателю p присваивается указатель на последний элемент очереди. В цикле (строки 3–6) выводятся значения каждого элемента очереди, пока не дойдет до первого элемента.
162
Поскольку очередь имеет строгие правила удаления и добавления элементов, реализуем их отдельно, и в дальнейшем будем использовать эти функции.
Удаление элемента из очереди:
int pop(Queue* &first, Queue* &last) { // Функция удаления элемента
Queue* p = last;
int k = 0; // Кол-во элементов в очереди while (p != NULL) { // Считаем кол-во элементов
k++;
p = p->next;
/* Если элемент один, то обнуляем указатели и возвращаем последний элемент */
int t = last->data; delete p;
last = NULL; first = NULL; return t;
} |
|
else { |
// Если больше одного |
while (p->next->next != NULL)
// Переходим к предпоследнему элементу p = p->next;
Queue* t = p; // Указатель на предпоследний
|
элемент |
int e = p->next->data; |
|
// Сохранение значения последнего элемента |
|
p = p->next; |
// Переход к последнему элементу |
t->next = NULL; |
// Предпоследний указатель |
|
указывает на NULL |
first = t; |
// И он теперь первый элемент |
delete p; |
// Удаление последнего элемента |
return e; |
// Возвращение первого элемента |
}
}
163
Подробнее: параметром передается указатель по ссылке на первый и последний элементы очереди. В строке 2 объявляется указатель p, чтобы сохранить последний элемент. Подсчет количества элементов в очереди (строки 3–6). Если в очереди находится один элемент, то возвращается значение этого элемента и удаляется из памяти (строки 8–16), а если нет, то осуществляется переход к предпоследнему элементу (строки 18–19) и его указатель сохраняется в переменную t. Переход к последнему элементу, сохранение его значения, чтобы потом возвратить, и удаление элемента. Указателю предпоследнего элемента присваивается NULL, а указателю на первый элемент очереди присваивается указатель предпоследнего элемента.
Добавление элемента в очередь:
Queue* push(int n, queue* &last) {
Queue* p = new queue; |
// Выделение памяти для нового |
|
элемента |
p->data = n; |
// Присвоение |
p->next = last; |
// Наш новый элемент указывает на |
|
следующий |
last = p; |
// Новый элемент стал последним |
return last; |
|
} |
|
Подробнее: параметром передается указатель на последний элемент очереди и значение элемента, который необходимо добавить. Выделяется память для нового элемента (строка 2), присваивается значение, переданное параметром (строки 3–5), указателю нового элемента присваивается указатель на последний элемент очереди (строка 6), а указателю на последний элемент присваивается указатель на новый элемент (строка 7).
Удаление первых двух и последних двух элементов (в главной функции):
pop(first, last); |
// Удаление первого элемента |
pop(first, last); |
// Удаление второго элемента |
int mas[6]; |
|
164
for (int i = 0; i < 6; i++) // Перенос элементов в массив mas[i] = pop(first, last);
pop(first, |
last); |
// |
Удаление |
девятого |
элемента |
pop(first, |
last); |
// |
Удаление |
десятого |
элемента |
for (int i = 0; i < 6; i++) // Перенос элементов в массив push(mas[i], last);
cout << "Очередь после удаления: "; print_queue(last); // Печать очереди
Подробнее: удаляются первые два элемента (строки 1–2) методом pop(). Затем создается массив из шести элементов для временного хранения всех элементов очереди, кроме последних двух. В цикле (строки 4–5) все элементы очереди, кроме двух, переносятся в массив. Удаляются последние два элемента (строки 6–7). Затем все элементы переносятся обратно в очередь (строки 8–9). Очередь печатается (строка 11).
Добавление трех элементов в середину очереди:
for (int i = 0; i < 6; i++) // Перенос элементов в массив mas[i] = pop(first, last);
for (int i = 0; i < 3; i++) // Добавление первой половины из массива
push(mas[i], last);
for (int i = 0; i < 3; i++) // Добавление новых элементов push(rand()% 10 + 1, last);
for (int i = 3; i < 6; i++) // Добавление второй половины из массива
push(mas[i], last);
cout << "Очередь после добавления: "; print_queue(last); // Печать очереди
Подробнее: в цикле (строки 1–2) все элементы очереди переносятся в массив. Затем добавляются первые три элемента (строки 3–4) из массива, после добавляются три новых элемента (строки 5–6) и оставшиеся три из массива (строки 7–8). Очередь печатается.
Главная функция:
int main() { setlocale(LC_ALL, "Rus");
165
srand(time(0)); |
|
Queue* first,* last; |
/* Указатели на первый и последний |
|
элементы очереди */ |
make_queue(10, first, last); |
|
print_queue(last); |
// Печать очереди |
pop(first, last); |
// Удаление первого элемента |
pop(first, last); |
// Удаление второго элемента |
int mas[6]; |
|
for (int i = 0; i < 6; i++)
// Перенос элементов в массив mas[i] = pop(first, last);
pop(first, |
last); |
// |
Удаление |
девятого |
элемента |
pop(first, |
last); |
// |
Удаление |
десятого |
элемента |
for (int i = 0; i < 6; i++)
// Перенос элементов в массив push(mas[i], last);
cout << "Очередь после удаления: "; print_queue(last); // Печать очереди for (int i = 0; i < 6; i++)
// Перенос элементов в массив mas[i] = pop(first, last);
for (int i = 0; i < 3; i++)
// Добавление первой половины из массива push(mas[i], last);
for (int i = 0; i < 3; i++) // Добавление новых элементов
push(rand()% 10 + 1, last);
for (int i = 3; i < 6; i++) /* Добавление второй половины из массива */
push(mas[i], last);
cout << "Очередь после добавления: "; print_queue(last); // Печать очереди return 0;
}
Пример выполнения работы программы:
3 10 1 7 10 10 7 1 8 3
Очередь после удаления: 1 7 10 10 7 1 Очередь после добавления: 1 7 10 1 1 2 10 7 1
166
14.13. Реализация очереди через класс
Рассмотрим решение задачи в гл. 3, реализованное через класс. Первым шагом создается класс queue со всеми необходимыми
методами.
class Queue { |
|
private: |
|
int* arr; |
// Массив элементов очереди |
int MAX; |
// Максимальное кол-во элементов очереди |
int index; |
// Текущий элемент очереди |
public: |
|
Queue(int); |
// Конструктор |
~Queue(); |
// Деструктор |
bool push(int); |
// Вставка элемента |
int pop(); |
// Удаление элемента |
void print(); |
// Печать очереди |
}; |
|
Скрытые данные: указатель на массив элементов, максимальное количество элементов в очереди, номер текущего элемента в очереди. Публичные методы: конструктор, деструктор, добавление элемента, удаление элемента и печать очереди.
Конструктор и деструктор:
Queue::Queue(int kol) { // Создание очереди c кол-вом
|
элементов = kol |
MAX = 100; |
// Максимальное кол-во элементов |
|
очереди |
index = –1; |
// Начальный индекс |
if (kol <= MAX) { |
// Если количество не больше |
|
максимума |
arr = new int[kol]; |
|
MAX = kol; |
// Изменение максимума |
}
else cout << "Переполнение очереди\n";
} |
|
Queue::~Queue() { |
// Деструктор |
167
delete[] arr;
};
Подробнее: параметром для конструктора передается максимальное количество элементов очереди. Переменной MAX присваивается переданный параметр (строка 6), и выделяется память для массива элементов (строка 5). Если ввели количество элементов больше 100, то выводит ошибку о переполнении очереди (строка 8). В деструкторе удаляется массив (строка 11).
Печать очереди:
void Queue::print() {
for (int i = 0; i <= index; i++) cout << arr[i] << " ";
cout << endl;
}
Подробнее: элементы массива печатаются в прямом порядке
(строки 2–3).
Добавление элемента в очередь:
bool Queue::push(int n) { int t;
if (index == MAX) // Если очередь уже полная return 0;
else {
if (index == –1) // Вставка первого элемента arr[++index] = n;
else { // Вставка остальных элементов for (int i = index; i >= 0; i--) {
// Вставка элементов по очереди arr[i + 1] = arr[i];
arr[i] = n;
}
index++;
}
return 1;
}
};
168
Подробнее: параметром передается значение элемента, который нужно добавить. Если происходит попытка добавить элемент, но места для него уже нет, то возвращается 0 (строка 4), иначе если добавляется первый элемент, то индекс увеличивается на 1 и элемент добавляется в массив (строки 6–7), а если в очереди уже есть элементы, то все элементы массива смещаются вправо и в начало массива добавляется новый элемент (строки 9–13).
Удаление элемента из очереди:
int Queue::pop() { |
|
if (index == –1) { |
// Если индекс не |
|
изменился |
cout << "Очередь пуста\n"; |
|
return 0; |
|
} |
|
else |
|
return arr[index--]; |
|
}; |
|
Подробнее: если очередь пустая, то это сообщается пользователю и возвращается 0 (строки 3–4), а если нет, то возвращается элемент, который был добавлен последним (строка 6).
Удаление первых двух и последних двух элементов:
qu.pop(); |
// Удаление первого элемента |
qu.pop(); |
// Удаление второго элемента |
int mas[6]; |
|
for (int i = 0; i < 6; i++) |
// Перенос элементов в массив |
mas[i] = qu.pop(); |
|
qu.pop(); |
// Удаление девятого элемента |
qu.pop(); |
// Удаление десятого элемента |
for (int i = 0; i < 6; i++) |
// Перенос элементов в массив |
qu.push(mas[i]); |
|
cout << "Очередь после удаления: "; |
|
qu.print(); |
// Печать очереди |
Подробнее: удаляются первые два элемента (строки 1–2) методом pop(). Затем создается массив из шести элементов для временного хранения всех элементов очереди, кроме последних двух.
169
В цикле (строки 4–5) все элементы очереди, кроме двух, переносятся в массив. Удаляются последние два элемента (строки 6–7). Затем все элементы переносятся обратно в очередь (строки 8–9). Очередь печатается (строка 11).
Добавление трех элементов в середину очереди:
for (int i = 0; i < 6; i++) // Перенос элементов в массив mas[i] = qu.pop();
for (int i = 0; i < 3; i++) // Добавление первой половины из массива
qu.push(mas[i]);
for (int i = 0; i < 3; i++) // Добавление новых элементов qu.push(rand()%10 + 1);
for (int i = 3; i < 6; i++) // Добавление второй половины
|
из массива |
|
qu.push(mas[i]); |
|
|
cout << "Очередь после добавления: "; |
|
|
qu.print(); |
// Печать |
очереди |
Подробнее: в цикле (строки 1–2) все элементы очереди переносятся в массив. Затем добавляются первые три элемента (строки 3–4) из массива, после добавляются три новых элемента (строки 5–6) и оставшиеся три из массива (строки 7–8). Очередь печатается.
Главный файл:
#include <iostream> #include <time.h> #include "queue.h" using namespace std; int main() {
setlocale(LC_ALL, "Rus"); srand(time(0));
Queue qu(10); // Очередь имеет максимум 10 элементов for (int i = 0; i < 10; i++)
qu.push(rand() % 10 + 1); qu.print(); // Печать очереди qu.pop(); // Удаление первого элемента qu.pop(); // Удаление второго элемента
170