现在我有一个数据库Test
表结构和数据如入:
ID     Name    ParentID
1      中国人  00000000
2      浙江人  1
3      湖北人  1
4      杭州人  2
5      绍兴人  2
6      武汉人  3
7      荆门人  3
8      美国人  00000000
9      纽约人  8
10     华盛顿人8
11     曼哈顿人9
现在要根据他们的ID和ParentID的关系加载到树中,呈现层次关系请问有没有好的算法,不要用到TreeView的SelectChange事件,要求一次性加载。
高手帮忙啊!

解决方案 »

  1.   

    快速创建树的方法 (抛弃拙劣的数据库结构和算法)1、现在很多人都使用“父-子结构+递归算法”来显示树型的层次结构,但是不得不说这是一种非常拙劣的方式,下面给大家一种简单方便的数据结构和算法,快速显示树型的层次结构:
    2、数据库结构
    例如表“国家”可以是这样:
    编号      名称
    ----------
    01        中国
    0101      吉林省
    010101    长春市
    010102    吉林市
    0102      江苏省
    010201    南京市
    010202    常州市
    02        美国
    0201      密歇根州
    020101    底特律市
    0202      华盛顿州
    020201    温哥华市
    020202    西雅图市
    03        澳大利亚
    3、在 TreeView 中显示结构
    procedure CreateTree;
    const
      ID_DEPT = 2;
    var
      nLevel: Integer;
      pNodes: array[0..1023] of TTreeNode;
      lpID, lpName: string;
    begin
      ADODataSet1.Close;
      ADODataSet1.CommandText := 'SELECT * FROM [国家] ORDER BY [编号]';
      ADODataSet1.Open;
      pNodes[0] := nil;
      TreeView1.Items.Clear;
      with ADODataSet1.Recordset do
        while not Eof do
        begin
          lpID := Fields['编号'].Value;
          lpName := Fields['名称'].Value;
          nLevel := Length(lpID) div ID_DEPT;
          pNodes[nLevel] := TreeView1.Items.AddChild(pNodes[nLevel - 1], lpName);
          MoveNext;
        end;
    end;
    4、短短 20 行,一次读取数据。有人可能问为什么把 pNodes 的大小设成 1024?你也可以设成 10000,随你便,不过 TreeView 如果有那么多节点早死机了。
      

  2.   

    树的快速创建算法,只需读一次数据库.unit U_CreateTree;interfaceuses
      Classes, ComCtrls, ADODB, SysUtils;type
      PPNodedata=^TNodeData;
      TNodeData = record
        ID:integer;//节点编号
        PID:Integer;//父节点编号
        Name:string;//节点名称
        child:PPNodedata;//孩子节点
        brather:PPNodedata;//兄弟节点
      end;
      PNodeData = PPNodeData;
      TTreeFill1 = class(TThread)
        TV: TTreeView;
        RootID:Integer;
        ptr:PPNodeData;
        root:PPNodeData;//根节点
        PointNode:PPNodeData;
        s:array[0..10000] of PPNodeData;
       constructor Create(Root_Id:integer;ATreeView: TTreeView);
      private
        procedure AddTree(Node: TTreeNode; PN: PNodeData);
      protected
        procedure Execute; override;
      end;implementationuses
      U_Main, DateUtils;var count,nodeCount:Integer;
    //----------
    constructor TTreeFill1.Create(Root_Id:integer;ATreeView:TTreeView);
    begin
      TV:= ATreeView;
      TV.Items.Clear;
      RootID:=Root_Id;
      inherited Create(False);
    end;
    //----------
    procedure TTreeFill1.Execute;
    var Query: TADOQuery;
        i,j:Integer;
        Node: TTreeNode;
    begin
      FreeOnTerminate := True;
      TV.Items.Clear;
      with Query do
        begin
          Query := TADOQuery.Create(nil);
          Connection := frm_Main.ADOC_SQL;//需要更改
          Close;
          SQL.Clear;
          SQL.Add('Select * from 部门表 order by 部门编号 ');
          Open;
          first;
          count:=recordcount;
          if count>0 then
            begin
              for i:=0 to recordcount-1 do
              begin
              new(PointNode);
              PointNode^.child:=nil;
              PointNode.brather:=nil;
              PointNode^.ID:=fieldbyname('部门编号').AsInteger;
              PointNode^.PID:=fieldbyname('父部门编号').AsInteger;
              PointNode^.Name:=fieldbyname('部门名称').AsString;
              s[i]:= PointNode;
              next;
              end;
            end;
          free;
        end;
    //------创建树----------
    for i:=0 to count-1 do
      begin
        for j:=0 to count-1 do
         if s[i]^.PID=s[j]^.ID then
           begin
             if s[j]^.child=nil then
              s[j]^.child:=s[i]
             else
              begin
              ptr:= s[j]^.child;
              while (ptr.brather<>nil) do
              ptr:=ptr^.brather;
              ptr.brather:=s[i];
              end;
            end;
      end;
      for i:=0 to count-1 do
        if s[i]^.ID=RootID then
        begin
          root:=s[i]; //根节点
          break;
        end;
      Node:=TV.Items.AddObject(nil,Root^.Name,Root);//创建树的根节点
      nodeCount:=0; 
      Node.ImageIndex := 0;
      Node.SelectedIndex := 2;
      AddTree(Node,root);
    end;procedure TTreeFill1.AddTree(Node:TTreeNode;PN:PNodeData);
    var
       nNode: TTreeNode;
       PNode,q: PNodeData;
    begin
    PNode:=PN;
    if PNode.child<>nil then
      begin
         q:=PNode.child;
         while (q<>nil) do
          begin
           nNode:=TV.Items.AddchildObject(Node,q^.Name,q);
           nodeCount:=nodeCount+1;
           AddTree(nNode,q);
           q:=q^.brather;
          end;
      end;
    end;end.
      

  3.   

    1,数据如下:
    ModuleCode                               ModuleName                               ModuleLevel 
    ---------------------------------------- ---------------------------------------- ----------- 
    11                                       系统维护                                     1
    21                                       基础资料                                     1
    31                                       采购管理                                     1
    31-31                                    采购收货单                                    2
    31-31-101                                采购收货单-开单                                 3
    31-31-102                                采购收货单-修改                                 3
    31-31-103                                采购收货单-删除                                 3
    31-41                                    采购付款单                                    2
    31-41-101                                采购付款单-开单                                 3
    31-41-102                                采购付款单-修改                                 3
    31-41-103                                采购付款单-删除                                 3
    31-51                                    采购退货单                                    2
    31-51-101                                采购退货单-开单                                 3
    31-51-102                                采购退货单-修改                                 3
    31-51-103                                采购退货单-删除                                 3
    32                                       销售管理                                     1
    {******************************************************************************}
    --模块编码
    2 SQL 语句如下,注意 ORDER BY ModuleCode
    SELECT ModuleCode,ModuleName,ModuleLevel FROM SB_Modules ORDER BY ModuleCode
    /*
    SELECT ModuleCode,ModuleName,LeafModuleSign,ParentModuleCode,ModuleLevel FROM SB_Modules ORDER BY ModuleCode
    */
    {******************************************************************************}3,代码如下procedure TfrmPurviewAssign.BuildCheckTree(pDataSet:TDataSet);
    var
      iLevel:Integer;
      sCode,sName:string;
      MyNode:array[0..10]of TTreeNode;//保存各级节点,最长支持 10 级(重点)
    begin
      Screen.Cursor:=crHourGlass;
      ckTreePurview.Items.Clear;
      //FIDList.Clear;
      with pDataSet do
      begin
        First;
        //以上是增加第一项
        while not Eof do
        begin
          sCode:=Trim(FieldByName(Purviews.FModuleCode_FieldName).AsString);
          sName:=Trim(FieldByName(Purviews.FModuleName_FieldName).AsString);
          iLevel:=FieldByName(Purviews.FModuleLevel_FieldName).AsInteger;
          if iLevel=1 then//确保代码符合标准
          begin
            MyNode[iLevel]:=ckTreePurview.Items.AddChild(nil,sName);
          end
          else
          begin
            MyNode[iLevel]:=ckTreePurview.Items.AddChild(MyNode[iLevel-1],sName);
          end;
          //MyNode[iLevel].ImageIndex:=iLevel;
          //MyNode[iLevel].SelectedIndex:=iLevel-1;
          Next;
        end;
        First;
      end;
      Screen.Cursor:=crDefault;
    end;
      

  4.   

    如果不是在TreeVIEW使用,而要在LISTVIEW实现这种树形结构,算法就不是这样的了!
    但,可以说的是,先确定数据各据的LEVEL是算法的重点!