Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.08.2015, 15:02   #1
MrQuestion
Пользователь
 
Регистрация: 16.08.2015
Сообщений: 40
По умолчанию Серьезные проблемы с связным списком. с++

Код:
#include <iostream>
using namespace std;

class spisok // Создали класс
{
      public:
             int a,b; // Создали полезные данные
             
             spisok* next; // Создали указатель на следующий объект в списке
};

spisok* head = 0; // Создали начало списка, ни на что не указывающее.

void addelement()
{
     spisok* current = new spisok; // Здесь создали новый объект.
     
     cin >> current->a;
     cin >> current->b; // Забили поля объекта полезными данными.
     
     current->next = 0; // Забили в указатель текущего объекта нуль. Указатель текущего объекта ни на что не указывает.
     
     if(head == 0) // Если в списке нет адреса какого либо объекта...
     {
             head = current; // ... верх списка указывает на текущий объект.
     }
     
     else // Если head на что то указывает
     {
         spisok* temp = head; // Создаем новый указатель, который указывает на начало списка. Т.е. на нуль. 
         while(temp->next != 0) temp = temp->next;
            // Пока указатель next указателя temp не указывает на нуль, temp указывает на  temp->next.
                Но чему изначально равен temp->next?
         temp->next=current; // Указатель next указателя temp указывает на текущий объект.
                     Каким образом осуществлен проход по списку?
     }
}
     
int main()
{
    int value = 0;
    while(value<5)
    {
              addelement();
              value++;
    };
    
    spisok* current = head; // Создали указатель на начало списка. Теперь текущий объект указывает на head, 
                                а т.к. head ни на что не указывает, то и current ни на что не указывает.
    while(current!=0) // Пока текущий объект не указывает на нуль, выполнять цикл. Но текущий объект как раз указывает на нуль.
    {
            cout << current->a << " " << current->b << endl;
            current = current->next;
    }            
    system("pause");
    return 0;
}
Здравствуйте. Никак не могу разобраться со связным списком. Все основные вопросы в моих же собственных комментариях к программе. Основной интерес вызывает тот кусок, что идет после else. Буду благодарен за помощь и подробные объяснения.

Последний раз редактировалось Stilet; 17.08.2015 в 07:14.
MrQuestion вне форума Ответить с цитированием
Старый 16.08.2015, 15:44   #2
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,645
По умолчанию

Цитата:
Код:
while(temp->next != 0) temp = temp->next;
 // Пока указатель next указателя temp не указывает на нуль, temp указывает на  temp->next. 
Но чему изначально равен temp->next?
если
temp = head
значит
temp->next = head->next
то есть первоначально
temp->next = указатель на второй добавленный элемент списка (или на ноль, если список состоит только из одной головы)

Цитата:
Код:
spisok* current = head; 
// Создали указатель на начало списка. Теперь текущий объект указывает на head, а т.к. head 
ни на что не указывает, то и current ни на что не указывает.
глобальный head был изменен в ранее идущей ф-ии addelement и он указывает на самый первый new spisok, т.е. на начало, значит и current первоначально указывает туда же

Последний раз редактировалось Stilet; 16.08.2015 в 16:33.
eoln вне форума Ответить с цитированием
Старый 16.08.2015, 16:33   #3
MrQuestion
Пользователь
 
Регистрация: 16.08.2015
Сообщений: 40
По умолчанию

Цитата:
если
temp = head
значит
temp->next = head->next
то есть первоначально
temp->next = указатель на второй добавленный элемент списка (или на ноль, если список состоит только из одной головы)
Так, если head->next == temp-> next, то temp->next == current->next, ведь и current == head. И все эти указатели указывают в никуда. На нуль.

Да и вообще. Если взять другой пример. Функцию добавления в начало списка.

Код:
 spisok head = 0;

           void add(spisok* current)
{
           current->next = head;
           head = current;
}
И что же получается? current->next указывает на head. Потом head указывает на current. И получается, что current->next == current. Т.е. это указатель не на следующий элемент, а сам на себя.

Последний раз редактировалось MrQuestion; 16.08.2015 в 17:14.
MrQuestion вне форума Ответить с цитированием
Старый 16.08.2015, 17:20   #4
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,645
По умолчанию

Советую взять отладчик и посмотреть как изменяются адреса.
head - фиксированные для всей программы
current - каждый раз новый при входе в функцию, но от начала ф-ии до её конца не меняется
temp - многократно изменяется в циклах while
Код:
spisok* current = new spisok;
...
     if(head == 0) 
     {
             head = current;
Сначала в current записывается какой-то адрес, например, 12345600.
Потом это же присваивается и глобальной переменной head. Больше head не меняется и всегда равен этому 12345600

Переменная temp сначала = head, то есть 12345600
Затем в цикле:
1) если у temp (которая сейчас равна head=12345600) есть последователи (то есть если temp->next != 0), то temp = temp->next = адресу последователя, например, 12345611;
2) если у temp (которая сейчас равна head->next=12345611) есть ещё последователи (то есть если temp->next != 0), то temp = temp->next = адресу следуещего последователя, например, 12345622;
3) если у temp (которая сейчас равна head->next->next=12345622) есть ещё последователи (то есть если temp->next != 0), то temp = temp->next = адресу следуещего последователя, например, 12345633;
и т.д. пока последователи не кончатся.
Как только кончаются последователи в цепочке, то добавляем ещё одного нового к самому последнему
Код:
temp->next=current;
В прошлом посте я подчеркнул слово первоначально

Последний раз редактировалось eoln; 16.08.2015 в 17:23.
eoln вне форума Ответить с цитированием
Старый 16.08.2015, 17:52   #5
MrQuestion
Пользователь
 
Регистрация: 16.08.2015
Сообщений: 40
По умолчанию

Цитата:
1) если у temp (которая сейчас равна head=12345600) есть последователи (то есть если temp->next != 0), то temp = temp->next = адресу последователя, например, 12345611;
С каждым постом картина проясняется, но не до конца ясно вот что. В момент, когда head и temp указывают на один адрес, в вашем примере на 12345600, в этот момент head->next = temp->next. И вот это что то невообразимое.

Цитата:
то temp = temp->next = адресу последователя, например, 12345611
temp->next == head->next.

Получается, запись temp = temp->next аналогична записи temp = head->next. Но что за адрес хранится в head->next? Там current->next или, вообще, что?

Каким образом temp->next получает адрес следующего элемента?

Последний раз редактировалось MrQuestion; 16.08.2015 в 17:56.
MrQuestion вне форума Ответить с цитированием
Старый 16.08.2015, 18:20   #6
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,645
По умолчанию

Цитата:
В момент, когда head и temp указывают на один адрес, в вашем примере на 12345600, в этот момент head->next = temp->next. И вот это что то невообразимое.
А что тут странного? head и temp первоначально при первой итерации цикла указывают на одно и то же.
Допустим, head- это телефонная книга, temp - это ксерокопия этой книги. И head и temp будут указывать на одних и тех же абонентов.

Цитата:
temp = temp->next аналогична записи temp = head->next
только для первой итерации цикла while
для второй так:
Код:
temp = temp->next аналогична записи temp = head->next->next
для третьей
Код:
temp = temp->next аналогична записи temp = head->next->next->next
для четвёртой
Код:
temp = temp->next аналогична записи temp = head->next->next->next->next
и так далее
и вот чтобы не писать для каждой итерации всё больше и больше кода, на каждом проходе делают замену. Заменяют temp= temp->next. В итоге получаем краткую запись как в программе
Цитата:
Но что за адрес хранится в head->next?
Всегда указатель на второй элемент (или ноль, если его нет)
Цитата:
Каким образом temp->next получает адрес следующего элемента?
temp->next принимает значение адреса 2-го, 3-го, 4-го и т,д, элемента. Это просто некий счётчик в цикле while

Последний раз редактировалось eoln; 16.08.2015 в 18:24.
eoln вне форума Ответить с цитированием
Старый 16.08.2015, 19:07   #7
MrQuestion
Пользователь
 
Регистрация: 16.08.2015
Сообщений: 40
По умолчанию

Цитата:
Всегда указатель на второй элемент (или ноль, если его нет)
Т.е. при первой итерации в temp->next и head->next хранится адрес current?

И в присвоении head = current происходит не присвоение head->next = current->next, а head->next = current?

Если не трудно, вы могли бы описать схему и поочередность присвоений? Что к чему конкретно присваивается и что на что указывает. Я не понимаю.

Цитата:
1) если у temp (которая сейчас равна head=12345600) есть последователи (то есть если temp->next != 0), то temp = temp->next = адресу последователя, например, 12345611;
Если адрес head = 12345600, а head->next == адрес второго элемента (т.е. currennt( который тоже 12345600) то temp=temp->next то же самое, что 12345600 == 12345600. Адрес не двигается с места. Это замкнутый круг.

Последний раз редактировалось MrQuestion; 16.08.2015 в 19:20.
MrQuestion вне форума Ответить с цитированием
Старый 16.08.2015, 23:28   #8
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,645
По умолчанию

Цитата:
Сообщение от MrQuestion Посмотреть сообщение
Т.е. при первой итерации в temp->next и head->next хранится адрес current?
И в присвоении head = current происходит не присвоение head->next = current->next, а head->next = current?
Итерации цикла, я везде писал про цикл, про цикл после else
current вообще записывается в самом конце процедуры, Это новый указатель на элемент. До самого конца на него ничего не указывает и ничего с ним не связано, и сам он ни с чем не связан.
Тут вообще нет понимания что такое указатель. head/current/temp - это не объекты класса, это просто числа, набор цифр, адрес по которому можно найти объект. Что-то типо GPS-координат.
Если написано head = current, то это значит что
head->next = current->next
head->a= current->a
head->b= current->b
Но опять в 6-ой раз скажу, что это происходит лишь однажды

head=current выполняется всего лишь один раз за всё время когда список вообще пуст. Больше эта строка не выполняется никогда. В любое другое время в current уже другой адрес.

Цитата:
Если адрес head = 12345600, а head->next == адрес второго элемента (т.е. currennt( который тоже 12345600)
Нет и ещё раз нет. current и head совпадают лишь однажды в самом начале, в другие моменты времени current имеет совершенно другие значения. В первый раз ни до каких temp, ни до каких вторых элементов не доходит, выполняется только это
Код:
if(head == 0) 
     {
             head = current; 
     }
Цитата:
описать схему и поочередность присвоений?
Я уже привёл краткую схему, подробности в учебниках.

Цитата:
Я не понимаю.
Объяснения в книжках. Тут только конкретные вопросы.
И ещё раз советую включить пошаговую отладку и посмотреть какие значения принимают head/current/temp. Это всё после прочтения о том как устроены динамические списки.
eoln вне форума Ответить с цитированием
Старый 17.08.2015, 13:32   #9
MrQuestion
Пользователь
 
Регистрация: 16.08.2015
Сообщений: 40
По умолчанию

Да! Я понял! Я понял, как они работают! Воспользовался отладочной печатью и всё понял! Ха-ха-ха! Нужно было включать мозги с самого начала! Спасибо eoln! Большое спасибо!
MrQuestion вне форума Ответить с цитированием
Старый 17.08.2015, 19:47   #10
Алексей_2012
t45t
Участник клуба
 
Аватар для Алексей_2012
 
Регистрация: 20.03.2012
Сообщений: 1,849
По умолчанию

Если автор разобрался, то теперь вопросы у меня..., естественно по теме)

Здесь в качестве списка создаются связанные экземпляры класса? Просто мы для создания связанного списка писали примерно вот так:

Код:
struct spisok
{
int a,b;
spisok *next;
}

spisok *head;
Если да, то исходные списки продолжают существовать как отдельные объекты?

Плюс вопрос по коду из первого поста:

Разве при выводе списка не нужно писать так:

Код:
while (!head)
?
from dark to light)
Алексей_2012 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Стековый калькулятор, чистый Си, реализовать его со связным списком anna27 Помощь студентам 4 09.05.2013 23:31
проблемы с Char-списком Caged Помощь студентам 0 25.12.2011 18:02
Операции над многочленами, заданными списком свомх коэффициентовОперации над многочленами, заданными списком свомх коэффициентов lelicki_bolicki Общие вопросы по Java, Java SE, Kotlin 1 06.12.2011 22:07
проблемы со связным списком с++ (Borland) adwaer Помощь студентам 0 15.04.2009 16:23
проблемы со связным списком с++ (Borland) adwaer Помощь студентам 0 15.04.2009 16:22