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

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

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

p->data =

rand() % 10 + 1;

p->next =

NULL;

/* Обнуляем его указатель на

 

 

следующий элемент */

p->prev = q;

 

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

}

return first;

}

Подробнее: в строках 4–5 присваивается первый элемент. Затем в цикле от 2 до n (начальное количество элементов в списке) присваиваются остальные элементы. В строке 10 выделяется память для нового элемента. Затем в строке 12 указателю первого элемента присваивается указатель на только что созданный элемент, в строке 13 переходим к следующему элементу и для указателя нового элемента присваиваем указатель прошлого элемента (строка 16). Указателю только введенного элемента присваиваем NULL, так как он пока что является последним. В строке 18 возвращаем указатель на первый элемент.

Вывод списка на экран:

void print_list(List*first) {

 

if (first == NULL) {

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

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

}

 

List* p = first;

 

while (p != NULL) {

 

cout << p->data << " ";

// Вывод значения

 

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

p = p->next;

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

 

элементу

}

 

cout << endl;

}

Подробнее: параметром передается указатель на первый элемент однонаправленного списка. В строке 2 выполняется проверка, пустой список или нет. В строке 6 указателю p присваивается указатель на первый элемент списка. В цикле (строки 7–10) выводятся значения каждого элемента списка, пока p не указывает на NULL.

131

Поиск элемента в списке:

List* find(List* first, int val) {

 

if (first == NULL) return NULL;

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

List* p = first;

 

List* n = nullptr;

// Хранение

 

найденного элемента

while(p != NULL) {

// Выполняется, пока

 

есть элементы

if (p->data == val) {

// Если нашло равный

 

элемент

return p;

// Возвращается ссылка на найденный элемент

}

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

}

return 0;

}

Подробнее: параметром передается указатель на первый элемент двунаправленного списка и значение элемента, который необходимо найти. В цикле (строки 5–10) находим нужный элемент и возвращаем указатель на него, а если элемент не найден, то возвращаем 0.

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

void delete_element(int val, list* &first) {

if (first == NULL) return;

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

List* p = first;

 

List* e = nullptr;

 

bool f = false;

// Для проверки

while (p != NULL) {

// Проверка, входит элемент в список или нет if (p->data == val)

f = true; p = p->next;

}

132

if (!f) {

// Если не входит, то функция заканчивается cout << "Такого элемента нет. Удаление не произведено\n";

return;

}

p = first; // Обнуление р List* w = first;

while (w != NULL) { /*

Удаление первого элемента и, если все последующие за ним такого же значения

*/

if (first->data == find(first, val)->data) {

//Если удаляем первый элемент p = p->next;

//Переходим ко второму элементу first = p;

if (p != NULL) p->prev = NULL;

}

 

w = w->next;

 

}

 

p = first;

// Обнуление р

int kol = 0;

// Количество удаляемых

 

элементов

while (p != NULL) {

// Подсчет количества удаляемых

 

элементов

if (p->data == val)

kol++;

// Количество удаляемых

 

элементов

p = p->next;

 

}

 

if (first

==

NULL) return;

for (int j =

0;

j < kol;

j++) {

list* t

=

nullptr;

 

p = first;

 

 

int k =

0;

 

// Индекс удаляемого

133

элемента while (p->data != val) {

// Находим индекс элемента p = p->next;

k++;

if (p->data == val) { t = p->next;

// Сохраняем указатели удаляемого элемента

e = p->prev;

}

}

p = first; // Обнуление р

for (int i = 0; p != NULL; i++) { if (i == k – 1)

p->next = t; /*

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

*/ if (i == k)

p->prev = e; p = p->next;

}

}

}

Подробнее: параметром передается указатель на первый элемент двунаправленного списка, значение элемента, который хотим удалить. В цикле (строки 6–10) проверяется, входит ли такой элемент в список. Если такого элемента нет, то функция прекращается (строка 13). В строках 17–25 происходит удаление первых повторяющихся элементов, если они равны переданному параметру. Если получилось так, что все элементы были удалены, то выходим из функции (строка 33). В цикле (строки 30–34) происходит подсчет количества удаляемых чисел, и это число сохраняется в перемен-

134

// Обнуляем p

ную kol. Находится индекс удаляемого элемента в списке (строки 40–47), и число удаляется (строки 49–55).

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

void add_to_end(int kol, List* &first) {

if (first == NULL) return;

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

List* p

= first;

 

int k =

0;

// Счетчик

while (p != NULL) {

// Подсчитываем кол-во

 

 

элементов

p = p->next; k++;

}

p = first;

for (int i = 1; i < k; i++)

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

for (int i = 1; i <= kol; i++) {

//Добавление kol элементов по принципу создания списка

List* h = new list;

// Выделение памяти для следующего элемента

List* q = p;

//Для того чтобы записать два указателя p->next = h;

//Настраиваем указатель предшествующего элемента

p = p->next;

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

 

 

элементу

p->data =

rand()%10 + 1;

 

p->next =

NULL;

 

// Обнуляем его указатель на следующий элемент

p->prev = q;

 

// Указываем на прошлый

 

 

элемент

}

}

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

135

тов. В строках 5–8 подсчитываем количество элементов в списке. В строках 10–11 переходим к последнему элементу списка. Добавляем элементы по принципу создания двунаправленного списка

(строки 12–20);

Главная функция:

int main() {

 

setlocale(LC_ALL, "Rus");

 

srand(time(0));

 

List* list = make_list(10);

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

print_list(list);

// Печать списка

int n;

// Удаляемое число

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

списка: ";

 

cin >> n;

 

delete_element(n, list);

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

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

 

print_list(list);

// Печать списка

int p;

// Количество добавляемых

чисел

 

 

 

 

cout << "Введите количество добавляемых чисел: ";

 

cin >> p;

 

 

 

add_to_end(p, list);

// Добавление случайных

чисел

 

 

 

 

 

 

в конец списка

 

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

 

 

print_list(list);

// Печать списка

 

return 0;

 

 

}

 

 

 

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

 

1 6 6

1 4 1 4 5

2 1

 

Введите число, которое хотите удалить из списка: 4 Новый список: 1 6 6 1 1 5 2 1 Введите количество добавляемых чисел: 7

Новый список: 1 6 6 1 1 5 2 1 2 1 1 7 7 6 3

136

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

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

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

class List {

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

private:

 

 

class Node {

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

public:

 

 

node* next, *prev;

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

 

элемент

 

int data;

 

 

Node(int data1 = 0, node* next1 = nullptr, node*

prev1 == nullptr) {

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

data = data1;

 

 

next = next1;

 

 

prev = prev1;

 

 

}

 

 

};

 

 

Node* head;

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

мент

 

 

int size;

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

public:

 

 

List();

 

 

~List();

 

 

void push_back(int);

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

void print();

// Печать списка

bool delete_element_by_number(int);

// Удаление

 

 

элемента по

 

 

индексу

bool delete_element_by_value(int);

// Удаление

 

 

элемента по

значению

};

137

Описывается дополнительный класс 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 указывает на

 

 

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

while (t) {

 

 

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

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

t = t->next;

 

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

 

 

элементу

}

 

 

cout << endl;

 

 

}

 

 

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

138

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

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);

//Присваиваем новый элемент t->next->prev = t;

//Новый элемент указывает на прошлый

}

 

size++;

// Увеличиваем размер

}

Подробнее: если добавляется первый элемент, то выделяется память для нового элемента, и указателю head присваивается указатель на только что выделенную память (строка 3). Если же добавляется не первый элемент, то переменной t присваивается указатель на первый элемент, и затем в цикле доходит до последнего элемента (строки 8–9). Затем выделяется память для нового объекта, и указателю последнего элемента присваивается указатель на новый элемент (строка 10), а указателю на прошлый элемент нового элемента присваивается указатель t (строка 11); size увеличивается на 1 (строка 13), так как только что добавили элемент.

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

bool List::delete_element_by_number(int p) { if (head == nullptr) return 0;

else {

if (p < 0 || p > size) { // Если такого индекса нет

139

cout << "Неверно введен индекс\n"; return 0;

}

else {

if (p == 0) { // Если удаляем первый элемент

Node* del = head;

if (head->next != NULL) { /* Если остался не один элемент */

head = head->next;

//

 

Переприсваиваем

 

head

head->prev = NULL;

/* Новый первый

 

элемент

 

указывает на

 

0 */

}

 

if (head->next == NULL)

/* Если остался

 

один элемент

 

*/

head = NULL;

 

delete del;

 

}

else {

Node* t = head;

for (int i = 0; i < p; i++)

//Переходим к удаляемому элементу

t = t->next; Node* e = t->next;

//Указатель на элемент, стоящий после удаляемого

Node* y = t->prev;

// Указатель на элемент, стоящий до

удаляемого

 

delete t;

// Удаление

 

элемента

140

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