English 中文(简体)
类似树木的数据结构(用于虚拟普查)
原标题:Tree-like Datastructure (for use with VirtualTreeview)

I have come to the point where I need to stop storing my data in a VCL component, and have an "underlying datastructure", as Mr. Rob Kennedy suggested.

首先,这个问题涉及“我如何构建一个基本的数据结构”。

我的希拉底由两层 no子组成。

现在,我穿着根).子,在我 lo着根子,让孩子们获得我所需要的东西。 我会热衷于把我的所有数据储存在所谓的附属数据结构中,以便我能够方便地利用透镜修改条目(我相信我能够这样做吗?)

然而,在通过我的条目(现在的右边)时,结果取决于底部——如果我使用一个基本的数据结构,我如何知道,在我的数据结构I loop thru时,我不知道我的名字是否受到检查?

我要说的是,我要使用2个等级。

父母是:

TRoot = Record
  RootName : String;
  RootId : Integer;
  Kids : TList; //(of TKid)
End;

并且:

TKid = Record
  KidName : String;
  KidId : Integer;
End;

这基本上是我现在做的事。 评论说,这不是最佳解决办法,因此,我愿意提出建议。

我希望你理解我的问题:

感谢!

最佳回答

The data structure you re requesting is very simple, it s so simple I d recommend using the windows-provided TTreeView: it allows storing the text and an ID straight into the tree s node with no additional work.


尽管我建议使用更简单的<代码> TTreeView 我要谈谈数据结构问题。 首先,将使用,,而不是records。 在你非常简短的法典中,你以非常不舒服的方式重新组合记录和课程: 当您提供<代码>TRoot记录(由于记录被视为“价值”)时,您不再提供树木的“完整副本”: <代码>TRoot的全文将包含相同的<代码>Kids:TList,作为原文,因为各班次,与记录不同,都是参考资料:你重新处理参考值。

还有一个问题,是生命周期管理: 页: 1 因此,你需要一个其他机制来释放所有物体(Kids:TList)。 你可以将改为array of Tkid,但是,在通过mon记录时,你必须小心谨慎,因为如果你最不期望的话,你可能最终将大量记录复制。

我认为,最谨慎的做法是,把数据结构建立在states之上,而不是记录:分类案例(目标)作为参考文件通过,因此,你可以把这些数据推向你们所有希望,而没有任何问题。 您还得到了生活周期的内在管理(destructor)。

基地阶级愿意这样做。 阁下注意到,这可以用作根基或基基,因为根基和基基都分享数据: 两人的姓名和身份证:

TNodeClass = class
public
  Name: string;
  ID: Integer;
end;

如果这一类别被用作根基,它需要一种储存孩子的办法。 我假设你在德尔菲·2010+上重新发言,因此你具有通用性。 这一类别加上一个清单,即:

type
  TNode = class
  public
    ID: integer;
    Name: string;
    VTNode: PVirtualNode;
    Sub: TObjectList<TNode>;

    constructor Create(aName: string =   ; anID: integer = 0);
    destructor Destroy; override;
  end;

constructor TNode.Create(aName:string; anID: Integer);
begin
  Name := aName;
  ID := anID;

  Sub := TObjectList<TNode>.Create;
end;

destructor TNode.Destroy;
begin
  Sub.Free;
end;

You might not immediately realize this, but this class alone is enough to implement a multi-level tree! Here s some code to fill up the tree with some data:

Root := TNode.Create;

// Create the Contacts leaf
Root.Sub.Add(TNode.Create( Contacts , -1));
// Add some contacts
Root.Sub[0].Sub.Add(TNode.Create( Abraham , 1));
Root.Sub[0].Sub.Add(TNode.Create( Lincoln , 2));

// Create the "Recent Calls" leaf
Root.Sub.Add(TNode.Create( Recent Calls , -1));
// Add some recent calls
Root.Sub[1].Sub.Add(TNode.Create( +00 (000) 00.00.00 , 3));
Root.Sub[1].Sub.Add(TNode.Create( +00 (001) 12.34.56 , 4));

你们需要一种回收程序,以利用这种类型来填补虚拟树情:

procedure TForm1.AddNodestoTree(ParentNode: PVirtualNode; Node: TNode);
var SubNode: TNode;
    ThisNode: PVirtualNode;

begin
  ThisNode := VT.AddChild(ParentNode, Node); // This call adds a new TVirtualNode to the VT, and saves "Node" as the payload

  Node.VTNode := ThisNode; // Save the PVirtualNode for future reference. This is only an example,
                           // the same TNode might be registered multiple times in the same VT,
                           // so it would be associated with multiple PVirtualNode s.

  for SubNode in Node.Sub do
    AddNodestoTree(ThisNode, SubNode);
end;

// And start processing like this:
VT.NodeDataSize := SizeOf(Pointer); // Make sure we specify the size of the node s payload.
                                    // A variable holding an object reference in Delphi is actually
                                    // a pointer, so the node needs enough space to hold 1 pointer.
AddNodesToTree(nil, Root);

When using objects, different nodes in your Virtual Tree may have different types of objects associated with them. In our example we re only adding nodes of TNode type, but in the real world you might have nodes of types TContact, TContactCategory, TRecentCall, all in one VT. You ll use the is operator to check the actual type of the object in the VT node like this:

procedure TForm1.VTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var PayloadObject:TObject;
    Node: TNode;
    Contact : TContact;      
    ContactCategory : TContactCategory;
begin
  PayloadObject := TObject(VT.GetNodeData(Node)^); // Extract the payload of the node as a TObject so
                                                   // we can check it s type before proceeding.
  if not Assigned(PayloadObject) then
    CellText :=  Bug: Node payload not assigned 
  else if PayloadObject is TNode then
    begin
      Node := TNode(PayloadObject); // We know it s a TNode, assign it to the proper var so we can easily work with it
      CellText := Node.Name;
    end
  else if PayloadObject is TContact then
    begin
      Contact := TContact(PayloadObject);
      CellText := Contact.FirstName +     + Contact.LastName +   (  + Contact.PhoneNumber +  ) ;
    end
  else if PayloadObject is TContactCategory then
    begin
      ContactCategory := TContactCategory(PayloadObject);
      CellText := ContactCategory.CategoryName +   (  + IntToStr(ContactCategory.Contacts.Count) +   contacts) ;
    end
  else
    CellText :=  Bug: don  t know how to extract CellText from   + PayloadObject.ClassName;
end;

这里就是一个例子,说明为什么要把虚拟诺德点放在你的 no子上:

procedure TForm1.ButtonModifyClick(Sender: TObject);
begin
  Root.Sub[0].Sub[0].Name :=  Someone else ; // I ll modify the node itself
  VT.InvalidateNode(Root.Sub[0].Sub[0].VTNode); // and invalidate the tree; when displayed again, it will
                                                // show the updated text.
end;

你们知道,在简单的树木数据结构方面有一个工作榜样。 你需要“浏览”这一数据结构,以适应你们的需要:可能性是无限的! 给你一些想法,指示探讨:

  • You can turn the Name:string into a virtual method GetText:string;virtual and then create specialized descendants of TNode that override GetText to provide specialized behavior.
  • Create a TNode.AddPath(Path:string; ID:Integer) that allows you to do Root.AddPath( ContactsAbraham , 1); - that is, a method that automatically creates all intermediary nodes to the final node, to allow easy creation of the tree.
  • Include an PVirtualNode into TNode itself so you can check rather the Node is "checked" in the Virtual Tree. This would be a bridge of the data-GUI separation.
问题回答

我认为,最好能找到一个现有的图书馆,包括一个全面的树木执行,然后可以重新使用,满足你们的需要。

为了给你一个想法,我写道,在这里是一些法典,说明最简单的树种结构是可想象的。

type
  TNode = class
    Parent: TNode;
    NextSibling: TNode;
    FirstChild: TNode;
  end;

  TTree = class
    Root: TNode;
    function AddNode(Parent: TNode): TNode;
  end;

function TTree.AddNode(Parent: TNode);
var
  Node: TNode;
begin
  Result := TNode.Create;

  Result.Parent := Parent;
  Result.NextSibling := nil;
  Result.FirstChild := nil;

  //this may be the first node in the tree
  if not Assigned(Root) then begin
    Assert(not Assigned(Parent));
    Root := Result;
    exit;
  end;

  //this may be the first child of this parent
  if Assigned(Parent) and not Assigned(Parent.FirstChild) then begin
    Parent.FirstChild := Result;
  end;

  //find the previous sibling and assign its next sibling to the new node
  if Assigned(Parent) then begin
    Node := Parent.FirstChild;
  end else begin
    Node := Root;
  end;
  if Assigned(Node) then begin
    while Assigned(Node.NextSibling) do begin
      Node := Node.NextSibling;
    end;
    Node.NextSibling := Result;
  end;
end;

<><><>>说明:我没有测试该守则,因此无法证明其正确性。 我期望它有缺陷。

所有这一切都给树木增添了新的 no子。 它使你无法控制树 no的生长地点。 如果只是增加一个新 no子,作为特定母子最后的兄弟姐妹。

采取这种方式,你很可能需要处理:

  • Inserting after a specified sibling. Actually this is quite a simple variant of the above.
  • Removing a node. This is somewhat more complex.
  • Moving existing nodes within the tree.
  • Walking the tree.
  • Connecting the tree to your VST.

这样做当然是可行的,但可以更好地建议你找到已经落实这一功能的第三党图书馆。

我询问了类似的问题:here。 我没有回答任何有用的答案,因此我决定自行执行,你可以找到here

EDIT: I ll try to post example how you could use my data structure:

uses
  svCollections.GenericTrees;

2. 申报数据类型:

type
  TMainData = record
    Name: string;
    ID: Integer;
  end;

Declare your main data tree object somewhere in your code:

MyTree: TSVTree<TMainData>;

建立这一机制(并且不会忘记以后自由):

MyTree: TSVTree<TMainData>.Create(False);

签名 2. 树给我们的数据结构:

MyTree.VirtualTree := VST;

之后,你可以将数据树与一些价值观混为一谈:

procedure TForm1.BuildStructure(Count: Integer);
var
  i, j: Integer;
  svNode, svNode2: TSVTreeNode<TMainData>;
  Data: TMainData;
begin
  MyTree.BeginUpdate;
  try
    for i := 0 to Count - 1 do
    begin
      Data.Name := Format( Root %D , [i]);
      Data.ID := i;
      svNode := MyTree.AddChild(nil, Data);
      for j:= 0 to 10 - 1 do
      begin
        Data.Name := Format( Child %D , [j]);
        Data.ID := j;
        svNode2 := MyTree.AddChild(svNode, Data);
      end;
    end;
  finally
    MyTree.EndUpdate;
  end;
end;

• 举办专业考试和测验活动,展示你的数据:

procedure TForm1.vt1InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
  var ChildCount: Cardinal);
var
  svNode: TSVTreeNode<TMainData>;
begin
  svNode := MyTree.GetNode(Sender.GenerateIndex(Node));
  if Assigned(svNode) then
  begin
    ChildCount := svNode.FChildCount;
  end;
end;

procedure TForm1.vt1InitNode(Sender: TBaseVirtualTree; ParentNode,
  Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var
  svNode: TSVTreeNode<TMainData>;
begin
  svNode := MyTree.GetNode(Sender.GenerateIndex(Node));
  if Assigned(svNode) then
  begin
    //if TSVTree<TTestas> is synced with Virtual Treeview and we are building tree by
    // setting RootNodeCount, then we must set svNode.FVirtualNode := Node to
    // have correct node references
    svNode.FVirtualNode := Node;  // Don t Forget!!!!
    if svNode.HasChildren then
    begin
      Include(InitialStates, ivsHasChildren);
    end;
  end;
end;

//display info how you like, I simply get name and ID values
procedure TForm1.vt1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  svNode: TSVTreeNode<TMainData>;
begin
  svNode := MyTree.GetNode(Sender.GenerateIndex(Node));
  if Assigned(svNode) then
  begin
    CellText := Format( %S ID:%D ,[svNode.FValue.Name, svNode.FValue.ID]);
  end;
end;

此时,你只与你的MyTree数据结构合作,对数据所作的所有改动将反映在你所指定的VST中。 那么,你总是能够将(和负荷)基本结构用于上游或档案。 希望这一帮助。

德尔菲具有通用性。 我刚刚发明了一个非常冰树数据结构。 不久的将来,尽管还有其他原因,但“角逐”并没有取消,实际上不是开放源的人。

但是,我要谈谈如何重新调整:

假设你们所有节点都包含同样的数据结构(从上看,似乎就是这样,是插手、id,然后是链接)。

您需要重新确定的内容如下:

  1. Generics
  2. A generic type T
  3. This type T needs to be constrained to class and constructor as follows:

<T : 班、建筑和建筑; (在您的案例中,以记录、未经测试的类别替换,但也可使用)

  1. 两个领域:自行(hint hint),数据: T;

  2. 财产

  3. (a) 不仅属于任何适当情况,而且属于违约财产;

  4. 一辆面包车。

  5. 一个具有深度和儿童性的修复建筑商。

  6. 有些人说要停止施工。

  7. 以及“SetaLength”理论,以建立链接/点,呼吁某些人为 lo,然后对一些东西进行某种冲淡。

鉴于你们的背后,如果有人能够重新收留,那将是令人不快和感兴趣的,否则,我可能仅仅对它提出专利,而只是dding,而不是花钱向它投放钱,可能扩大这一类别,与其他设施相比。

这些班级在施工期间分配所有节点,如真正的数据结构......指出并删除,至少是现在。

现在是这一(秘密)设计中最令人感兴趣和最棘手的方面,我想要的是,现在已成为现实。 我现在可以撰写如下的法典:

TGroup is just an example can be anything as long as it s a class in my case. In this case it s just a class with mString

var
  mGroupTree : TTree<TGroup>;

procedure Main;
var
  Depth : integer;
  Childs : integer;
begin

  Depth := 2;
  Childs := 3;

  mGroupTree := TTree<TGroup>.Create( Depth, Childs );

  mGroupTree.Data.mString :=  Basket ; // notice how nice this root is ! ;)

  mGroupTree[0].Data.mString :=  Apples ;
  mGroupTree[1].Data.mString :=  Oranges ;
  mGroupTree[2].Data.mString :=  Bananas ;

  mGroupTree[0][0].Data.mString :=  Bad apple ;
  mGroupTree[0][1].Data.mString :=  Average apple ;
  mGroupTree[0][2].Data.mString :=  Good apple ;

  mGroupTree[1][0].Data.mString :=  Tiny orange ;
  mGroupTree[1][1].Data.mString :=  Medium orange ;
  mGroupTree[1][2].Data.mString :=  Big orange ;

  mGroupTree[2][0].Data.mString :=  Straight banana ;
  mGroupTree[2][1].Data.mString :=  Curved banana ;
  mGroupTree[2][2].Data.mString :=  Crooked banana ;

现在请各位注意actual 测试守则是,它允许像我很少看到的那样“扩大档案”,因为这种财产是自我参照的。

So [] [] is depth 2. [][][] would be depth 3.

我仍在评估这方面的使用情况。

一个潜在的问题是,Delphi没有实现这些阵列的自动化的真正技术,尽管我尚未发现并且已经证实。

我喜欢一种方法,即我可以撰写一些可以深入到任何程度的法典:

[0][0][0][0]

尚未确定如何做到......简单排除选择是“入侵”。

real 例如:

procedure DisplayString( Depth : string; ParaTree : TTree<TGroup>);
var
  vIndex : integer;
begin
  if ParaTree <> nil then
  begin
//    if ParaTree.Data.mString <>    then
    begin
      writeln( ParaTree.Data.mString );

      Depth := Depth +    ;
      for vIndex := 0 to ParaTree.Childs-1 do
      begin
        DisplayString( Depth, ParaTree[vIndex] );
      end;
    end;
  end;
end;

页: 1

仍在探讨它对于“真实应用”的有用性,如果我想要再次入侵或不入侵的话;

也许有一天,我将开放我的所有法典。 我将近40岁,当时我已经超过40岁,从39岁到40岁,我计划开放。 距40=D还有4个月

(我必须说,这是我第一次对通用名词印象深刻,很久以前测试过,当时是多余的,或许是无法设计的,但现在有固定和有限的通用物,在最新的Delphi Toyko 10.2.3版本中,大概是2018年!)

我只是对最先进的德尔菲技术所无法做到的表面表示赞扬,可能采用匿名方法撰写复习例行公事,处理这一数据结构可能变得比以往容易,而且可能会同时进行处理,德尔菲有助于为匿名方法提及这一点。

Bye, Skybuck.





相关问题
determining the character set to use

my delphi 2009 app has a basic translation system that uses GNUGetText. i had used some win API calls to prepare the fonts. i thought it was working correctly until recently when someone from Malta ...

Help with strange Delphi 5 IDE problems

Ok, I m going nuts here. For the last (almost) four years, I ve been putting up with some extremely bad behavior from my Delphi 5 IDE. Problems include: Seemingly random errors in coride50.bpl ...

How to write a Remote DataModule to run on a linux server?

i would like to know if there are any solution to do this. Does anyone? The big picture: I want to access data over the web, using my delphi thin clients. But i´would like to keep my server/service ...

How convert string to integer in Oxygene

In Delphi, there is a function StrToInt() that converts a string to an integer value; there is also IntToStr(), which does the reverse. These functions doesn t appear to be part of Oxygene, and I can ...

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签