динамические структуры в паскале

Модераторы: Duncon, Naeel Maqsudov, Игорь Акопян, Хыиуду

Аватара пользователя
Alex_Burn
Сообщения: 147
Зарегистрирован: 13 апр 2007, 17:49
Контактная информация:

Здравствуйте, уважаемые участники форума!

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

Вот какое у меня задание:

Разработать программу, которая удаляет из списка все элементы, меньше заданного пользователем значения k. Список строится путем ввода с клавиатуры значений элементов. Количество элементов заранее не известно, но отлично от нуля. Процедуры и функции для работы со списком (такие как формирование списка, поиск элемента по ключу, удаление элемента списка, просмотр списка и т.п.) оформить в виде модуля.

Вот какой модуль я пытался составить:

Код: Выделить всё

unit list;
 interface
 uses crt;
   const n=10;
   type ukaz=^k;
        k=record
         inf:integer;
         next:ukaz;
        end;
   var nlst,klst,pc,p,px:ukaz;
       c:array[1..n] of integer;
       i,key:integer;
       flag:boolean;
   procedure fill(var nlst:ukaz);
   procedure survey(nlst:ukaz);
   procedure search(var key:integer; nlst,p:ukaz; flag:boolean);
   procedure delete(var key:integer; nlst:ukaz);
 implementation
   procedure fill(var nlst:ukaz);
    begin
     for i:=1 to n do
      begin
       new(p);
       p^.inf:=c[i];
       p^.next:=nlst;
       nlst:=p;
      end;
    end;
   procedure survey(nlst:ukaz);
    begin
     write('Содержание списка:  ');
     p:=nlst;
     if nlst<>nil then
      repeat
       write(p^.inf,' ');
       p:=p^.next;
      until p=nil;
    end;
   procedure search(var key:integer; nlst,p:ukaz; flag:boolean);
    begin
     p:=nlst;
     flag:=false;
     while (p<>px) and (not flag) do
      begin
       if p^.inf<key
       then flag:=not flag
       else
        begin
         px:=p;
         p:=p^.next;
        end;
      end;
    end;
   procedure delete(var key:integer; nlst:ukaz);
    var p,px:ukaz;
    begin
     search(key,nlst,p,flag);
     px^.next:=p^.next;
     dispose(p);
     p:=nil;
    end;
end.
Но программа, использующая этот модуль не работает. Помогите пожалуйста разобраться, почему.

Заранее благодарен!
Аватара пользователя
Duncon
Сообщения: 2085
Зарегистрирован: 10 окт 2004, 14:11
Откуда: Питер
Контактная информация:

Ошибка тут(дальше не смотрел)
Ты объявляешь некую переменную ukaz ссылкой на запись и внутри нее переменная next которая будет ссылкой на саму себя, ппс даже объяснить нормально не могу такой бред...

Код: Выделить всё

type ukaz=^k;
        k=record
         inf:integer;
         next:ukaz;
        end;
Писать нужно примерно так

Код: Выделить всё

type 
  k = record
  inf: integer;
  next: string; //(ну или чем у тебя является по задумке данная переменная)
end;
ukaz=^k;
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

Duncon, синтаксических ошибок тут нет.
Разьве что в третьей строке снизу буковка "х" попала.... Наверное случайно.

А "такой бред" - это специальное исколючение языка Паскаль для работы со списками. Оно заключается в том, что без слова forward разрешается объявлять взаиморекурсивные типы данных.
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

Alex_Burn, к сожалению нет много времени разбираться, но могу сказать следующее.
1) процедура fill - не является решением поставленной задачи, так как количество элементов задано констанотой, а к тому же процедура создает список из массива, а не вводом с клавиатуры.
2) процедура survey нормально выводит список
3) процедура delete использует глобальные переменные p и flag - этого не следует делать. Вообще в delete что-то несуразное написано.
4) не понял с первого взгляда, что делает параметр flag в процедуре search

Код основной программы тоже в студию!

Вцелом (как бывший преподаватель ИТ в ВУЗе) могу сказать, что это работа на "незачет".
Аватара пользователя
Alex_Burn
Сообщения: 147
Зарегистрирован: 13 апр 2007, 17:49
Контактная информация:

Ещё раз здравствуйте, уважаемые участники форума. :)

Прошу прощения, что не принимал участия в дискуссии вчера и позавчера (не было доступа к интернету).

Что касается модуля, то я, в принципе, не понял тему (в смысле про динамические структуры). Поэтому и написал полный бред. Да и менял я код уже 10 раз (возможно с каждым разом получалось все бредовее).

Что касается главной программы, то что-то в этом духе:

Код: Выделить всё

program lst;
uses crt, list;
 begin
 clrscr;
  writeln('введите числа для занесния в список(10 чисел)');
  for i:=1 to n do read(c[i]);
  fill(nlst);
  survey(nlst);
  writeln('введите число (все числа меньше введенного будут удалены из списка)');
  readln(key);
  writeln;
  delete(key,nlst);
  survey(nlst);
 readkey;
 end.
Не мог бы кто-нибудь из вас подсказать мне как правильно все это сделать, а то сам никак не разберусь. :confused:

Заранее благодарен.
Аватара пользователя
Alex_Burn
Сообщения: 147
Зарегистрирован: 13 апр 2007, 17:49
Контактная информация:

не могли бы вы поделиться своими мыслями по поводу задачи, которую я выложил в начале темы? как ее лучше реализовать? выручайе... :(
Аватара пользователя
Игорь Акопян
Сообщения: 1440
Зарегистрирован: 13 окт 2004, 17:11
Откуда: СПБ
Контактная информация:

Alex_Burn,
процедуру Fill переделать - убрать цикл for, спросить количество и заполнять в цикле while

Да и вообще надо переделать алгоритм, чтобы было понятнее:
1) Функция Search по идее должна искать в списке элемент равный ключу, принимает 2 параметра - ключ и указатель на начало, возвращает указатель на найденный элемент. Но для решения задачи она не нужна, ибо надо делать полный перебор элментов списка в цикле
2) Процедура Delete должна удалять элемент из списка, переданный в качестве параметра.
3) В теле программы в цикле while бежим по всем элементам, и если значение меньше заданного вызываем Delete на текущий элемент

Полагаю что остальные процедуры должны быть как заготовка на случай изменения условия задачи
Изображение
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

Код: Выделить всё

program lst;
uses crt, list;
var
  nlst:ukaz;
  key:integer;
begin
  clrscr;
  if fill(nlst)>0 then begin
    survey(nlst);
    writeln('введите число (все числа меньше введенного будут удалены из списка)');
    repeat until getnumber(key)=gnOk;
    search_n_del(key,nlst);
    survey(nlst);
  end
    else writeln('Был введен пустой список');
  readkey;
end.

==========================================================

unit list;

interface

uses
  crt;

const
  n=10;

type
  ukaz=^k;
  k=record
    inf:integer;
    next:ukaz;
  end;

  getnumberstatus = (gnOk,gnStop,gnErr);

  function getnumber(var X:integer):getnumberstatus;
  function fill(var nlst:ukaz):integer;
  procedure add(val:integer; var nlst:ukaz);
  procedure survey(nlst:ukaz);
  procedure search_n_del(key:integer; var nlst:ukaz);
  procedure deletefirst(var nlst:ukaz);
  procedure deletenext(pred:ukaz);

implementation

function getnumber(var X:integer):getnumberstatus;
var
  s:string; code:integer;
begin
  readln(s);
  if s='' then getnumber:=gnStop else begin
    val(s,X,code);
    if code=0 then getnumber:=gnOk else getnumber:=gnErr;
  end
end;

function fill(var nlst:ukaz):integer;
var
  i,r:integer;
  p:ukaz;
begin
  r:=0;
  nlst:=nil;
  writeln('Введите числа, для завершения ввода нажмите Enter');
  repeat
    case getnumber(i) of
      gnOk: begin
        add(i, nlst);
        inc(r);
      end;
      gnErr: writeln('Ошибка! Неверное число');
      gnStop: break;
    end;
  until false;
  fill:=r;
end;

procedure add(val:integer; var nlst:ukaz);
var
  p:ukaz;
begin
  new(p);
  p^.inf:=val;
  p^.next:=nlst;
  nlst:=p;
end;

procedure survey(nlst:ukaz);
var
  r:integer;
begin
  r:=0;
  write('Содержание списка: ');
  while nlst<>nil do begin
    write(nlst^.inf);
    if nlst^.next<>nil then write(', ') else writeln('.');
    nlst:=nlst^.next;
    inc(r);
  end;
  writeln('Всего ',r,' элементов');
end;

procedure search_n_del(key:integer; var nlst:ukaz);
var
  p:ukaz;
begin
  p:=nlst;
  while (p<>nil) and (p^.next<>nil) do begin
    if p^.next^.inf < key then deletenext(p) else p:=p^.next;
  end;
  if (nlst<>nil) and (nlst^.inf<key) then deletefirst(nlst);
end;


procedure deletenext(pred:ukaz);
var
  p:ukaz;
begin
  if (pred<>nil) and (pred^.next<>nil) then begin
    p:=pred^.next;
    pred^.next:=p^.next;
    dispose(p);
  end;
end;

procedure deletefirst(var nlst:ukaz);
var
  p:ukaz;
begin
  if nlst<>nil then begin
    p:=nlst;
    nlst:=nlst^.next;
    dispose(p);
  end;
end;

end.
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

функция getnumber вводит число с клавиатуры. Обеспечивает проверку ошибок и позволяет распознать пустой ввод (используется как сигнал конца списка).

функция fill заполняет список с клавиатуры. Пользуется процедурой add для добавоения элемента в начало списка. Результат функции - это сколько элементов было введено. В основной программе проверяется, но можно и не проверять, так как программа и с пустыми списками работает корректно.

процедура survey - то же что раньше, но теперь перечисляет все элементы через запятую, и сообщает длину списка (А чего по списку лазить задаром! :) )

search_n_del - решает поставленную задачу. Сначала просматривает все со второго элемента, а в заключение проверяет, не надо ли удалить первый. Так чделано потому, что в односвязном списке нельзя удалить элемент, заданный указателем. Можно удалить только следующий, от заданного указателем.
(т.е. конечно же элемент заданный указателем удалить можно, но в предыдущем надо подправить next, а искать его надо полным перебором от начала. Так что более эффективный алгоритм - это начать провыерять со второго, а потом проверить первый.
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

Alex_Burn писал(а):не могли бы вы поделиться своими мыслями по поводу задачи, которую я выложил в начале темы? как ее лучше реализовать? выручайе... :(
Готово.

2 All
Все посторонние рассуждения я перенес
в другую тему
Ответить