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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 18.04.2011, 17:01   #1
Вадим Мошев

Старожил
 
Аватар для Вадим Мошев
 
Регистрация: 12.11.2010
Сообщений: 8,568
По умолчанию

Здравствуйте.

Мне уже должно быть стыдно задавать такие вопросы, тем не менее, разобраться я с этим не могу.

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

Пишу программу на Delphi 7.0, однако решил список отлаживать на Turbo Pascal 7.0.

По идее программы, список должен хранить в качестве информационной части записи, поля которых имеют различные типы, но, опять-таки, для тренировки над списком я решил просто хранить в нём числа типа byte.

Наработки (если их так можно назвать) у меня, конечно, есть, я их опубликую, но прежде - несколько слов ходе реализации этой структуры.

Существует несколько способов реализации списков (например, с использованием средств ООП), однако я решил не заморачиваться и реализовал свой список через простые записи:

Код:
type TNode = ^Node;

        Node = Record
                  data: byte;
                  next: ^Tnode;
               end;
Как видно, список будет реализован простой совокупностью его узлов (распространённый метод).
Далее, создаётся сам список, что происходит простым созданием его головы:

Код:
Procedure CreateList;
begin
 new(head);
 head:=nil;
end;
Список пустой, поэтому пока голова зануляется (устанавливается в nil). Для дальнейшего тестирования списка создана процедура для добавления элементов (по одному):

Код:
 
Procedure Add(x: byte);

begin

 if head = nil then
{Этот условной оператор выполняется единственный раз и только в том случае, если список ещё пуст. В этом случае добавление данных происходит в голову списка, ссылка на следущий элемент зануляется и потом - выход}
                begin
                 head^.data:=x;
                 head^.next:=nil;
                 exit
                end;

 new(curr);

 curr:=head;

 while curr^.next <> nil
               do curr:=(curr^.next)^;

 curr^.data:=x;

end;

Для того чтобы убедиться, что у меня всё правильно, я ввёл в свою программу процедуру для вывода всего списка на экран:


Код:

Procedure ShowList;
begin
     curr:=head;
     WriteLn;
     While curr^.next <> nil do
                             begin
                               writeLn('!!!!!!!!!!!'); {Это для отладки}
                               readkey; {И это тоже}
                               writeLn(curr^.data);
                             end;

end;
Ну и, собственно, весь код:

Код:
program Project1;

uses
  Crt;

type TNode = ^Node;

        Node = Record
                  data: byte;
                  next: ^Tnode;
               end;

 var curr, head: Tnode;

Procedure CreateList;
begin
 new(head);
 head:=nil;
end;

Procedure Add(x: byte);

begin

 if head = nil then
                begin
                 head^.data:=x;
                 head^.next:=nil;
                 exit
                end;

 new(curr);

 curr:=head;

 while curr^.next <> nil
               do curr:=(curr^.next)^;

 curr^.data:=x;

end;

Procedure ShowList;
begin
     curr:=head;
     WriteLn;
     While curr^.next <> nil do
                             begin
                               writeLn('!!!!!!!!!!!');
                               readkey;
                               writeLn(curr^.data);
                             end;

end;


 var k: byte;

begin
    ClrScr; writeln;


    CreateList;

    Read(k);
    Add(k);

    ShowList;


     ReadKey;


end.
Теперь, что же у меня происходит...
Запускаю программу на исполнение, ввожу число (например, 5). Процедура Add благополучно его принимает, далее вызывается процедура ShowList. Но на экран ничего не выводится.

Методом пошаговой трассировки (F7) мною было установлено, что проблемы возникают из-за двух противоречий в коде программы:
В процедуре добавления элементов:

Код:
head^.next:=nil
Здесь у меня написано, что после добавления элемента в голову, её ссылка уславливается в nil.

А в процедуре вывода элементов на экран написано:
Код:
     curr:=head;
     WriteLn;

While curr^.next <> nil do
Процедура вывода вызывается сразу же после процедуры ввода элементов в список.

Цикл у нас будет выполняться, пока ссылочная часть очередного элемента не будет пустой, а поскольку в проедуре добавления элементов ссылочная часть головы была занулена, а в процедуре вывода curr стал эквивалентен голове списка, цикл не выполняется ни разу, а сразу идёт переход в конец процедуры.

Но как тогда поступать иначе, ведь ссылочная часть последнего добавленного элемента в спике должна указывать в nil, верно?

Да и строка
curr:=(curr^.next)^; мне не очень симпатична...

Итак, я прошу помощи в реализации списка, не могли бы хорошо так меня проконсультировать, чтобы я более-менее понял и разобрался с этим.

Спасибо большое заранее.

Последний раз редактировалось Вадим Мошев; 10.12.2018 в 13:13.
Вадим Мошев вне форума Ответить с цитированием
Старый 18.04.2011, 18:26   #2
Son Of Pain
Участник клуба
 
Регистрация: 23.12.2010
Сообщений: 1,129
По умолчанию

Итак, по порядку.
1)
Код:
 type TNode = ^Node;
Поскольку это указатель (Pointer), принято называть такие типы PNode.

2)
Код:
                  next: ^Tnode;
Указатель на указатель? Символ ^ - лишний.

3)
Код:
 new(head);
 head:=nil;
Сначала ты выделяешь память для структуры, а потом обнуляешь указатель на нее. Зачем? Выделенный блок памяти становится недоступным для дальнейшего использования (memory leak). Строчка с new - лишняя.

4)
Код:
 if head = nil then
                begin
                 head^.data:=x;
Смотрим сюда внимательнее, и видим обращение по нулевому указателю - runtime error.

5)
Код:
 new(curr);
 curr:=head;
Ошибка, похожая на описанную в пункте 3. Вообще, в процедуре добавления элементов почти все неправильно. Она, например, может выглядеть так (для добавления вконец списка):
Код:
Procedure Add(x: byte);
var n, tmp:PNode;
begin
 new(n);
 n^.data:=x;
 n^.next:=nil;
 if head = nil then
     head:=n
 else begin
     tmp:=head;
     while tmp^.next <> nil do tmp:=tmp^.next;
     tmp^.next:=p;
 end;
end;
6) В процедуре вывода списка сейчас есть бесконечный цикл
После вывода значения на экран нужно написать
Код:
curr:=curr^.next;
и условие заменить на
Код:
while curr <> nil

Последний раз редактировалось Son Of Pain; 18.04.2011 в 18:30.
Son Of Pain вне форума Ответить с цитированием
Старый 18.04.2011, 19:37   #3
Вадим Мошев

Старожил
 
Аватар для Вадим Мошев
 
Регистрация: 12.11.2010
Сообщений: 8,568
По умолчанию

Большое спасибо тебе. Я ещё не всё проанализировал, но тем не менее, очень благодарен.

Да, действительно были вещи элементарные, которые я не углядел (видать, сильно утомился) но также есть и то, что мне следует подучить/запомнить/выучить
Вадим Мошев вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[РЕШЕНО]: Вращение шестиугольника. Делфи 7 Наталочка12 Помощь студентам 3 16.11.2016 13:57
Проверка кода Делфи. Динамический кольцевой список agrestid Помощь студентам 30 30.11.2015 15:50
Динамический список Паскаль andrew_ryaba Паскаль, Turbo Pascal, PascalABC.NET 1 30.12.2013 09:26
Опять! однонаправленный список Паскаль, Делфи, Бейсик pionerka Помощь студентам 0 13.12.2012 18:41
однонаправленный список Паскаль, Делфи, Бейсик pionerka Помощь студентам 3 09.12.2012 17:22