Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Центр помощи > [Delphi] Работа со сложными структурами данных


Автор: SniyLSD 28.5.2008, 17:54
Всем привет! У меня есть небольшая просьба о помощи по теме динамические структуры данных, 
Есть задача :
    Элементы двунаправленного списка имеют следующую структуру:
- Шифр детали
- Наименование
- Цена
- Вес
- Указатель предыдущего
- Указатель последующего
Удалить элемент с заданным номером  от конца списка.

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

Автор: anwe 28.5.2008, 22:45
Тебе надо все последующие номера сместить на 1 влево: на место 2-го пойдет 3, на место 3-го пойдет 4 и т. д. А потом у смещенных уменьшить номера на единицу.
А в коде, не разбираясь с записями, видна сразу явная ошибка:
Код

   while p<>nil do
   i:=i+1;
Где смена условия? Где изменение р? Это бесконечный цикл!

Автор: SniyLSD 29.5.2008, 05:58
Понятно вроде, но слишком замудрился я с ней smile  - тему "Дин. списки " я плохо понял smile
Цитата

 А в коде, не разбираясь с записями, видна сразу явная ошибка:

  while p<>nil do
   i:=i+1;


Так, вроде чуть поправил:
Код

begin
  k:=strtoint(edit1.text);
  i:=0;
  g:=(t-k)+1;
   while p<>nil do
   i:=i+1;
   p:=p^.next;{вставил изменение p, но начинает выдавать ошибку на обращение к памяти. похоже надо поставить в конец кода этот оператор}
    if (i=g) then
      Begin
        P:=Head;//
        B:=False; //перенесен из начала процедуры
          If P=Head Then
            Begin
              Head:=P^.Next;
              p1:=p^.next;
            End
            Else
              Begin
                If P^.Next=Nil Then
                b:=true
                  Else
                    Begin
                      Last^.Next:=P^.Next;
                      P1:=P^.next;
                      P1^.prev:=last;
                    End;
              End;
              If  B Then
              Last^.Next:=Nil;
            End;
            Last:=P;
            P:=P^.Next;
          end;


Теперь не виснет, но выдает ошибку типа 
"Project Project1.exe raised exception class EAccessViolation with message 'Access violation at address 0045F58E in module 'Project1.exe'. Read of address 00000054'. Process stopped. Use step or Run to continue." Ошибку обращения к памяти.

[quote]Тебе надо все последующие номера сместить на 1 влево: на место 2-го пойдет 3, на место 3-го пойдет 4 и т. д. А потом у смещенных уменьшить номера на единицу.[quote]
эммм... не понял, эти номера на счет чего?
 если честно, я этот код списал из программы аналогичной задачи, но там было другое условие - Удалить повторяющиеся элементы списка, если в них совпадает шифр и наименование. Сам в нем плохо разобрался.

Можете мне помочь написать этот кусок кода правильно? Чтоб работал))

Автор: SniyLSD 29.5.2008, 08:06
Понятно вроде, но слишком замудрился я с ней :crazy  - тему "Дин. списки " я плохо понял :dash1
Цитата

 А в коде, не разбираясь с записями, видна сразу явная ошибка:

  while p<>nil do
   i:=i+1;


Так, вроде чуть поп

Автор: anwe 29.5.2008, 13:38
Цитата(SniyLSD @  29.5.2008,  07:06 Найти цитируемый пост)
тему "Дин. списки " я плохо понял 

Это одно а незнание элементарных операторв - это другое. Почитай про while..do. Для выхода условие должно менятся внутри цикла. То что добавлено, ничего не дает. Для этого оператора при его работе с циклом из нескольких строк нужны операторные скобки. Да и добавил строку p:=p^.next, независящую от i. А проскакивает у тебя этот цикл, вероятно, потому что делаешь это в первый же раз. Другими словами и p и head=nil
Цитата
эммм... не понял, эти номера на счет чего?

Это индексы элементов в массиве.

Автор: SniyLSD 29.5.2008, 15:42
Походу я намудрил с алгоритмом подсчитывания номера удаляемого элемента от головы. это все и усложнило процедуру удаления, а может этот способ даже неприемлен для данной ситуации, что вызывает различного рода ошибки.
Можете мне помочь написать код который выбирает элемент с заданным номером от конца списка? то есть в списке 10 элементов, выбрали второй элемент от конца, а от головы он будет 9. а дальше мне будет понятнее, так как траблы у меня именно с этим((
Код


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, ExtCtrls, Grids;
    {    Элементы двунаправленного списка имеют следующую структуру:
- Шифр детали
- Наименование
- Цена
- Вес
- Указатель предыдущего
- Указатель последующего
Удалить элемент с заданным номером  от конца списка.}
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button4: TButton;
    sed1: TLabeledEdit;
    sed2: TLabeledEdit;
    sed3: TLabeledEdit;
    sed4: TLabeledEdit;
    Button6: TButton;
    Edit1: TEdit;
    StringGrid1: TStringGrid;
    Button2: TButton;
    procedure Button4Click(Sender: TObject);



    procedure Button1Click(Sender: TObject);

    procedure Edit1KeyPress(Sender: TObject; var Key: Char);

    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

Type
   TPPrice=^Tprice;

   TPrice=record
   index:string[20];
   name:string[20];
   price:string[20];
   mass:string[20];
   next:TPPrice;
   prev:TPPrice;
   end;
var
  Form1: TForm1;
   n,t:integer;        //t - количество элементов в списке
   p,p1,p2,head,last: TPPrice;
   B,B1:boolean;

implementation

{$R *.dfm}

procedure TForm1.Button4Click(Sender: TObject);
begin
 Application.Terminate;
end;

procedure TForm1.Button1Click(Sender: TObject);

begin
 new(p);
 p^.index:=sed1.Text;
 p^.name:=sed2.Text;
 p^.price:=sed3.text;
 p^.mass:=sed4.text;
  if head=nil then
  begin
    p^.next:=nil;
    p^.prev:=nil;
    head:=p;
    last:=p;
  end
  else
    begin
      last^.next:=p;
      p^.prev:=last;
      p^.next:=nil;
    end;
  last:=p;
   sed1.clear;
   sed2.clear;
   sed3.clear;
   sed4.clear;
   sed1.SetFocus;
   END;
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);  {процедура фильтрации ввода}
begin
 case key of
  '0'..'9':;
  else key:=chr(0);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   head:=nil;
  last:=nil;
  n:=0;
  StringGrid1.Cells[0,0]:='№';
  StringGrid1.Cells[1,0]:='Шифр';
  StringGrid1.Cells[2,0]:='Наименование';
  StringGrid1.Cells[3,0]:='Цена';
  StringGrid1.Cells[4,0]:='Вес';
end;

procedure TForm1.Button2Click(Sender: TObject); {процедура вывода списка в таблицу}
var i:integer;
begin
  i:=0;
  p:=head;
  StringGrid1.RowCount:=2;
  StringGrid1.Cells[0,1]:='';
  StringGrid1.Cells[1,1]:='';
  StringGrid1.Cells[2,1]:='';
  StringGrid1.Cells[3,1]:='';
  StringGrid1.Cells[4,1]:='';
  t:=0;
  while p<>nil do
    begin
      t:=t+1; // здесь мы считаем количество элементов в списке
      i:=i+1;
      StringGrid1.RowCount:=StringGrid1.RowCount+1;
      StringGrid1.Cells[0,i]:=IntToStr(i);
      StringGrid1.Cells[1,i]:=p^.index;
      StringGrid1.Cells[2,i]:=p^.name;
      StringGrid1.Cells[3,i]:=p^.price;
      StringGrid1.Cells[4,i]:=p^.mass;
      p:=p^.next;
    end;
  StringGrid1.Cells[0,i+1]:='';
  StringGrid1.Cells[1,i+1]:='';
  StringGrid1.Cells[2,i+1]:='';
  StringGrid1.Cells[3,i+1]:='';
  StringGrid1.Cells[4,i+1]:='';

  END;

procedure TForm1.Button6Click(Sender: TObject);
var
 k,g,i:integer;
begin
  k:=strtoint(edit1.text);
  i:=0;
  g:=(t-k)+1; 

{ g - нужный нам элемент, получаемый в результате вычитания числа введенного пользователем из числа t и суммой полученного числа с 1. в результате мы начинаем считать цикл идущий следом, если i (количество проведенных циклов - совпадает с номером элемента от головы) , будет равно числу g то инициируется удаление данного элемента.}


   while p<>nil do
   i:=i+1;
    if (i=g) then
      Begin
        P:=Head;
        B:=False;
          If P=Head Then
            Begin
              Head:=P^.Next;
              p1:=p^.next;
            End
            Else
              Begin
                If P^.Next=Nil Then
                b:=true
                  Else
                    Begin
                      Last^.Next:=P^.Next;
                      P1:=P^.next;
                      P1^.prev:=last;
                    End;
              End;
              If  B Then
              Last^.Next:=Nil;
            End;
            Last:=P;
            P:=P^.Next;
          end;

    
end.





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

Автор: anwe 29.5.2008, 19:47
Отвечая на первый вопрос
Цитата(SniyLSD @  28.5.2008,  16:54 Найти цитируемый пост)
но не работает удаление нужного элемента списка

привожу работоспособный код:
Код

Type
   TPPrice=^Tprice;
   TPrice=record
   index:string[20];
   name:string[20];
   price:string[20];
   mass:string[20];
   nomer:byte;         //это добавлено: номер элемента в списке
   next:TPPrice;
   prev:TPPrice;
   end;
Код

procedure TForm1.Button1Click(Sender: TObject);
begin
n:=n+1;          //это добавлено
...
p^.nomer:=n;   //это добавлено
...

Добавлена кнопка Button3 (чтобы твой код не трогать)
Код

procedure TForm1.Button3Click(Sender: TObject);
var
 k,i:integer;
 q:TPPrice;
begin
k:=strtoint(edit1.text);
P:=Head;
try
    if k<>1 then
        while k-1<>p^.nomer do
        p:=p^.next;
    q:=p^.next;
    p^.next:=q^.next;
    p:=q;
    if k=n then
    p:=p^.prev;
    for i:=k+1 to n-1 do
        begin
        p:=p^.next;
        p^.nomer:=p^.nomer-1;
        end;
    n:=n-1;
    Button2.Click;
except
ShowMessage('Такого номера нет);
end;
end;

Ниже сам проект.

Автор: SniyLSD 30.5.2008, 00:00
Ого! Спасибо дружище! Блин, не додумался до такого простого варианта (, видно сказывается небольшой опыт практического программирования, да и с сессией замотался - мозги кипят smile , сейчас курсовой проект как раз только закончил, на часах у меня 6 утра.
Еще раз спасибо)  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)