Здравствуйте.
Проверьте, пожалуйста, правильно ли выполнено задание:
Реализуйте заданную структуру данных (двусвязный список целых чисел) в виде класса (набора классов).
Не используйте стандартные классы .NET для представления коллекций ( разрешается использование только массивов).
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
PList = ^TList;
TList = record
inf : integer;
prior: PList;
next : PList
end;
TListDual = object
private
pfirst, plast : PList;
public
constructor Init;
destructor RemoveList;
procedure Print_forward;
procedure Print_back;
procedure Insert( NewInf : integer);
end;
constructor TListDual.Init; {инициализация списка }
begin
pfirst := nil; plast := nil;
end;
destructor TListDual.RemoveList; {уничтожение списка}
var
q: Plist;
begin
if pfirst = nil then writeln('List not init')
else
begin
while pfirst <> nil do
begin
q := pfirst;
pfirst := pfirst^.next;
dispose(q);
end;
end;
plast := nil;
end;
procedure TListDual.Print_forward; { процедура печати элементов с первого(начало) }
var start : PList;
begin
if pfirst = nil then writeln('List not init')
else
begin
start := pfirst;
while (start <> nil) do
begin
write(start^.inf, ' ');
start := start^.next;
end;
WriteLn;
end;
end;
procedure TListDual.Print_back; { процедура печати элементов с последнего(начало) }
var last : PList;
begin
if plast = nil then writeln('List not init')
else
begin
last := plast;
while (last <> nil) do
begin
write(last^.inf, ' ');
last := last^.prior;
end;
WriteLn;
end;
end;
procedure TListDual.Insert( NewInf : integer); {процедура вставки элементов в конец списка(информационная часть) }
var
p : PList;
begin
new(p);
p^.inf := NewInf;
p^.next := nil;
if (pfirst=nil) and (plast=nil) {если пустой список} then
begin
pfirst := p;
pfirst^.prior := nil;
end
else {список не пуст, добавляем элемент в конец и корректируем указатели}
begin
plast^.next := p;
p^.prior := plast;
end;
plast := p;
end;
begin
{ TODO -oUser -cConsole Main : Insert code here }
end.
Здесь:
procedure TListDual.Insert( NewInf : integer); {процедура вставки элементов в конец списка(информационная часть) }
var
p : PList;
begin
new(p);
p^.inf := NewInf;
p^.next := nil;
if (pfirst=nil) and (plast=nil) {если пустой список} then
begin
pfirst := p;
pfirst^.prior := nil;
end
else {список не пуст, добавляем элемент в конец и корректируем указатели}
begin
plast^.next := p;
p^.prior := plast;
end;
plast := p;
end;
procedure TListDual.Insert( NewInf : integer);Остальное вроде нормально, напиши тестовую программу и проверь, работает ли, нет ли утечек, не вылетает ли где...
var p : PList;
begin
new(p);
p^.inf := NewInf;
p^.next := nil;
p^.prior := plast;
if (pfirst=nil) {если пустой список}
then pfirst := p
else {список не пуст, добавляем элемент в конец }
plast^.next := p;
plast := p;
end;
Спасибо. В том то и дело, что оно работает, но меня смущает формулировка вопроса, что надо реализовать список в виде класса
Значит, сделай так:
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TList = class
inf : integer;
prior: TList;
next : TList;
constructor Create(AInf : Integer;
APrev, ANext : TList);
end;
TListDual = class
private
pfirst, plast : TList;
public
constructor Create;
destructor Destroy; override;
procedure Print_forward;
procedure Print_back;
procedure Insert(NewInf : integer);
function IsEmpty : Boolean;
end;
constructor TList.Create(AInf : Integer;
APrev, ANext : TList);
begin
Inf := AInf;
Prior := APrev; Next := ANext;
end;
constructor TListDual.Create;
begin
pfirst := nil; plast := nil;
end;
function TListDual.IsEmpty : Boolean;
begin
Result := (pFirst = nil);
end;
destructor TListDual.Destroy;
var q : Tlist;
begin
if IsEmpty then writeln('List not init')
else
begin
while not IsEmpty do
begin
q := pfirst;
pfirst := pfirst.next;
q.Free;
end;
end;
plast := nil;
inherited;
end;
procedure TListDual.Print_forward;
var start : TList;
begin
if IsEmpty then writeln('List not init')
else
begin
start := pfirst;
while (start <> nil) do
begin
write(start.inf, ' ');
start := start.next;
end;
WriteLn;
end;
end;
procedure TListDual.Print_back;
var last : TList;
begin
if IsEmpty then writeln('List not init')
else
begin
last := plast;
while (last <> nil) do
begin
write(last.inf, ' ');
last := last.prior;
end;
WriteLn;
end;
end;
procedure TListDual.Insert( NewInf : integer);
var p : TList;
begin
P := TList.Create(NewInf, PLast, nil);
if IsEmpty then
pfirst := P
else
plast.next := p;
plast := P;
end;
var
L : TListDual;
i : Integer;
begin
L := TListDual.Create;
for i := 1 to 10 do
begin
L.Insert(i);
end;
L.Print_Back;
L.Print_Forward;
L.Free;
end.
Огромное спасибо !!!
Буду разбираться. Может еще подскажете: в другом задании надо написать обобщенную реализацию для этого двусвязного списка, позволяющую хранить объекты (ссылочные переменные); Для этого в теле программы просто надо запустить методы,или я что-то неправильно поняла?
Ничего особенного делать не надо, разницы, что именно хранить, целые числа или ссылки на объект класса, никакой нет. Только не надейся, что все будет вот так вот безоблачно Во-первых, проблема будет с выводом данных (печать через WriteLn допустима для встроенных типов, но не для объектов, WriteLn просто не умеет печатать объекты). Но это еще не все. Проблема вторая: при уничтожении списка нужно удалять и его содержимое. В случае, который рассмотрен выше (список целых) этого делать не надо, а вот если список будетхранить ссылки на какие-то объекты, то объекты эти надо будет уничтожать, иначе будут утечки. И тут возникает вопрос: а как, собственно, отличить, работает список с Integer-ами (или Boolean-ами, или Double-ами), которые удалять не надо, или с объектами самописных типов, которые удалять-таки нужно? Вот тут, я имею в виду:
type
T = TSomeClass; // Какой-то тип, потомок TObject, как все классы
// Класс, хранящий элемент списка, практически не изменяется,
// разве что добавляется деструктор. В котором и будет проблема
TList = class
inf : T;
prior: TList;
next : TList;
constructor Create(AInf : T; APrev, ANext : TList);
destructor Destroy; override;
end;
constructor TList.Create(AInf : T; APrev, ANext : TList);
begin
Inf := AInf;
Prior := APrev; Next := ANext;
end;
destructor TList.Destroy;
begin
inf.Free; // Попытка сделать это, когда Inf - переменная простого типа - ошибка
end;
// Создаваться элемент списка может так:
L := TListDual.Create;
for i := 1 to 10 do
begin
L.Insert( TSomeClass.Create('Object #' + IntToStr(i)) );
end;
Я так понимаю, что в проблеме с деструктором дело в ограничениях, но конкретно еще не разобралась (расскажите, пожалуйста, я на правильном пути?)
А по поводу вывода данных пока мыслей нет
> Какие есть мысли по преодолению проблемы?
Подключить интерфейсы, чтобы было хоть какое-то автоудаление.
Uses ..., TypInfo;
// ...
destructor TList.Destroy;
begin
if PTypeInfo(typeInfo(T)).Kind = tkClass then // Класс ? Очищаем ...
begin
// Вызов inf.Free компилятор не пропустит,
// если работаешь со встроенным типом, поэтому используем
FreeAndNil(inf)
end;
end;
procedure PrintMe(Obj : твой_тип); overload;
begin
// тут выводишь каким-то образом значение
end;
// Cкажем, для Integer-ов:
procedure PrintMe(Obj : Integer); overload;
begin
write(Obj, ' ');
end;
// Для любых классов - может быть так:
procedure PrintMe(Obj : TObject); overload;
begin
write(Obj.ToString, ' ');
// Пускай класс сам разбирается, как выводить информацию
// Обычно для этого как раз перегружается метод ToString()
end;
[offtop]Володь, давно подпись сменил? Я только заметил )). Класс!
Рекомендую аватар вырезать из фото 22 [/offtop]
Скажите, пожалуйста, надо писать именно T = TSomeClass;? Компилятор не пропускает
Вроде объявляют как-то типа TSomeClass<T>=class(TObject) или это не о том?
Спасибо, мне именно на дженериках и надо было.
Но объясните, пожалуйста, запись: TPrintProcedure<T> = reference to procedure(const Value: T); или где можно почитать?
Вот тут можно почитать об анонимных методах: http://skiminog.livejournal.com/33854.html
Спасибо большое, классно написано. Многое стало более понятно
Почитал ссылку
> На практике очень часто применяются функции, создающие другие функции в зависимости от параметров. Это экономит время и место, в случае, если результирующая функция готовится к частому использованию.
А на самом деле там действительно создаются функции (т.е. выделяется кусок памяти, в него пишется тело новой функции, кусок помечается выполняемым), или создаются структуры из указателя и внутренних переменных, которые ведут себя как функции, только намного медленнее?
Анонимные методы реализуются с помощью интерфейса, имеющего один-единственный метод Invoke, совпадающий по сигнатуре с анонимным.
http://sergworks.wordpress.com/2010/01/27/anonimous-methods-in-delphi-the-internals/