方法一:delphi中递归算法构建treeView

过程:

通过读取数据库中table1的数据,来构建一颗树。table1有两个字段:ID,preID,即当前结点标志和父结点标志。所以整个树的表示为父母表示法。本递归算法不难写,但是要注意:程序内部的变量都应使用局部变量!比如当Query是外部变量(函数外定义或者直接通过控件拖拽得来)时就会得到错误的结果。代码如下:

 

unit Unit1;

interface

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, DB, ADODB, ComCtrls, StdCtrls;

type

  TForm1 = class(TForm)

    Button1: TButton;

    tree: TTreeView;

    Query1: TADOQuery;

    procedure Button1Click(Sender: TObject);

    procedure CreateTree;

  private

    { Private declarations }

  public

    { Public declarations }

  end;

  PTNodeInfo=^TNodeInfo;

  TNodeInfo=record

   id,preId:string;

   end;

var

  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.CreateTree;

  procedure CreateTree(Pre:string;preNode:TTreeNode);

  var

    pInfo:PTNodeInfo;

    node:TTreeNode;

    sql:string;

    Query:TADOQUery;

  begin

    Query:=TADOQuery.Create(nil);

    Query.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:/实验/递归父母表示/新建 Microsoft Office Access 应用程序.mdb;Persist Security Info=False';

    sql:= Format('select * from table1 where preId=%s', [QuotedStr(pre)]);

    Query.Close;

    Query.SQL.Clear;

    Query.SQL.Add(sql);

    Query.Open;

    Query.First;

    while not Query.Eof do

    begin

      new(pInfo);

      pInfo.id:=Query.Fields[0].AsString;

      pInfo.preId:=Query.Fields[1].AsString;

      node:=tree.Items.AddChild(preNode,pInfo.id);

      node.Data:=pInfo;

      CreateTree(pInfo.id,node);

      Query.Next;

    end;

    Query.Close;

    Query.Free;

  end;

begin

  createTree('000',nil);

  tree.FullExpand;

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

  createtree;

end;

end.

 

createTree函数也可以这么写:

procedure TForm1.CreateTree;

var

  p:pTNodeInfo;

  procedure CreateTree(Pre:PTNodeInfo;preNode:TTreeNode);

  var

    pInfo:pTNodeInfo;

    node:TTreeNode;

    sql:string;

    Query:TADOQuery;

  begin

    Query:=TADOQuery.Create(nil);

    Query.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:/实验/递归父母表示/新建 Microsoft Office Access 应用程序.mdb;Persist Security Info=False';

    sql:= 'select * from table1';

    Query.Close;

    Query.SQL.Clear;

    Query.SQL.Add(sql);

    Query.Open;

    Query.First;

    while not Query.Eof do

    begin

      new(pInfo);

      pInfo.id:=Query.Fields[0].AsString;

      pInfo.preId:=Query.Fields[1].AsString;

      if pInfo.preId=pre.id then

      begin

        node:=tree.Items.AddChild(preNode,pInfo.id);

        node.Data:=pInfo;

        CreateTree(pInfo,node);

      end;

      Query.Next;

    end;

  end;

begin

  new(p);

  p.id:='000';

  createTree(p,nil);

  tree.FullExpand;

end;

方法二://数据采用ADOQuery读取,并将数据暂存在一个动态数组中,树形列表控件为TreeView。 

procedure TForm1.LoadTreeInfo; 

type 

  TInfo = record 

    ID,      //代码       

    Name,    //名称 

    SuperID  //上级代码              

      : string; 

    //附加字段随需添加 

  end; 

var 

  sql: string; 

  i, nCount: Integer; 

  arrInfo: array of TInfo; 

  NewNode: TTreeNode; 

  //加载一个节点 

  procedure InitOneNode(ANode: TTreeNode; AId: string); 

  var 

    k: Integer; 

  begin 

    for k := 0 to length(arrInfo) - 1 do 

      if arrInfo[k].SuperID = AId then 

      begin 

        NewNode := TreeView1.Items.AddChild(ANode, arrInfo[k].Name); 

        InitOneNode(NewNode, arrInfo[k].ID); 

      end; 

  end; 

begin 

  TreeView1.Items.BeginUpdate; 

  TreeView1.Items.Clear; 

  sql := 'select ID, Name, SuperID from DictionaryTable order by ID'; 

  ADOQuery1.Close; 

  ADOQuery1.SQL.Text := sql; 

  ADOQuery1.Open; 

  nCount := ADOQuery1.RecordCount; 

  if nCount > 0 then 

  begin 

    SetLength(arrInfo, nCount); 

    for i := 0 to nCount - 1 do 

      with arrInfo[i] do 

      begin 

        ID := Trim(ADOQuery1.FieldByName('ID').AsString); 

        Name := Trim(ADOQuery1.FieldByName('Name').AsString); 

        SuperID := Trim(ADOQuery1.FieldByName('SuperID').AsString);  //无没有此字段,可根据上下级编码规则赋值 

        ADOQuery1.Next; 

      end; 

  end; 

  ADOQuery1.Close; 

  if nCount > 0 then 

  begin 

    InitOneNode(nil, '');  //假设顶级代码为空白 

    TreeView1.FullExpand; 

    TreeView1.Items.EndUpdate; 

  end; 

end; 

 

 

方法三: 此方法是第一种方法的变种,凡是有已经添加节点的,删除。

在数据库中建一张表,包含:NodeName,NodeId,ParentId 3个字段,具体什么含义,一看就知了。

过程如下:

procedure TFRM_channel.formtreenode(parentid:string;TreeView1: TTreeView;parentnode:TTreeNode;ADOQuery1:TADOQuery);

var

    i:integer;

    treenode:TTreeNode;

begin

    i:=0;

    ADOQuery1.First;

    while not ADOQuery1.Eof do

      begin

         if ADOQuery1.FieldByName('ParentId').AsString=parentid then

           begin

              treenode:=TreeView1.Items.AddChild(parentnode,ADOQuery1.fieldbyname('NodeName').AsString);

              formtreenode(ADOQuery1.fieldbyname('NodeId').AsString ,TreeView1,treenode,ADOQuery1);

           end;

          inc(i);

          ADOQuery1.First;

          ADOQuery1.MoveBy(i);

      end;

end;

在调用如下,如在窗体的create事件中:

procedure TFRM_channel.FormCreate(Sender: TObject);

var

  TreeNode1:TTreeNode;

  i:integer;

  nodename:string;

  nodeid:string;

  parentid:string;

  cmdstr:string;

begin

//初始化树形节点

   ADOQuery1.ConnectionString:=mypublic.datastr;

   cmdstr:='select * from ChanTreeNode order by ParentId ,NodeId asc';

   ADOQuery1.Close;

   ADOQuery1.SQL.Clear;

   ADOQuery1.SQL.Add(cmdstr);

   ADOQuery1.Open;

       TreeNode1:=nil;

     formtreenode('000',TreeView1,TreeNode1,ADOQuery1);

end;

方法四:用一个排序的TStringList列表,通过排序列表采用二分查找的快速性能,就能够很快地查找到当前要添加节点的父节点,从而插入到 TreeView树的正确位置。

根据数据表的内容生成TreeView树状结构,通常的做法就是从顶级开始,然后逐项递归查询遍历生成。这种方法在实现上容易做到,也很容易想到,但是效率比较低,因为数据库的检索(SQL语句需要解释执行,而且是对数据库文件进行操作)还是比较耗时的,尤其是树的层次较多,节点较多的情况。这里我要介绍的方法是以空间换取时间,只进行一次数据库检索,提取出全部数据,然后一次生成TreeView树状结构。通过SQL语句,让返回的记录按照父节点ID、节点ID进行排序,这样保证每次当前要添加的节点记录的父节点都已经添加到了TreeView树中,剩下的工作就是如何在TreeView树中找到父节点。这里我采用了一个排序的TStringList列表,通过排序列表采用二分查找的快速性能,就能够很快地查找到当前要添加节点的父节点,从而插入到 TreeView树的正确位置。

源代码如下(假定数据表名称为FTree,字段有ID, ParentID, Name):

procedure MakeTree(Query: TQuery; TreeView: TTreeView);

var

  List: TStringList;

  Node: TTreeNode;

  Index: Integer;

begin

  TreeView.Items.BeginUpdate;

  try

    TreeView.Items.Clear;

    List := TStringList.Create;

    try

      List.Sorted := True;

      while not Query.Eof do

      begin

        if Query.FieldByName('ParentID').AsInteger = 0 then { ParentID=0,顶层节点 }

          Node := TreeView.Items.AddChild(nil, Query.FieldByName('Name').AsString)

        else

        begin

          Index := List.IndexOf(Query.FieldByName('ParentID').AsString);

          Node := TreeView.Items.AddChild(TTreeNode(List.Objects[Index]),

            Query.FieldByName('Name').AsString);

        end;

        List.AddObject(Query.FieldByName('ID').AsString, Node);

        Query.Next;

      end;

    finally

      List.Free;

    end;

  finally

    TreeView.Items.EndUpdate;

  end;

end;

procedure TForm1.Button1Click(Sender: TObject);

var

  T: DWORD;

begin

  T := GetTickCount;

  Query1.SQL.Text := 'SELECT * FROM FTree ORDER BY ParentID, ID';

  Query1.Open;

  MakeTree(Query1, TreeView1);

  Label1.Caption := Format('MakeTree所用时间: %d ms', [GetTickCount - T]); 

end; 

==============================================================================

unit Unit1;

interface

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, DB, ADODB;

type

  PTNode=^TNode;

  TNode=record

  id:string;

  fID,nID:string;

  hasCreate:boolean;

  fChild:PTNode;

  nSibling:PTNode;

end;

type

  TArr=array of TNode;

type

  TTree=class(TObject)

  root,cur:PTNode;

  constructor create; overload;

  constructor create(var arr:TArr); overload;

  function FindNode(s:string;p:PTNode):boolean;

end;

type

  TForm1 = class(TForm)

    Button1: TButton;

    conn: TADOConnection;

    Query: TADOQuery;

    Memo1: TMemo;

    procedure DisPlayFChild(p:PTNode);

    procedure LoadData(var arr:Tarr);

    function  GetNode(var arr:Tarr;s:string):PTNode;

    procedure Button1Click(Sender: TObject);

   

  private

    { Private declarations }

  public

    { Public declarations }

  end;

var

  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.displayFChild(p:PTnode);

begin

  if p.fChild<>nil then begin memo1.Lines.Add(p.fchild.id); end;

end;

function TTree.FindNode(s:string;p:PTNode):boolean;

var

  pn:PTNode;

begin

  result:=false;

  if p.id=s then

    begin

      result:=true;

      cur:=p;

      exit;

    end;

  pn:=p.fChild;

  while ((pn<>nil)and (FindNode(s,pn)=false)) do

    begin

      pn:=pn.nSibling;

    end;

end;

function  TForm1.GetNode(var arr:Tarr;s:string):PTNode;

var

i,n:integer;

begin

  result:=nil;

  n:=Length(arr);

  for i:=0 to n-1 do

  begin

    if (arr[i].id=s)  then

    begin result:=@arr[i]; exit; end;

  end;

end;

procedure TForm1.LoadData(var arr:TArr);              //load data from database

var

i:integer;

begin

  Query.Close;

  Query.SQL.Clear;

  Query.SQL.Add('select * from table2');

  Query.Open;

  Query.First;

  i:=Query.RecordCount;

  setLength(arr,i);

  i:=0;

  while not Query.Eof  do

  begin

    arr[i].id:=Query.Fields[0].AsString;

    arr[i].fID:=Query.Fields[1].AsString;

    arr[i].nID:=Query.Fields[2].AsString;

    arr[i].hasCreate:=false;

    i:=i+1;

    Query.Next;

  end;

  Query.Close;

end;

constructor TTree.create;

begin

  root:=nil;

end;

constructor TTree.create(var arr:TArr);             //create a tree from arr

var

i,j,n:integer;

p:PTNode;

begin

  i:=0;

  n:=Length(arr);

  while i<n do

  begin

    j:=0;

    while j<n do

    begin

      if (arr[j].id='root') and (arr[j].hasCreate=false) then

        begin

          new(root);

          root:=@arr[j];

          root.fChild:=nil;

          root.nSibling:=nil;

          cur:=root;

          i:=i+1;

          arr[j].hasCreate:=true;

        end;

      if arr[j].hasCreate=true  then

        begin

          if arr[j].fid<>'none'  then

            begin

              p:=Form1.GetNode(arr,arr[j].fID);

              if p.hasCreate=false then

                begin

                  arr[j].fChild:=p;

                  p.hascreate:=true;

                  p.fchild:=nil;

                  p.nsibling:=nil;

                  i:=i+1;

                end;

            end;

          if arr[j].nid<>'none' then

            begin

              p:=Form1.GetNode(arr,arr[j].nID);

              if p.hascreate=false then

                begin

                  arr[j].nSibling:=p;

                  p.hascreate:=true;

                  p.fchild:=nil;

                  p.nsibling:=nil;

                  i:=i+1;

                end;

            end;

        end;

      j:=j+1;

    end;

  end;

end;

procedure TForm1.Button1Click(Sender: TObject);

var

arr:TArr;

aTree:TTree;

begin

  LoadData(arr);

  aTree:=TTree.create(arr);

  memo1.Lines.Add(atree.root.fchild.fchild.nsibling.nsibling.id);          //test

  aTree.Free;

end;

end.

 

---------------------