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

книги / Технологии разработки объектно-ориентированных программ на язык C++. Основы структурного программирования на алгоритмическом языке C++

.pdf
Скачиваний:
4
Добавлен:
12.11.2023
Размер:
3.17 Mб
Скачать

add_begin(list);

/* Добавление трех

 

элементов

в начало

 

списка */

 

cout << "Cписок c добавлением: "; print_list(lis); // Печать списка return 0;

}

Пример выполнения программы:

Введите кол-во элементов: 5 Введите 1 элемент: 1 Введите 2 элемент: 2 Введите 3 элемент: 3 Введите 4 элемент: 4 Введите 5 элемент: 5

1 2 3 4 5

Новый список: 1 3 5 Введите 1 число: 6 Введите 2 число: 7 Введите 3 число: 8

Список с добавлением: 8 7 6 1 3 5

14.2. Реализация однонаправленного списка через класс

Рассмотрим решение задачи в подразд. 14.1, реализованное через класс.

Первым шагом создается класс list со всеми необходимыми методами:

class List {

// Класс список

private:

 

class Node {

// Класс для ячеек

public:

 

Node* next;

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

int data;

Node(int data1 = 0, Node* next1 = nullptr) {

//Конструктор data = data1;

121

next = next1;

 

}

 

};

 

Node* head;

// Указатель на первый элемент

int size;

// Кол-во элементов списка

public:

 

List();

// Конструктор

~List();

// Деструктор

void push_back(int);

// Вставка в конец списка

void push_begin(int);

// Вставка в начало списка

void print(); // Печать списка

bool delete_even(int);

// Удаление четных элементов

};

 

Описывается дополнительный класс node внутри класса списка (строка 3), который отвечает за создание ячейки в списке, а класс list (строка 1) работает с этими ячейками. Также к приватным данным относится указатель на первый элемент списка и количество элементов списка. Со строки 17 по строку 26 описаны прототипы методов, которые работают со списком (добавление, удаление и т.д.).

Конструктор и деструктор:

List::List() {

// Конструктор

size = 0;

// Пустой список

head = nullptr;

// Первого элемента пока нет

}

 

List::~List() {

// Деструктор

delete head;

 

}

 

Печать однонаправленного списка:

void List::print() {

 

if (head == nullptr)

// Если список пуст

cout << "Список пустой\n";

Node* t = head;

// t указывает на первый

 

Элемент

122

while (t) {

 

cout << t->data << " ";

// Вывод элементов

t = t->next;

// Переход к следующему

 

элементу

}

 

cout << endl;

 

}

 

Подробнее: если происходит попытка напечатать список, в который еще не добавили элементов, то программа выведет, что список пустой (строка 3). Переменной t присваивается указатель на первый элемент списка (строка 4), и затем в цикле (строки 5–8) выводится значение элемента в списке и осуществляется переход к следующему элементу списка.

Добавление элемента в конец списка:

void List::push_back(int data) {

 

if (head == nullptr) {

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

 

первый элемент

head = new Node(data);

// Присвоение нового

 

элемента

}

 

else {

 

Node* t;

 

t = head;

// t указывает на первый

 

элемент

while (t->next)

// Переходим к последнему

элементу

t = t->next;

t->next = new Node(data); // Присваиваем новый элемент

}

size++; // Увеличиваем размер

}

Подробнее: если добавляется первый элемент, то выделяется память для нового элемента, и указателю head присваивается указатель на только что выделенную память (строка 3). Если же добав-

123

ляется не первый элемент, то переменной t присваивается указатель на первый элемент, и затем в цикле доходит до последнего элемента (строки 8–9). Затем выделяется память для нового объекта, и указателю последнего элемента присваивается указатель на новый элемент (строка 10). Увеличиваем size (строка 12), так как только что добавили элемент.

Добавление элемента в начало списка:

void list::push_begin(int data) {

 

if (head == nullptr)

// Если вставляется

первый

 

 

элемент

head = new Node(data);

// Присвоение нового

 

элемента

else {

 

Node* h = new Node(data);

// Создание нового

 

элемента

h->next = head;

/* Новый элемент

 

указывает на первый

 

элемент */

head = h;

// Новый элемент стает

 

первым

}

 

size++;

 

}

 

Подробнее: если добавляется первый элемент, то выделяется память для нового элемента, и указателю head присваивается указатель на только что выделенную память (строка 3). Если же добавляется не первый элемент, то выделяется память для нового объекта, указателю нового элемента присваивается указатель на первый элемент списка (строка 6) и указателю на первый элемент присваивается указатель на только что созданный элемент (строка 7). Увеличиваем size (строка 9), так как только что добавили элемент.

Удаление четных чисел:

void List::delete_even() {

// Удаление четных

чисел

 

if (head == nullptr)

// Если список пуст

124

return;

 

else {

 

Node* p = head;

 

while (p->data % 2 == 0) {

/* Если первый элемент

 

четный и все

 

последующие за ним

 

тоже четные */

Node* q = head;

/* Сохранили указатель

 

на первый элемент в

 

переменную q */

head = p->next;

/* Теперь first

 

указывает на второй

 

элемент списка */

delete q;

/* Удаляем из памяти

 

первый элемент */

p = head;

/* Обнулили p (p

 

указывает на новый

 

первый элемент

 

списка) */

if (p == NULL) return;

/* Так как больше

 

элементов нет, то

 

функция закончена */

}

 

while (p->next != NULL) {

if (p->next->data % 2 == 0) {

Node* q = p->next; /* Сохранили указатель на удаляемый элемент

*/ p->next = p->next->next;

/*

Указателю первого элемента присвоили указатель на третий элемент

*/ delete q;

}

else p = p->next;

}

}

}

125

// Вставка элементов в конец списка
// Печать списка // Удаление четных чисел

Подробнее: если список пуст, то возвращается 0, так как удаление невозможно (строка 2). В строке 6 начинается цикл while и выполняется, пока подряд идут четные числа. В строке 8 сохраняется указатель на первый элемент, а затем указателю first присваивается указатель на второй элемент, и первый элемент списка удаляется из памяти. Если список состоит только из четных элементов, то функция прекращается (строка 12). Данный цикл удалит все первые четные элементы, а это значит, что следующий цикл (строка 14) начнется с нечетного числа, и он будет выполняться, пока следующий элемент не будет NULL. Если за нечетным числом идет четное (строка 15), то элемент удаляется так же, как и в прошлом цикле, только вместо first используется p–>next, а вместо p–>next p–>next–>next (т.е. работа осуществляется с числом, стоящим после нечетного числа), а если за нечетным числом идет нечетное, то осуществляется переход указателя p к следующему числу (строка 20).

Главный файл:

#include <iostream> #include "ListOne.h" using namespace std; int main() {

setlocale(LC_ALL, "Rus"); List list;

cout << "Введите количество элементов списка: ";

int size;

// Количество элементов

списка

 

cin >> size;

 

for (int i = 0; i < size; i++) { // Создание списка cout << "Введите число: ";

int p; cin >> p;

list.push_back(p);

}

list.print(); list.delete_even();

126

cout << "Новый список: "; list.print(); // Печать списка

for (int i = 0; i < 3; i++) { // Добавление элементов cout << "Введите число: ";

int p; cin >> p;

list.push_begin(p);

// Вставка элементов в начало списка

}

cout << "Список после добавления: "; list.print(); // Печать списка return 0;

}

Пример выполнения работы программы:

Введите количество элементов списка: 8 Введите число: 1 Введите число: 2 Введите число: 6 Введите число: 2 Введите число: 8 Введите число: 4 Введите число: 2 Введите число: 7

1 2 6 2 8 4 2 7

Новый список: 1 7 Введите число: 5 Введите число: 6 Введите число: 3

Список после добавления: 3 6 5 1 7

Задание для самостоятельной работы:

Реализовать однонаправленный список из n элементов (вводится пользователем) двумя способами. Написать программу, которая сортирует список по убыванию и удаляет элемент в середине (если количество элементов нечетное) или удаляет два элемента в середине (если количество элементов четное), добавляет p элементов (вводится пользователем) в начало списка.

127

14.3. Реализация двунаправленного списка через библиотеку STL

Необходимо реализовать двунаправленный список случайных чисел из 10 элементов, используя класс list библиотеки STL. Написать программу, которая удаляет все числа, равные числу, введенному пользователем, из списка и добавляет p (вводится пользователем) числа в конец списка.

Подключаем необходимые библиотеки, русский язык и генератор случайных чисел:

#include

<iostream>

 

#include

<list>

// Заголовок списка

#include <iterator> // Заголовок итераторов #include <time.h>

using namespace std; int main() {

setlocale(LC_ALL, "Rus"); srand(time(0));

return 0;

}

Создаем список и выводим его на экран:

list<int> my_list;

// Объявляем пустой список

for (int i = 0; i <= 10; i++) { my_list.push_back(rand()%10 + 1);

// Добавляем в список новые элементы

}

cout << "Список: ";

copy(my_list.begin(), my_list.end(), ostream_iterator<int>(cout, " ")); // Вывод на экран элементов списка

cout << endl;

Подробнее: в строке 1 объявляется пустой список типа int с именем lis. Затем в цикле от 0 до 10 (строки 2–4) с помощью метода push_back случайные числа от 1 до 10 добавляются в конец списка. А с помощью функции copy() (строка 6) список выводят на экран.

128

// Добавление элементов

Удаление элемента из списка:

int n;

cout << "Введите число, которое хотите удалить: ";

cin >> n;

 

lis.remove(n);

// Удаление чисел

cout << "Удалили " << n << ": ";

 

copy(my_list.begin(), my_list.end(), ostream_iterator<int>(cout, " "));

Подробнее: объявляется переменная n – число, которое необходимо удалить. Вводится n (строка 3), и методом remove() все числа, равные n, удаляются из списка (строка 4). Затем список выводится прежним способом.

Добавление элементов в конец списка:

cout << "\n Введите, сколько чисел добавить в конец списка: "; int p;

cin >> p;

for (int i = 0; i < p; i++) { my_list.push_back(rand() % 10 + 1);

}

cout << "Новый список: ";

copy(my_list.begin(), my_list.end(), ostream_iterator<int>(cout, " "));

Подробнее: в строке 3 вводится число p – количество добавляемых чисел. Затем в цикле (строка 4–6) новые случайные числа добавляются в конец списка таким же способом, как и при создании списка. В конце новый список выводится на экран.

Пример выполнения программы:

Список: 1 2 8 5

4 6 10

2 4 7 8

Введите

число,

которое

хотите удалить: 2

Удалили

2: 1

8

5 4

6 10

4

7 8

Введите, сколько чисел

добавить в конец списка: 3

Новый список: 1

8 5 4 6 10 4 7 8 10 2 10

129

14.4. Реализация двунаправленного списка через структуры

Рассмотрим решение задачи в подразд. 14.3, реализованное через структуры.

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

struct List {

// Структура список

int data;

// Данные элемента списка

List* next;

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

List* prev;

// Указатель на предыдущий элемент

};

 

Данная структура имеет имя list и содержит три поля: int data, list* next (указатель имеет тип list, так как указывает на эту же структуру) и list* prev.

Создание списка:

List* make_list(int size) {

 

List* first, *p;

 

first =

NULL;

 

p = new

List;

// Выделение памяти для первого

 

 

элемента

p->data

= rand()%10 + 1;

 

first =

p;

// Делаем элемент первым

p->next

= NULL;

// Обнуление указателей первого

 

 

элемента

p->prev = NULL;

for (int i = 2; i <= size; i++) {

List* h = new list; /* Выделение памяти для следующего элемента */

List* q = p; /* Для того чтобы записать два указателя */

p->next = h; /* Настраиваем указатель предшествующего элемента */

p = p->next; // Переходим к следующему элементу

130

Соседние файлы в папке книги