Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.06.03;
Скачать: CL | DM;

Вниз

Сортировка однонаправленного списка   Найти похожие ветки 

 
Val ©   (2002-05-22 15:07) [0]

Помогите пожалуйста алгоритмом на данную тему, пробовал делать стандартно, сменой соседних элементов, но запутался совершенно :(
Текст позорных изысканий привожу.
procedure SortList;
var BinElement: PointerToDevice;
i,j: word;
begin
for i := 0 to Count-1 do
begin
CurrentListElement := FirstListElement;
while CurrentListElement^.Next <> nil do
begin
if CurrentListElement^.Value.Weight > CurrentListElement^.Next^.Value.Weight then
begin
BinElement := CurrentListElement^.Next;
CurrentListElement^.Next^.Next := CurrentListElement;
CurrentListElement^.Next := BinElement^.Next;
end;
CurrentListElement := CurrentListElement^.Next;
end;
end;
end;


 
Lord Warlock ©   (2002-05-22 15:15) [1]

BinElement := CurrentListElement;
CurrentListElement:=CurrentListElement^.Next;
CurrentListElement^.Next:= BinElement;


 
McSimm ©   (2002-05-22 15:20) [2]

>Val © (22.05.02 15:07)
Похоже все нормально, за исключением ньюанса
Надо менять ссылку у предыдущего для CurrentListElement элемента.

Заведи переменную (изначально присвой nil) и при обмене двух элементов пишешь
if PrevListElement <> nil then
PrevListElement^.Next := BinElement


 
vuk ©   (2002-05-22 15:25) [3]

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


 
Lord Warlock ©   (2002-05-22 15:26) [4]


> Похоже все нормально


Да гдеж нормально!!!

он же за два элемента вперед запрыгивает!

CurrentListElement^.Next^.Next - это что??




 
McSimm ©   (2002-05-22 15:32) [5]

Все правильно.
> CurrentListElement^.Next^.Next - это что??
Это поле Next второго элемента. Ему присваивается значение ссылки на первый элемент.

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


 
Lord Warlock ©   (2002-05-22 15:48) [6]


> McSimm ©

да, звиняюсь, забыл что связи тоже нужно перетаскивать...

вот еще один позор, работает или нет, не знаю не проверил за недостатком времени

for i := 0 to Count-1 do
begin
CurrentListElement := FirstListElement;
PrevListElement:= FirstListElement;
while CurrentListElement^.Next <> nil do
begin
if CurrentListElement^.Value.Weight > CurrentListElement^.Next^.Value.Weight then
begin
BinElement := CurrentListElement^.Next;
CurrentListElement^.Next := CurrentListElement^.Next^.Next
BinElement^.Next:=CurrentListElement;
PrevListElement^.Next:=BinElement;
end;
PrevListElement:=CurrentListElement;
CurrentListElement := CurrentListElement^.Next;
end;



 
Andrey007   (2002-05-22 15:52) [7]

Я не понял задачу. Вам TList надо отсортировать, что ли?


 
McSimm ©   (2002-05-22 16:19) [8]

>Lord Warlock © (22.05.02 15:48)
не верно. Глубоко не вникал, но если менятся будут первые два элемента списка, будет ошибка. Смотри мои сообщения выше.

>Andrey007 (22.05.02 15:52)
Нет


 
PVOzerski ©   (2002-05-22 16:27) [9]

IMHO, такой путь вообще крайне медленный, даже при его успешной реализации. Если память не лимитирует, имеет смысл сделать такую штуку:

var
SortAccel:array of указатель_на_структуру;
Mover:указатель_на_структуру;
Temp:структура_того_же_типа_что_поле_Value;
....
SetLength(SortAccel,Count);
Mover:=FirstListElement;
for i:=0 to pred(Count)do
begin
SortAccel[i]:=Mover;
Mover:=Mover.Next;
end;
for i:=0 to Count-2 do
for j:=succ(i)to pred(Count)do
if SortAccel[i].Value.Weight>SortAccel[j].Value.Weight then
begin
Temp:=SortAccel[i].Value;
SortAccel[i].Value:=SortAccel[j].Value;
SortAccel[j].Value:=Temp;
end;
SetLength(SortAccel,0);


 
Lord Warlock ©   (2002-05-22 16:29) [10]


> McSimm ©

в общем подзабыл я эти указатели :(

я делал класс в котором реализован двунаправленный список и все было гораздо проще...


 
Lord Warlock ©   (2002-05-23 09:17) [11]

Пока не добью, не отстану :)

итак,

var TempElement: PointerToDevice <-добавить

for i := 0 to Count-1 do <-не понял, зачем это, сортируем список
< Count раз ?
begin
CurrentListElement := FirstListElement; <-верно
BinElement := FirstListElement; <- добавть
while CurrentListElement^.Next <> nil do
begin
if CurrentListElement^.Value.Weight > CurrentListElement^.Next^.Value.Weight then
begin
BinElement^.Next := CurrentListElement^.Next;
TempElement:=CurrentListElement^.Next;
CurrentListElement^.Next := CurrentListElement^.Next^.Next;
TempElement^.Next:=CurrentListElement;
end;
BinElement:=CurrentListElement //Запоминаем предыдущий
CurrentListElement := CurrentListElement^.Next;
end;
end;

по логике вороде так...
проверяйте


 
McSimm ©   (2002-05-23 10:33) [12]

>Пока не добью, не отстану :)
Зачем, я же еще в первом своем посте написал достаточно для решения проблемы.

>не понял, зачем это, сортируем список Count раз ?
Нет сортируем, 1 раз, но для этого Count проходов.
Алгоритм сортировки. В принципе можно немного оптимизировать, если внутренний цикл каждый раз делать на 1 короче предыдущего, т.к. после первого прохода последний элемент уже на своем месте, после второго предпоследний и т.д.

>проверяйте
Так сам и проверь, не трудно. Раз проблема так задела...


 
Val ©   (2002-05-23 10:40) [13]

>PVOzerski © (22.05.02 16:27)
идея хоршая конечно, но по чеку делфи5 по привычку щелкнул, на 7-ом паскале это делаю, а там массивы открытого типа присутствуют только в качестве параметров процедур/функций. :(
> McSimm ©
Спасибо за совет, думаю, можно начать со второго элемента списка а первый взять как Prev и т.д. Но предполагаю еще одну проблему, которая может возникнуть - работа со списком начинается, классически, с первого элемента и т.д. по указателям, пока не встретим nil можем производить какие-либо действия над всеми его элементами.
Вовремя сортировки FirstListElement может оказаться где угодно в списке, т.е., как-то надо определять первый элемент и записывать его адрес в FirstListElement.
>Lord Warlock © (23.05.02 09:17)
спасибо за активную помощь, ваш последний код еще не проверял, но почему был наружный цикл могу объяснить: когда вы пробегаете в while по списку, вы сравниваете только соседние элементы между собой и меняете их местами, а нужно сравнить между собой все элементы, для этого сравнение и смена мест производится столько раз, сколько элементов в списке, каждый раз начиная с его начала.


 
McSimm ©   (2002-05-23 11:07) [14]

>Вовремя сортировки FirstListElement может оказаться где угодно в списке
Действительно. Об этом я не подумал. Предлагаю решение сразу для двух проблем.

Исходный вариант. Изменения:
Перед нутренним циклом:
PrevListElement := nil;

При обмене (последняя операция):
if (PrevListElement = nil) then FirstListElement := BinElement
else PrevListElement^.Next := BinElement;


После if...then begin...end; :
PrevListElement := CurrentListElement;
CurrentListElement := CurrentListElement^.Next;

При этом вроде бы поддерживается ссылка от пред. элемента и актуальность FirstListElement.


 
Val ©   (2002-05-23 12:24) [15]

>McSimm © (23.05.02 11:07)
PrevListElement := CurrentListElement;
Вот тут несостыковка получается, поскольку мы меняем местами текущий элемент со следующим, то нужно PrevListElement присваивать не текущий элемент, а тот с которым они поменялись местами.


 
PVOzerski ©   (2002-05-23 12:57) [16]

2 Val © (23.05.02 10:40)
>идея хоршая конечно, но по чеку делфи5 по привычку щелкнул, на 7-ом паскале это делаю,

Идеей этой я сам регулярно пользуюсь, с тем различием, что в проектах, написанных
на D3, как у меня (а в D5 не должно бы возникать этой проблемы...) динамических
массивов нет, поэтому код чуть-чуть отличается:
в описании:
type
tSortAccel=array[0..0]of указатель_на_структуру;
pSortAccel=^tSortAccel;
...
var
SortAccel:pSortAccel;

Вместо SetLength(SortAccel,Count):
GetMem(SortAccel,sizeof(tSortAccel)*Count);

Вместо SetLength(SortAccel,0):
ReallocMem(SortAccel,0);

Если можно, переведите на более общепринятый язык фразу:
"но по чеку делфи5 по привычку щелкнул" - а то понять её не могу :^(


 
Val ©   (2002-05-23 13:10) [17]

>PVOzerski © (23.05.02 12:57)
Если можно, переведите ...
извиняюсь за косноязычие, этот набор слов означал: при формировании вопроса, ошибочно отметил птичкой, что я пользуюсь для решения задачи Delphi 5, хотя решаю данную задачу на Turbo Pascal 7.0.
Большое спасибо за совет. Обязательно им воспользуюсь. Но хотелось бы решить задачу и сменой элементов, уже взяло за живое, упорно что-то упускаю :(


 
Val ©   (2002-05-23 13:15) [18]

Начудил такой код, но где-то упущение :( первый элемент со вторым меняются, а дальше список состоит из нескольких экземпляров только второго элемента:
procedure SortList;
var PrevElement,BinElement: PointerToDevice;
i,j: word;
begin
for i := 0 to Count-1 do
begin
CurrentListElement := FirstListElement;
PrevElement := nil;
while CurrentListElement^.Next <> nil do
begin
if CurrentListElement^.Value.Weight > CurrentListElement^.Next^.Value.Weight then
begin
BinElement := CurrentListElement^.Next;
CurrentListElement^.Next^.Next := CurrentListElement;
CurrentListElement^.Next := BinElement^.Next;
if (PrevElement = nil) then
begin
FirstListElement := BinElement ;
PrevElement := FirstListElement;
end
else
begin
PrevElement^.Next := BinElement;
PrevElement := PrevElement^.Next;
end;
end
else
begin
PrevElement := CurrentListElement;
CurrentListElement := CurrentListElement^.Next;
end;
end;
end;
end;


 
McSimm ©   (2002-05-23 13:21) [19]

Вот, чтобы закрыть тему. Проверено:
Для Count элементов:
(добавлена оптимизация внутреннего цикла)

procedure SortList;
var i, j: Integer;
begin
for i := 1 to Count - 1 do
begin
PrevListElement := nil;
CurrentListElement := FirstListElement;
for j := 1 to Count - i do
begin
if CurrentListElement^.Value.Weight > CurrentListElement^.Next^.Value.Weight then
begin
BinElement := CurrentListElement^.Next;
CurrentListElement^.Next := BinElement^.Next;
BinElement^.Next := CurrentListElement;
CurrentListElement := BinElement;
if (PrevListElement = nil) then FirstListElement := BinElement
else PrevListElement^.Next := BinElement;
end;
PrevListElement := CurrentListElement;
CurrentListElement := CurrentListElement^.Next;
end;
end;
end;


 
Val ©   (2002-05-23 13:25) [20]

>McSimm © (23.05.02 13:21)
спасибо, работает, жаль сам не сумел :((



Страницы: 1 вся ветка

Текущий архив: 2002.06.03;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.015 c
1-7007
Dennn_is
2002-05-23 13:54
2002.06.03
Уважаемые Мастера!


1-7061
MaximatorVeter
2002-05-21 20:20
2002.06.03
Если ли что-то типа препроцессора для Delphi?


4-7272
Eugene "Jek" Efimochkin
2002-03-26 23:34
2002.06.03
Иконки в SysTray


3-6923
Oleg_er
2002-05-14 06:19
2002.06.03
Как транкзакцию организовать?


1-7040
[BAD]Angel
2002-05-21 16:05
2002.06.03
Нужна помощь с динамической загрузкой DLL