Advertisement
Ver5us

C++ Linear List example

May 23rd, 2019
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 18.72 KB | None | 0 0
  1. #include "pch.h"
  2. #include <iostream>
  3.  
  4. using namespace std;
  5.  
  6. /*------------------------------------------------------------------- ЛИНЕЙНЫЙ СПИСОК ---------------------------------------------------------------*/
  7.  
  8. /*
  9. Тип данных для однонаправленного списка целых чисел LinearList
  10. @data - значение целого числа в элементе списка
  11. @next - указатель на следующий элемент списка (nullptr, если это последний элемент)
  12. */
  13. struct LinearList
  14. {
  15.     int data;                       // поле данных
  16.     struct LinearList* next;        // указатель на следующий элемент
  17. };
  18.  
  19.  
  20.  
  21. /*
  22. Операции над однонаправленным линейным списком LinearList -----------------------
  23. В качестве одного из аргументов передается LinearList**, т.е. указатель на указатель на наш тип данных - вроде как (LinearList*)*,
  24. это необходимо для того, чтобы в наших функциях можно было менять исходный список.
  25. Поскольку память под элементы списка выделяется динамически (new), мы оперируем указателями на эти области памяти (LinearList*).
  26. Чтобы менять исходные данные, нам нужно передавать их в функцию по адресу (&), иначе будут меняться копии данных, создаваемые функцией
  27. Чтобы получить адрес указателя нам нужно использовать в качестве типа данных указатель на этот указатель... отсюда страшный LinearList**
  28. Далее в коде мы просто создадим наш список как указатель на первый элемент (LinearList* list) и будем передавать в функции адрес этого списка (func(&list)),
  29. чтобы функции работали с исходным списком, а не с копиями.
  30. В качестве альтернативного решения нам потребовалось бы возвращать в функциях значения ссылок на обновленный список и обновлять list результатами их выполнения (list = func(list))
  31. */
  32.  
  33. // Создание линейного списка root и инициализация его значениями на основе массива values длины length
  34. void createLinearList(LinearList** root, int* values, const int length)
  35. {
  36.     if (length > 0)                             // есть смысл инициализировать список толькое если передаваемая длина массива length ненулевая
  37.     {
  38.         *root = new LinearList;                 // разыменованием получаем указатель на тип LinearList (т.е. LinearList*), который нужен для динамического выделения памяти (new)
  39.         (*root)->data = values[0];              // инициализируем только что созданный элемент, указывая первый элемент массива в качестве параметра @data
  40.         (*root)->next = nullptr;                //...и пустой указатель (nullptr aka NULL) в качестве параметра @next. Т.е. по факту у нас сейчас список из одного элемента.
  41.  
  42.         if (length > 1)                         // если длина передаваемого массива length всё же больше 1 элемента, можем дополнить список оставшимися в массиве значениями
  43.         {
  44.             LinearList* e = *root;              // создаем временную переменную e для движения по списку от положения root
  45.             for (int i = 1; i < length; i++)    // в цикле по остатку массива values...
  46.             {
  47.                 e->next = new LinearList;       // для каждого обрабатываемого элемента массива добавляем в конец списка новый элемент
  48.                 e = e->next;                    // сдвигаем указатель (временную переменную) на новый элемент
  49.                 e->data = values[i];            // инициализируем этот элемент по аналогии с первым, но по порядку членов массива
  50.                 e->next = nullptr;              // последний элемент всегда будет указывать на пустой указатель nullptr (aka NULL)
  51.             }
  52.         }
  53.     }
  54. }
  55.  
  56. // Последовательный вывод содержимого линейного списка root (здесь нам не надо менять исходный список, поэтому можно обойтись простым указателем на первый элемент списка LinearList*)
  57. void printLinearList(LinearList* root)
  58. {
  59.     cout << endl << "Линейный однонаправленный список:" << endl;
  60.     LinearList* e = root;                       // создаем временную переменную e для движения по списку от положения root
  61.     while (e != nullptr)                        // пока не достигнут конец списка, т.е. пока временная переменная e не приняла значение равное пустому указателю nullptr
  62.     {
  63.         cout << "[" << e->data << "] -> ";      // выводим данные из узла списка @data
  64.         e = e->next;                            // ...и переходим к следующему узлу, сдвигая временный указатель e дальше по списку.
  65.     }
  66.     cout << "NULL" << endl;                     // конец списка у нас всегда указывает на nullptr (NULL)
  67. }
  68.  
  69. // Добавление нового элемента линейного списка со значением @data = value ПЕРЕД указанным element
  70. void addLinearListElementBefore(LinearList** element, const int value)
  71. {
  72.     LinearList* e = new LinearList;             // Создаем новый узел
  73.     e->data = value;                            // инициализируем его данные @data переданным в функцию значением value
  74.     e->next = *element;                         // в качестве следующего элемента передаем исходный список (исходный список продолжает наш новый элемент)
  75.     *element = e;                               // ...а сам новый элемент становится новым началом списка
  76. }
  77.  
  78. // Добавление нового элемента линейного списка со значением @data = value ПОСЛЕ указанного element
  79. void addLinearListElementAfter(LinearList** element, const int value)
  80. {
  81.     LinearList* tmp = new LinearList;           // Создаем новый узел
  82.     tmp->data = value;                          // инициализируем его данные @data переданным в функцию значением value
  83.  
  84.     LinearList* e = (*element)->next;           // создаем временный узел для обмена ссылками и записываем в него указатель на элемент, следующий за переданным в функцию узлом element
  85.     (*element)->next = tmp;                     // вместо сохраненного следующего подставляем только что созданный узел tmp
  86.     tmp->next = e;                              // а сам tmp будет ссылаться на сохраненный ранее узел, который теперь смещается дальше по списку (element -> tmp -> e -> ...)
  87. }
  88.  
  89. // Добавление нового элемента со значением @data = value в начало списка root
  90. void addLinearListElementHead(LinearList** root, const int value)
  91. {
  92.     addLinearListElementBefore(&(*root), value); // по сути это функция обертка - мы добавляем новый элемент перед элементом root (ссылкой на первый элемент списка)
  93. }
  94.  
  95. // Добавление нового элемента со значением @data = value в конец списка root
  96. void addLinearListElementEnd(LinearList** root, int value)
  97. {
  98.     LinearList* e = *root;                      // создаем временную переменную e для движения по списку от положения root
  99.  
  100.     while (e->next != nullptr)                  // движемся по списку от узла к узлу пока на достигнем последнего узла (у которого ссылка на следующий элемент будет NULL)
  101.     {
  102.         e = e->next;                            // переход к следующему узлу...
  103.     }
  104.     addLinearListElementAfter(&e, value);       // добавляем новый элемент ПОСЛЕ последнего найденного узла e (последний узел списка) через описанную ранее функцию
  105. }
  106.  
  107. // Удаление из списка root элемента element (при совпадении адреса ссылки на element с одним из элементов списка root)
  108. void removeLinearListElement(LinearList** root, LinearList* element)
  109. {
  110.     if (*root == nullptr) return;               // если список и так пуст, удалять особо нечего, поэтому просто уходим отсюда
  111.  
  112.     LinearList* a = *root;                      // создаем временную переменную a для движения по списку от положения root
  113.     if (a == element)                           // если совпадение пришлось на первый же элемент списка - это особый случай...
  114.     {
  115.         *root = a->next;                        // смещаем указатель на начало массива дальше (там вполне может оказаться NULL - ничего страшного)
  116.         delete a;                               // чистим память по указанному адресу a
  117.         return;                                 // и прекращаем дальнейший обход
  118.     }
  119.    
  120.     a = *root;                                  // Если с первым элементом не прокатило, то начинаем обход списка с начала, запоминаем a, после которого возможно будет удален элемент b
  121.     LinearList* b = (*root)->next;              // создаем указатель b на следующий элемент - удалять найденный элемент будем по этому же указателю
  122.     while (b != nullptr)                        // пока мы не достигли конца списка (a - последний элемент, следующий за ним b - пустой)
  123.     {
  124.         if (b == element)                       // проверяем, нужно ли удалять следующий элемент (по совпадению адресов памяти)
  125.         {
  126.             a->next = b->next;                  // если да - записываем в следующий за a узел значение узла, следующего за b (как бы исключем b из нашего списка)
  127.             delete b;                           // и очищаем выделенную под удаленный узел память с последующим выходом...
  128.             return;
  129.         }
  130.         a = b;                                  // ...если совпадения нет - смещаем наши указатели a и b дальше по списку
  131.         b = b->next;
  132.     }
  133. }
  134.  
  135. // Удаление первого элемента списка root (смещение корневой ссылки дальше по списку)
  136. void removeLinearListHead(LinearList** root)
  137. {
  138.     removeLinearListElement(&(*root), *root);   // передаем в описанную ранее функцию список root (по адресу) и адрес указателя на первый элемент (т.е. то, что будем удалять)
  139. }
  140.  
  141. // Удаление последнего элемента списка root
  142. void removeLinearListEnd(LinearList** root)
  143. {
  144.     LinearList* a = *root;                 
  145.     LinearList* b = (*root)->next;
  146.  
  147.     if (b == nullptr)                           // если в списке только один элемент, сносим его нашей функцией (через указатель на первый элемент)
  148.     {
  149.         removeLinearListElement(&(*root), *root);
  150.         return;
  151.     }
  152.  
  153.     while (b->next != nullptr)                  // иначе движемся по списку по аналогии с предыдущей функцией до самого конца (a - предпоследний элемент, b - последний)
  154.     {
  155.         a = b;
  156.         b = b->next;
  157.     }
  158.  
  159.     delete b;                                   // удаляем последний элемент b
  160.     a->next = nullptr;                          // перезаписываем у предпоследнего узла a ссылку на следующий элемент, чтобы она указывала не на удаленный b, а на пустой указатель NULL
  161. }
  162.  
  163. // Очищаем список от элементов
  164. void clearLinearList(LinearList** root)
  165. {
  166.     while (*root != nullptr)                    // пока список не опустеет
  167.     {
  168.         removeLinearListHead(&(*root));         // удаляем элемент из начала и смещаем список дальше.
  169.     }
  170. }
  171.  
  172.  
  173.  
  174. //-------------------------------------------------------------------------------//
  175. // Задача 1 лабораторной (по варианту 1)
  176. //-------------------------------------------------------------------------------//
  177. void operateLinearList(LinearList* root)
  178. {
  179.     cout << endl;
  180.     cout << "------------------------------------------------------" << endl;
  181.     cout << " Определение среднего арифметического значения элементов списка, кратных 4: " << endl;
  182.     cout << "------------------------------------------------------" << endl;
  183.  
  184.     int num = 0;                                // количество найденных элементов кратных 4
  185.     int sum = 0;                                // сумма найденных элементов кратных 4
  186.     LinearList* e = root;                       // создаем временную переменную e для движения по списку от положения root
  187.  
  188.     cout << "Числа кратные 4:" << endl;
  189.     while (e != nullptr)                        // пока не дошли до конца списка
  190.     {
  191.         if (e->data % 4 == 0)                   // проверяем кратность значения, хранящегося в @data текущего узла е
  192.         {
  193.             cout << e->data << endl;
  194.             sum += e->data;                     // если значение кратно 4, плюсуем его к сумме sum
  195.             num++;                              // и увеличиваем число найденных элементов num на 1
  196.         }
  197.         e = e->next;                            // переходим к следующему доступному элементу по указателю @next
  198.     }
  199.  
  200.     if (num > 0)                                // если в результате обхода списка что-то нашлось, значит можно посчитать среднее арифметическое всех найденных элементов
  201.     {
  202.         cout << "Среднее арифметическое = " << (float)sum / num << endl;
  203.     }
  204.     else                                        // иначе считать особо нечего, не делить же 0 на 0...
  205.     {
  206.         cout << "Чисел удовлетворяющим условиям задачи в списке не найдено" << endl;
  207.     }
  208. }
  209.  
  210.  
  211.  
  212. int main()
  213. {
  214.     setlocale(LC_ALL, "Russian");
  215.  
  216.     const int default_length = 5;                               // длина инициализационного массива
  217.     int default_data[default_length] = { 4, 7, 13, 17, 44 };    // инициализационный массив значений для инициализации структур
  218.  
  219.     LinearList* list = nullptr;                 // переменная для хранения указателя на линейный однонаправленный список
  220.  
  221.     cout << "------------------------------------------------------" << endl;
  222.     cout << " Создание линейного однонаправленного списка: " << endl;
  223.     cout << "------------------------------------------------------" << endl;
  224.     createLinearList(&list, default_data, default_length);
  225.     printLinearList(list);
  226.  
  227.     cout << endl;
  228.     cout << "------------------------------------------------------" << endl;
  229.     cout << " Добавление элемента в конец списка: " << endl;
  230.     cout << "------------------------------------------------------" << endl;
  231.  
  232.     int ListData = 0;
  233.     cout << "Введите целое число: ";
  234.     cin >> ListData;                            // записываем введенное число в переменную
  235.     addLinearListElementEnd(&list, ListData);
  236.     printLinearList(list);
  237.  
  238.     cout << endl;
  239.     cout << "------------------------------------------------------" << endl;
  240.     cout << " Добавление элемента в начало списка: " << endl;
  241.     cout << "------------------------------------------------------" << endl;
  242.  
  243.     cout << "Введите целое число: ";
  244.     cin >> ListData;                            // записываем введенное число в переменную
  245.     addLinearListElementHead(&list, ListData);
  246.     printLinearList(list);
  247.  
  248.     cout << endl;
  249.     cout << "------------------------------------------------------" << endl;
  250.     cout << " Удаление первого элемента списка: " << endl;
  251.     cout << "------------------------------------------------------" << endl;
  252.     removeLinearListHead(&list);
  253.     printLinearList(list);
  254.  
  255.     cout << endl;
  256.     cout << "------------------------------------------------------" << endl;
  257.     cout << " Удаление последнего элемента списка: " << endl;
  258.     cout << "------------------------------------------------------" << endl;
  259.     removeLinearListEnd(&list);
  260.     printLinearList(list);
  261.  
  262.     // задание лабораторной по варианту 1
  263.     operateLinearList(list);
  264.  
  265.     cout << endl;
  266.     cout << "------------------------------------------------------" << endl;
  267.     cout << " УДАЛЕНИЕ всего списка: " << endl;
  268.     cout << "------------------------------------------------------" << endl;
  269.  
  270.     clearLinearList(&list);
  271.     printLinearList(list);
  272.  
  273.     return 0;
  274. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement