IPB
ЛогинПароль:

> ВНИМАНИЕ!

Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Двусвязный список в виде класса
сообщение
Сообщение #1





Группа: Пользователи
Сообщений: 6
Пол: Женский

Репутация: -  0  +


Здравствуйте.
Проверьте, пожалуйста, правильно ли выполнено задание:
Реализуйте заданную структуру данных (двусвязный список целых чисел) в виде класса (набора классов).
Не используйте стандартные классы .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.

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Здесь:
Цитата
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;
Остальное вроде нормально, напиши тестовую программу и проверь, работает ли, нет ли утечек, не вылетает ли где...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3





Группа: Пользователи
Сообщений: 6
Пол: Женский

Репутация: -  0  +


Спасибо. В том то и дело, что оно работает, но меня смущает формулировка вопроса, что надо реализовать список в виде класса
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Значит, сделай так:
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.

- будет тебе в виде набора классов. Проверял в FPC, вроде работает, утечек не дает... Что непонятно в реализации - спрашивай.

Сообщение отредактировано: IUnknown -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Гость






Огромное спасибо !!!
Буду разбираться. Может еще подскажете: в другом задании надо написать обобщенную реализацию для этого двусвязного списка, позволяющую хранить объекты (ссылочные переменные); Для этого в теле программы просто надо запустить методы,или я что-то неправильно поняла?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Ничего особенного делать не надо, разницы, что именно хранить, целые числа или ссылки на объект класса, никакой нет. Только не надейся, что все будет вот так вот безоблачно smile.gif Во-первых, проблема будет с выводом данных (печать через 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;



, не сделать вышеописанное в деструкторе - утечка, когда работаем с классами. Что делать думаешь? Какие есть мысли по преодолению проблемы? smile.gif
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7





Группа: Пользователи
Сообщений: 6
Пол: Женский

Репутация: -  0  +


Я так понимаю, что в проблеме с деструктором дело в ограничениях, но конкретно еще не разобралась (расскажите, пожалуйста, я на правильном пути?)
А по поводу вывода данных пока мыслей нет
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> Какие есть мысли по преодолению проблемы?

Подключить интерфейсы, чтобы было хоть какое-то автоудаление.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


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

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

2) каким-то образом в рантайме проверять, нужно ли вызывать деструктор хранимого объекта, или нет. Вот это уже лучше:

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;


А все вызовы write(inf) внутри TListDual - заменить на вызовы PrintMe(inf)...

Сообщение отредактировано: IUnknown -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Уникум
*******

Группа: Пользователи
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


[offtop]Володь, давно подпись сменил? Я только заметил )). Класс! good.gif

Рекомендую аватар вырезать из фото 22 yes2.gif
[/offtop]


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11





Группа: Пользователи
Сообщений: 6
Пол: Женский

Репутация: -  0  +


Скажите, пожалуйста, надо писать именно T = TSomeClass;? Компилятор не пропускает
Вроде объявляют как-то типа TSomeClass<T>=class(TObject) или это не о том?

Сообщение отредактировано: Rei-li -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
Вроде объявляют как-то типа TSomeClass<T>=class(TObject)
Это дженерики. Тебе что, надо реализацию именно на дженериках? А версия Дельфи у тебя какая? 2009 или выше потребуется для Generic Classes.

Как-то вот так (Показать/Скрыть)

Я там немного поменял способ задания процедуры печати, если есть дженерики - значит есть и анонимные процедуры, вот их использование я и показал. Разумеется, проход вперед/назад по списку можно было сделать по-другому, через For .. In, но это еще усложнит код, так что не буду этого делать сейчас. Только, если тебя заинтересует smile.gif

[offtop mode]
Цитата
Володь, давно подпись сменил? Я только заметил )). Класс!
Спасибо. Нет, недавно, она появилась-то в доме всего месяц назад... Скоро еще добавлю фотографий. yes2.gif
Цитата
Рекомендую аватар вырезать из фото 22
Не, это чересчур будет smile.gif У меня, правда, бывает такое же выражение лица, когда я читаю некоторые вопросы, но не всегда же lol.gif

[/offtop mode]

Сообщение отредактировано: IUnknown -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13





Группа: Пользователи
Сообщений: 6
Пол: Женский

Репутация: -  0  +


Спасибо, мне именно на дженериках и надо было.
Но объясните, пожалуйста, запись: TPrintProcedure<T> = reference to procedure(const Value: T); или где можно почитать?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #14


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Вот тут можно почитать об анонимных методах: http://skiminog.livejournal.com/33854.html
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #15





Группа: Пользователи
Сообщений: 6
Пол: Женский

Репутация: -  0  +


Спасибо большое, классно написано. Многое стало более понятно
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #16


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Почитал ссылку

> На практике очень часто применяются функции, создающие другие функции в зависимости от параметров. Это экономит время и место, в случае, если результирующая функция готовится к частому использованию.

А на самом деле там действительно создаются функции (т.е. выделяется кусок памяти, в него пишется тело новой функции, кусок помечается выполняемым), или создаются структуры из указателя и внутренних переменных, которые ведут себя как функции, только намного медленнее?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #17


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Анонимные методы реализуются с помощью интерфейса, имеющего один-единственный метод Invoke, совпадающий по сигнатуре с анонимным.

http://sergworks.wordpress.com/2010/01/27/...-the-internals/
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 29.03.2024 12:20
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name