Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.11.05;
Скачать: [xml.tar.bz2];

Вниз

"Случайная" переменная?   Найти похожие ветки 

 
Palladin ©   (2006-10-19 17:15) [40]

момент истины


procedure TForm1.Button1Click(Sender: TObject);
Type
PItem=^TItem;
TItem=Record
 nID:Integer;
 strCaption:String;
End;

Var
theUnlinked,
theTree:TWRIntegerMap;
q:TADOQuery;

n,nID,nIDParent:Integer;
strCaption:String;

Function _CreateNode(p_theParent:TTreeNode;p_nID:Integer;Const p_strCaption:String):TTreeNode;
Var
 i,n:Integer;
Begin
 Result:=TreeView.Items.AddChild(p_theParent,p_strCaption);
 Result.Data:=Pointer(p_nID);
 If theUnlinked.Find(p_nID,n) Then
  Begin
   For i:=0 to TList(theUnlinked.ObjectData[n]).Count-1 Do
    Begin
     With PItem(TList(theUnlinked.ObjectData[n])[i])^ Do
      theTree.Add_Integer(nID,Integer(_CreateNode(Result,nID,strCaption)));
     Dispose(PItem(TList(theUnlinked.ObjectData[n])[i]));
    End;
   theUnlinked.Delete(n);
  End;
End;

Procedure _AddToUnlinked(p_nID,p_nIDParent:Integer;Const p_strCaption:String);
Var
 n:Integer;
 p:PItem;
Begin
 
 New(p);
 p.nID:=p_nID;
 p.strCaption:=p_strCaption;
 If Not theUnlinked.Find(p_nIDParent,n) Then n:=theUnlinked.Add_Object(p_nIDParent,TList.Create);
 TList(theUnlinked.ObjectData[n]).Add(p);
End;

begin
theTree:=TWRIntegerMap.Create;
theUnlinked:=TWRIntegerMap.Create;

q:=TADOQuery.Create(Nil);
q.Connection:=ADOConnection1;
vtQuickADOQuery(q);
q.sql.text:="select id, id_parent, caption from tree order by caption";
q.Open;
While not q.Eof Do
 Begin
  nID:=q.Fields[0].AsInteger;
  strCaption:=q.Fields[2].AsString;

  If q.Fields[1].IsNull Then theTree.Add_Integer(nID,Integer(_CreateNode(Nil,nID,strCaption))) Else
   Begin
    nIDParent:=q.Fields[1].AsInteger;
    If theTree.Find(nIDParent,n)
     Then theTree.Add_Integer(nID,Integer(_CreateNode(TTreeNode(theTree.IntegerData[n]),nI D,strCaption)))
     Else _AddToUnlinked(nID,nIDParent,strCaption);
   End;
  q.Next;
 End;
q.Close;
q.Free;
theTree.Free;
theUnlinked.Free;
end;


на все вопросы отвечу...


 
Palladin ©   (2006-10-19 17:17) [41]

это для не рекурсивного дерева, для рекурсивного немного сложней...


 
Palladin ©   (2006-10-19 17:22) [42]

краткий глоссарий

TWRIntegerMap - коллекция: ключ - данные (разных типов), с бинарным поиском

vtQuickADOQuery - всего лишь процедура выставляющая параметры исполнения TADOQuery на максимальную производительность


p.s. предполагая подобное "а если чтобы пункты нужны в определенном порядке?" сразу скажу - придирки, бо ничего сложного нет в: докрутить к вышенаписанному добавление элементов в дерево в определенном порядке...


 
Сергей М. ©   (2006-10-19 17:24) [43]


> q.sql.text:="select id, id_parent, caption from tree order  by caption"


Чтой-то вдруг именно по caption ? Зачем вообще здесь явно указанная сортировка ? Почему она не по ParentId, если уж на то пошло ?


> If q.Fields[1].IsNull Then


А если это условие ложно ? Где у тебя его обработка ?


 
Сергей М. ©   (2006-10-19 17:30) [44]


> "а если чтобы пункты нужны в определенном порядке?" сразу
> скажу - придирки


Нет, не придирки.

Это тот самый общий случай, при котором не делается никаких предположений о логическом порядке следования записей о существующих узлах в НД.

Твой код (как и авторский) отражает лишь частный случай - запись о дочернем узле (в порядке следования записей в результирующем НД) всегда ожидается позже, нежели запись о родительском узле.

В общем же случае запись о родителе не обязана фигурировать в НД раньше записи о его "чаде"


 
Palladin ©   (2006-10-19 17:30) [45]


> Чтой-то вдруг именно по caption ?

а просто так, что бы НД вернулся как в твоем примере, caption у меня там a b c d соответственно для каждой строчки, если глаза режет можешь order by убрать...


> А если это условие ложно ? Где у тебя его обработка ?

там Else в конце строки м/у прочим...


 
Palladin ©   (2006-10-19 17:31) [46]


> В общем же случае запись о родителе не обязана фигурировать в НД раньше записи о его "чаде"


а в моем примере она как раз и не обязана фигурировать раньше, разберись пжалста в коде, попробуй логику понять...


 
Palladin ©   (2006-10-19 17:34) [47]


> Нет, не придирки.


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


 
Сергей М. ©   (2006-10-19 17:35) [48]


> там Else в конце строки м/у прочим


ну и влупишь ты при этом узел в корень, ибо родитель в TreeView не найден, потому что еще не добавлен, потому что он в НД фигурирует позже добавляемого в дан.момент чада.

В чем прелесть-то - исказить реальную иерархию ?


 
Palladin ©   (2006-10-19 17:36) [49]


> Сергей М. ©   (19.10.06 17:35) [48]


ай ай ай... ну в какой же корень то? не в корень, а в theUnlinked, то бишь временное хранилище беспризорников...


 
Palladin ©   (2006-10-19 17:38) [50]


В чем прелесть-то - исказить реальную иерархию ?


в общем я смотрю ты мельком взглянул на код, подробно не разобравшись в происходящем... плохо


 
Palladin ©   (2006-10-19 17:42) [51]

вот серьезный косяк у себя нашел... строчка

theUnlinked.Delete(n);

ее нужно убрать, не нужна она.


 
Сергей М. ©   (2006-10-19 17:43) [52]


> Palladin ©   (19.10.06 17:34) [47]


вот смотри:

Было:

id, parent:

0 - Null
1 - 0

Запрос

select * from Treetable

вернет НД, по которому твой алгоритм построит совершенно корректное дерево, отражающее действительность.

Теперь я удалил запись с Id = 0 (почему я не вправе это сделать ? про нарушение целостности не будем - я админ и вправе отключить на время проверку) и вновь ее создал (в оригинальном виде).
В результате тот же запрос вернет:

id, parent:

1 - 0
0 - Null

И этот НД твой алгоритм изобразит в виде 2-ух корневых узлов , вместо того чтобы узел с Id=1 изобразить дочерним по отношению к узлу с Id = 0

Где я не прав ? Покажи ...


 
Palladin ©   (2006-10-19 17:47) [53]

нет не в виде двух узлов,
ладно: сейчас полностью откомментирую и запостю...


 
Сергей М. ©   (2006-10-19 17:53) [54]


> В результате тот же запрос вернет


Здесь - в предположении что индекс по перв.ключу при этом по каким-то причинам не использован, т.е. записи в рез. НД будут фигурировать в порядке их "физического" следования.

А если даже индекс по перв.ключу по умолчанию задействован, то ничто не мешает мне модифицировать исх.таблицу таким образом:

id, parent:

1 - 2
2 - Null

что тоже приведет к "краху" подобного алгоритма.


 
Наиль ©   (2006-10-19 17:59) [55]

Уверен, что в данном споре выиграет Palladin.
Нет ничего не возможного в том, чтобы загрузить нижний элемент, раньше верхнего.
Но спор пока вертиться вокруг дерьев.
Совсем другое дело, если база выдаст кольцо. Т.е. каждый элемент ссылается на следующий, а последний на первый.


 
Palladin ©   (2006-10-19 18:00) [56]

все комментировать не стал, только ключевые моменты

procedure TForm1.Button1Click(Sender: TObject);
Type
PItem=^TItem;
TItem=Record // описание записи для "безпризорника", дабы в TList ее хранить
nID:Integer;
strCaption:String;
End;

Var
theUnlinked, // безпризорники в виде
{
ID будущего родителя
 данные безпризорника 1
 данные безпризорника 2
как в твоем примере здесь будет содержатся
: +0
:   | 1

или как в примере выше из четырех записей
: +0
:   | 2
:   | 3
}

theTree:TWRIntegerMap; // основные данные (ключ - значение): ID записи - созданный и уже существующий TTreeNode

q:TADOQuery;

n,nID,nIDParent:Integer;
strCaption:String;

// рекурсивная функция создания TTreeNode в TTreeView"е :)
Function _CreateNode(p_theParent:TTreeNode;p_nID:Integer;Const p_strCaption:String):TTreeNode;
Var
i,n:Integer;
Begin
// создали узел
Result:=TreeView.Items.AddChild(p_theParent,p_strCaption);
Result.Data:=Pointer(p_nID);
// ищем по своему ID в списке безпризорников
If theUnlinked.Find(p_nID,n) Then
 Begin
  // нашли нашего(наших) потерявшегося (шихся)
  For i:=0 to TList(theUnlinked.ObjectData[n]).Count-1 Do
   Begin
    // добавляем каждого к себе в семью    
    With PItem(TList(theUnlinked.ObjectData[n])[i])^ Do
     theTree.Add_Integer(nID,Integer(_CreateNode(Result,nID,strCaption)));
    // удаляя запись о нем в детдоме
    Dispose(PItem(TList(theUnlinked.ObjectData[n])[i]));
   End;
 End;
End;

// процедура регистрации безпризорника в детдоме
Procedure _AddToUnlinked(p_nID,p_nIDParent:Integer;Const p_strCaption:String);
Var
n:Integer;
p:PItem;
Begin
// создаем для него в регистратуре запись
New(p);
p.nID:=p_nID;
p.strCaption:=p_strCaption;
// ищем а были ли в роддоме его сородичи по родителям
If Not theUnlinked.Find(p_nIDParent,n) Then n:=theUnlinked.Add_Object(p_nIDParent,TList.Create); // не было, ничего страшного создаем новый список братьев и сестер
TList(theUnlinked.ObjectData[n]).Add(p); // добавляем его туда
End;

begin
theTree:=TWRIntegerMap.Create;
theUnlinked:=TWRIntegerMap.Create;

q:=TADOQuery.Create(Nil);
q.Connection:=ADOConnection1;
vtQuickADOQuery(q);
q.sql.text:="select id, id_parent, caption from tree order by caption";
q.Open;
While not q.Eof Do
Begin
 nID:=q.Fields[0].AsInteger;
 strCaption:=q.Fields[2].AsString;

 If q.Fields[1].IsNull
  Then theTree.Add_Integer(nID,Integer(_CreateNode(Nil,nID,strCaption))) // еси вдруг товарисч ничей не ребенок, пихаем его в корень
  Else // иначе :)
  Begin
   nIDParent:=q.Fields[1].AsInteger;
   // пытаемся в уже существующих семьях найти родителя
   If theTree.Find(nIDParent,n)
    Then theTree.Add_Integer(nID,Integer(_CreateNode(TTreeNode(theTree.IntegerData[n]),nI  D,strCaption))) // нашли, отослали дитятко под его крыло
    Else _AddToUnlinked(nID,nIDParent,strCaption); // а иначе - определили в детдом
  End;
 q.Next;
End;
q.Close;
q.Free;
theTree.Free;
theUnlinked.Free;
end;


надеюсь так понятней...


 
Palladin ©   (2006-10-19 18:01) [57]

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


 
Сергей М. ©   (2006-10-19 18:01) [58]


> Нет ничего не возможного в том, чтобы загрузить нижний элемент,
>  раньше верхнего


При ограниченных возможностях навигации по НД (тот самый частный случай) шансы получить запись n+i (i > 0) раньше записи n оставляют желать лучшего)


 
Сергей М. ©   (2006-10-19 18:03) [59]


> база выдаст кольцо. Т.е. каждый элемент ссылается на следующий,
>  а последний на первый


Опять же - частный случай)

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


 
Palladin ©   (2006-10-19 18:22) [60]


> Сергей М. ©


ты все еще продолжаешь неверить своим глазам? хорошо

http://tiravi.narod.ru/send1.zip

компилируй, исполняй, выставляй НД как твоей душе угодно...


 
Palladin ©   (2006-10-19 18:23) [61]

правда под D6, если ее у тебя нет, то пришлю урезанные исходники dcu файлов


 
Palladin ©   (2006-10-19 18:39) [62]


> Наиль ©   (19.10.06 17:59) [55]

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


 
markers ©   (2006-10-20 01:11) [63]

не сорьтесь из-за меня!
Та поправка что была мне, благополучно поменяло ситуацию :) И вообще ИМХО енто один из самых лучших способов построить дерево с детьми! Всё работает прекрасно даже лучше чем не рекурсивный мой вариант (в другом топике опобликован, основанный на поиске родителя).


 
Сергей М. ©   (2006-10-20 08:11) [64]


> Palladin


Идея со списком "беспризорников" мне понятна. Можно, конечно, и ее реализовать, только вот вопрос об эффективности такой реализации довольно серьезен. Можно опять же говорить о частном случае, когда "двухпроходная схема" на кл.стороне (второй проход - привязка "беспризорников") будет эффективней, чем формирование нужных НД сразу на серв.стороне.



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

Форум: "Начинающим";
Текущий архив: 2006.11.05;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.59 MB
Время: 0.043 c
2-1161163863
pkm
2006-10-18 13:31
2006.11.05
Мемо.


15-1161192320
ArtemESC
2006-10-18 21:25
2006.11.05
Запутался с Реестром Far a...


15-1160814051
*Стажер*
2006-10-14 12:20
2006.11.05
История Делфи


2-1161087371
Svetlena
2006-10-17 16:16
2006.11.05
Dos


11-1137519814
Vladimir Kladov
2006-01-17 20:43
2006.11.05
ProjMover





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский