Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
2 / 2 / 0
Регистрация: 16.08.2020
Сообщений: 25

Списки и элементы

31.08.2020, 14:54. Показов 562. Ответов 9

Студворк — интернет-сервис помощи студентам
Здравствуйте, я изучаю С++ по книге Страуссрупа и сейчас разбираюсь со списками. Я написал следующий код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Node{
private:
    int number;
    Node* prev;
    Node* next;
public:
    Node(int x=0, Node* n=nullptr, Node* p=nullptr):
        number(x), next(n),prev(p){}
    Node* find(Node* rm,int i); // ищем узел
    Node* add(Node* nr); // добавляем новый
 
};
Node* Node::add(Node* nr){//дoбавляем nr после this
    if(this==nullptr) return nr;
    this->next=nr; //nr следует за this
    nr->prev=this;//this предшественник у nr
    return nr;}
 
Node* Node::find(Node* ws, int x){
    while(ws){
        cout << "Trying to find " << x << " in "<<ws->number << endl;
        if(ws->number==x){
            cout << "Here it is!" << endl;
            return ws;}
        ws=ws->next;}
    if(ws==nullptr) cout<< "error!" << endl;
}
 
int main(){
    int i=0;
    Node* mynodes=new Node(i);
    while(i<10){
        ++i;
        mynodes->add(new Node(i));
    }
    mynodes->find(mynodes, 7);
 
}
Как я думал сначала, он будет добавлять элемент в конец списка и возвращать указатель на него же, но вместо этого указатель каждый раз возвращается на mynodes(0) и каждый следующий элемент просто затирает добавленный ранее. В итоге я имею список из двух элементов, сколько бы раз не задействовал функцию add.
Сделать так, чтобы функция возвращала указатель на последний элемент списка, я так понимаю, не возможно? Всегда будет именно на
сам объект типа Node?
В сети я прочитал, что можно реализовать такой список добавив в класс новый член, который всегда обозначает стартовый элемент списка.
Этот метод вроде работает, но он не кажется изящным, есть ли какие-то иные решения?
Кроме того, сам Страуссруп делает это иначе, хотя я точно и не понимаю как, потому что приведенный в его книге код у меня не компилируется.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
31.08.2020, 14:54
Ответы с готовыми решениями:

Дан вектор, элементы которого списки из целых чисел.Заменить на NILL списки с суммой равной 0
Дан вектор, элементы которого списки из целых чисел.Заменить на NILL списки с суммой равной 0.

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

Списки. Удалить элементы с позиции n по m
Нужно удалить элементы с позиции n по m. Вот написал, но в этом месте выдает ошибку. cur = cur -&gt; pNext; Вот функция удаления. ...

9
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
31.08.2020, 15:04
Цитата Сообщение от markmarks Посмотреть сообщение
if(this==nullptr)
this НИКОГДА не может быть равно нулю.

И ко всему вам нужно еще раз прочитать раздел по которому вы пишете Список.
Узел и Список ето две разные сущности.
0
0 / 0 / 0
Регистрация: 23.02.2018
Сообщений: 77
31.08.2020, 15:07
Вот тебе пример как я реализовал класс.
создаешь 2 доп. переменные которые будут указывать на начало списка(HEAD) и конец списка(TAIL)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
template<typename T, typename T2, typename T3>
class List
{
public:
    List();
    ~List();
    void open_file(int index);                                  //Для чтения и записи данных в файл в txt формате
    void push_front(T name, T2 price, T3 quantity);             //добавить элемент в начало списка
    void push_insert(T name, T2 price, T3 quantity, int index); //добавить элемента по индексу (в середину)
    void push_back(T name, T2 price, T3 quantity);              //добавить элемент в конец списка
    void pop_front();                                           //Удалить первый элемент списка
    void pop_removeAt(int index);                               //Удалить элемент по индексу(из середены)
    void pop_back();                                            //Удалить элемент с конца списка
    void create_hand();                                         //Создание списка вручную
    void create_rand(string* arr);                              //Заполнение списка автоматом
    int search_list(boolean res);                               //Поиск элемента
    void clear();                                               //Удаляем список из дин. памяти
    int GetSize() { return Size; }                              //возвращает кол-во эл. в списке
    void print_next();                                          //Печать от 0 до Size
 
private:
    template<typename T, typename T2, typename T3>
    class Node                      //класс элемента
    {
    public:
        Node* pNext;                //Указатель на следующий элемент
        Node* pPrev;                //Указатель на предыдущий элемент
        T name;                     //Название товара
        T2 price;                   //Цена за единицу товара
        T3 quantity;                //Количество товара
                                    //конструктор для класса Node куда передаем данные и указатели на сл/пред элемент
        Node(T name = T(), T2 price = T2(), T3 quantity = T3(), Node* pNext = nullptr, Node* pPrev = nullptr)
        {
            this->name = name;
            this->price = price;
            this->quantity = quantity;
            this->pNext = pNext;
            this->pPrev = pPrev;
        }
    };
    int Size;                       //Для счета количества элементов
    Node<T, T2, T3>* head;          //Начало списка(указатель т.к. все элементы будут выделяться в дин. памяти)
    Node<T, T2, T3>* tail;          //Конец списка
};
А вот тебе реализация записи данных в конец списка. где указываются и начало списка и конец.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<typename T, typename T2, typename T3>                          //добавление элемента в конец списка
void List<T, T2, T3>::push_back(T name, T2 price, T3 quantity)
{
    Node<T, T2, T3>* temp = new Node<T, T2, T3>(name, price, quantity);
    temp->pNext = nullptr;
    if (tail == nullptr)                                                //проверка не пустой ли элемент
    {
        head = tail = temp;                                             //записываем данные в список
    }
    else
    {
        temp->pPrev = tail;         //Указываем, что предыдущим элементом списка относительно добавленного, будет последний элемент существующего списка
        tail->pNext = temp;         //в последнем элементе указателю на сл адрес  присваиваем вр. переменную
        tail = temp;                //присваиваем последнему элементу временныйую переменную
    }
    Size++;                         //+1 добавленный эемент
}
0
2 / 2 / 0
Регистрация: 16.08.2020
Сообщений: 25
31.08.2020, 15:19  [ТС]
Цитата Сообщение от SmallEvil Посмотреть сообщение
this НИКОГДА не может быть равно нулю.
На первый взгляд так и есть, но этот фрагмент взят собственно из книги(Программирование принципы и практика с использованием С++, Страуссруп глава 17.10 стр 680) вероятно, он служит для предупреждения каких-либо специфических ошибок или же просто для наглядности.
Цитата Сообщение от SmallEvil Посмотреть сообщение
зел и Список ето две разные сущности.
это понимаю) указатель на список указывает на объект класса, который включает узлы, другой объект - другие узлы
я не понимаю как мне возвращать указатель на узел и надо ли вообще так делать.
0
0 / 0 / 0
Регистрация: 23.02.2018
Сообщений: 77
31.08.2020, 15:29
Цитата Сообщение от markmarks Посмотреть сообщение
как мне возвращать указатель на узел
Я вот не понял на какой узел ты хочешь возвращать указатель.
Вот есть у тебя список заполненный элементами. в твоем списке могут быть указатели на первый и последний элемент списка.
Если ты хочешь обратиться к конкретному элементу списка,допустим по индексу(номеру элемента в списке) то тебе требуется написать перегрузку к оператору[]
0
2 / 2 / 0
Регистрация: 16.08.2020
Сообщений: 25
31.08.2020, 15:34  [ТС]
Цитата Сообщение от energ1 Посмотреть сообщение
void push_front(T name, T2 price, T3 quantity); //добавить элемент в начало списка
void push_insert(T name, T2 price, T3 quantity, int index); //добавить элемента по индексу (в середину)
Покажи, пожалуйста, эти две функции
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
31.08.2020, 15:39
В книге могут быть примеры с ошибками лишь при условии присутствия заданий их найти. (в конце главы)

На счет узлов и списка.
Список - лишь контейнер для узлов. Поэтому возврат указателя на узел явное следование из структуры списка.

C++
1
2
3
4
5
6
7
template<T> class Node 
{
public:
     T value;
     T* next;
     T* prev;
}
на этом самый простой узел для Списка закачивается.
C++
1
2
3
4
5
6
7
8
9
10
template<T> class MyList
{
    private:
             Node<T> * head;
             Node<T> * tail;
             Node<T> * current;
             int              count; // количество узлов
   public:
           // делаем методы   void pop_back(); и прочие. 
}
energ1, для вашего кода
C++
1
2
3
4
5
6
template<class T, class T2, class T3> struct good{
   
       T name;                     //Название товара
        T2 price;                   //Цена за единицу товара
        T3 quantity;                //Количество товара
}
MyList<good> goods; // список с вашыми товарами.
1
2 / 2 / 0
Регистрация: 16.08.2020
Сообщений: 25
31.08.2020, 15:43  [ТС]
Цитата Сообщение от energ1 Посмотреть сообщение
Я вот не понял на какой узел ты хочешь возвращать указатель.
Вот есть у тебя список заполненный элементами. в твоем списке могут быть указатели на первый и последний элемент списка.
Добавляю элемент в конец списка - возвращаю указатель на него же. Можно это делать если хранить отдельно указатели на первый и последний элемент - это единственный вариант?
Цитата Сообщение от energ1 Посмотреть сообщение
Если ты хочешь обратиться к конкретному элементу списка,допустим по индексу(номеру элемента в списке) то тебе требуется написать перегрузку к оператору[]
Я могу просто найти его по значению value, а не по индексу, для добавления в середину не нужна перегрузка, это должно выглядеть примерно вот так:
C++
1
2
3
4
5
6
7
8
9
10
11
Node* Node::insert(Node *n)
{
    if (n == nullptr)
        return this;
    n->next = this;
    if (prev)
        prev->next = n;
    n->prev = prev;
    prev = n;
    return n;
}
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
31.08.2020, 15:53
Цитата Сообщение от SmallEvil Посмотреть сообщение
C++
1
2
3
4
5
6
template<T> class Node 
{
public:
 T value;
 T* next;
 T* prev;
}
опечатался

C++
1
2
3
4
5
6
template<T> class Node 
{
public:
 T value;
 Node* next;
 Node* prev;
}[/quote]
0
0 / 0 / 0
Регистрация: 23.02.2018
Сообщений: 77
31.08.2020, 15:54
Цитата Сообщение от markmarks Посмотреть сообщение
Можно это делать если хранить отдельно указатели на первый и последний элемент - это единственный вариант?
Если у тебя не будет указателя на конец списка то для записи тебе потребуется искать элемент который указывает что за ним стоит nullptr, т.е. тебе придется пробежаться по всему списку. это с вариантом если список не кольцевой.
Если список кольцевой( первый элемент указывает на последний и наоборот. то тут у тебя куда запись сделается?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<typename T, typename T2, typename T3>                          //добавление элемента в начало списка
void List<T, T2, T3>::push_front(T name, T2 price, T3 quantity)
{
    Node<T, T2, T3>* temp = new Node<T, T2, T3>(name, price, quantity); //создаем элемент и записываем туда наши данные
    if (head == nullptr)                                                //Если список пуст
    {
        head = tail = temp;                                             //записываем данные в список
        Size++;
    }
    else
    {
        temp->pNext = head;                                             //следующий элемент после созданного указывает на первый имеющийся
        head->pPrev = temp;                                             //предыдущий элемент от текущего первого -> созданный
        head = temp;                                                    //первый элемент теперь созданный
        Size++;
    }
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
template<typename T, typename T2, typename T3>                          //добавить элемента по индексу (в середену)
void List<T, T2, T3>::push_insert(T name, T2 price, T3 quantity, int index)
{
    int tempn = 0;
    if (index == 0 || index == 1)                                       //Если index 0 или 1 записываем в начало списка
    {
        push_front(name, price, quantity);
    }
    else if ((Size == 0) && index > 0)                                  //Если нет элементов в списке и индекс указывает на несуществующий элемент то записываем с нуля
    {
        push_back(name, price, quantity);
    }
    else if (index > Size)                                              //Если index указывает на несуществующий элемент то записываем в конец списка
    {
        push_back(name, price, quantity);
    }
    else if (Size / 2 >= index)                                         //Если index в первой половине списка то ищем элемент сначала
    {
        Node<T, T2, T3>* temp = this->head;                             //создаем временную переменную и присваиваем значение head
        for (int i = 0; i < index - 1; i++)                             //цикл поиска индекса перед которым хотим поместить даные
        {
            temp = temp->pNext;
        }
        Node<T, T2, T3>* newNode = new Node<T, T2, T3>(name, price, quantity);
        newNode->pNext = temp;
        newNode->pPrev = temp->pPrev;
        temp->pPrev->pNext = newNode;
        temp->pPrev = newNode;
        Size++;
    }
    else                                                            //Иначе  ищем элемент с конца списка
    {
        Node<T, T2, T3>* temp = this->tail;                         //создаем временный указатель и присваиваем значение head
        for (int i = Size; i > index; i--)                                  //цикл поиска индекса перед которым хотим поместить данные
        {
            temp = temp->pPrev;
        }
        Node<T, T2, T3>* newNode = new Node<T, T2, T3>(name, price, quantity);
        newNode->pNext = temp;                      //указываем для нового элемента следующий за ним
        newNode->pPrev = temp->pPrev;                   //указываем для нового элемента предыдущий
        temp->pPrev->pNext = newNode;                   //указываем для элем стоявшего перед temp следующий новый
        temp->pPrev = newNode;                      //указываем для элемента temp 
        Size++;
    }
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
31.08.2020, 15:54

Списки. Удалить отрицательные элементы
Задание звучит так: Организовать ввод и формирование списка вещественных чисел с проверкой. Сформировать список положительных элементов...

Списки, атомы, элементы - найти t
Помогите решить задачу: Написать выражение, выдающее t если в первом заданном списке элемент с указанным номером является числом, во...

Списки, списки, списки. не все так просто
Написать функцию, которая принимает 2 списка, содержащие одинаковое число строк, затем изменяет списки сопоставляя строки, занимающие...

Списки: удалить из списка L все элементы E
Дана такая задача. Составить программу, которая удаляет из списка L все элементы E, если такие есть. Вот я решил как...

Списки: удалить все четные элементы
Написать программу, которая из последовательность целых чисел формирует односвязный спи- сок. Длина последовательности может быть...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
Транслитерация текста с кириллицы на латиницу (вариант №2)
Maks 13.11.2026
Обновленная версия ранее созданной обработки. Добавлено: - Проверка исходного текста на кириллицу, через обращение к стандартной функции "ТолькоКириллицаВСтроке" из общего модуля. . .
Часы с термометром и праздничным календарем
yariko 12.11.2026
Сегодня мы рассмотрим как можно сделать отличные многофункциональные часы. Итак, поставим конкретную задачу: разработать часы с календарем, двумя термодатчиками, выводом поздравительных сообщений. . .
Транслитерация текста с кириллицы на латиницу (вариант №1)
Maks 11.11.2026
Решил облегчить жизнь себе и коллегам админам при создании электронных почтовых ящиков для пользователей, в результате написал обработку "Транслитерация текста" с кириллицы на латиницу, а в ней. . .
Книги по геймдизайну, левел-дизайну, игровым механикам и проектированию игрового опыта
8Observer8 08.11.2026
Содержание блога | English Version 1. 2003 - 06 - Designing Virtual Worlds (1st Edition) Автор: Richard A. Bartle | Объем: 768 стр. Ссылки: Amazon . . .
Родители токсичные абьюзеры по отношению к своим детям ругают их оскорбляют не любят
zorxor 08.11.2026
Жить в атмосфере постоянных оскорблений, критики и холодности со стороны родителей — это тяжелое и болезненное испытание, которое оставляет глубокие эмоциональные раны. Токсичное и абьюзивное. . .
Как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Ответ от Джемени ИИ.
zorxor 08.11.2026
Джемени, как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Многие люди, возвращаясь домой, сразу переодеваются в максимально свободную одежду или вовсе предпочитают. . .
Паттерн очереди действий/команд (Action / Command Queue). Система очереди действий и кат-сцен с SDL3 Callbacks, cglm и OpenGL
8Observer8 07.11.2026
Содержание блога | English Version Руководство для начинающих по реализации паттерна очереди действий/ команд (Action / Command Queue) на C++ (C++20) с использованием официального SDL3 Callbacks. . .
Проверка полного ФИО в типовом справочнике
Maks 07.11.2026
Решение реализовано в конфигурации КА2, на примере справочника "КонтактныеЛицаПартнеров". Задача: Запрет инициалов. Не допускаеть использование сокращений вида "И. И. ", "И. И. ", "И И" и. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru