算法放送:从数据库读取树形资料,显示在treeview中,精练的广度优先算法 ( 积分: 1 )

这有什么,我都是直接将Treeview直接保存在数据库里,同时保存里面的Pointer,需要时调入Treeview,然后对每个节点赋值pointer,这样的速度肯定会快更加快。
 
如果是这样的话。我觉得还是先建立一级节点,然后,在点一级节点的时候再通过查询数据库建立二级节点,以此类推。
因为在建树时一直都在使用SQL查询数据库,所以如果数据量非常巨大的话,并且是在网络中提取数据,上述算法应该会非常慢,除非一次性将数据提取过来,然后过遍历数据集的方法更加快。而且减少了网络回路。
个人看法。
 
请问yangyih007:
  如果你的树看起来更像是塑料或其它硬材料制造的,我要问:为什么要保存到数据库里,直接保存到dfm文件然后编译到exe文件不就好了吗?
如果你的树也是会长的,你在保存之前总得想办法让这棵树长出来是吧,这是不是该有个算法?同时,你说保存了pointer,我想问难道程序每次运行时那个poniter应该指向的对象恰好就是数据库里保存好了的?应用程序的内存都是动态分配的,你怎么能保证呢?在更多的机器上运行呢?
  你是不是已经试过了呢

  5207提到的“在建树时一直都在使用SQL查询数据库造成的低效率”我也想到了,一种优化方法是只执行一次select * from TB,在添加了节点的时候就遍历一次这个数据集。还有一种更BT的思想--同样只执行一次select * from TB,不同处在于,每当这条记录被添加为子节点时,就从这个数据集中删除这条记录,下次遍历时因为总记录数少了,总的说来效率提高--同时数据库中这条记录必须仍然存在,所以不能用qry.Delete,这如何实现呢?
  只有到了这个BT的算法,才叫得上完美
 
我说的这个树就是可以随时改变的,只要将改变后的树保存在数据库里就行了,而且节点的pointer是唯一的,这个pointer可以与数据库里的AUtoID(就是每条数据唯一的ID)相联系,每次修改树后同时保存每个节点的Pointer,这样就可以自由的调整拖动树的节点或者重新修改名称什么的,只要没有添加数据或者删除数据,就只用保存树而已。所以我一直使用这种方法来使用树,不过可能我理解错了你的想法。
 
这倒要向你学习了,给个例子吧,请教了!
 
在数据库里建立一个表,用来保存treeview,和pointer索引,字段类型是“Memo”,
将treeview.savetostream(ms)---ms:tmemorystream,然后来一个循环

procedure tform1.savetree;
var i:integer;
indexlist:tstringlist;
begin
indexlist:=tstringlist.create;
try
indexlist.Clear;
for i:=0 to treeview1.Items.Count-1 do
indexlist.Add(inttostr(integer(treeview1.Items.Data )));

table.Append;
(table.FieldByName('tree') as tblobfield).LoadFromStream(ms);

ms.Clear;
indexlist.SaveToStream(ms);
ms.Position:=0;
(table.FieldByName('indexlist') as tblobfield).LoadFromStream(ms);
table.Post;

ms.Free;
indexchange:=false;
except end;
end;

以后凡是修改目录树,比如修改名称,添加和删除都要savetree一次,最好用添加的方式,因为如果出现问题可以将出现问题的的tree删除,这样就可以回到上一个状态,当然最后的修改就会丢失,但比所有的丢失要好。另外我的经验:就是修改节点名称时注意不要带有换行符号,否则保存treeview时就会多一行,然后数据指针对不上,目录树就毁掉了。只能看看上一个索引是否正常,当然也可以看第几行出现问题,然后用相关数据库管理软件打开tree,将那个多余的一行删除就可以了。其实这些问题注意了就不会出现。
 
载入数据tree时

ms:=tmemorystream.Create;
(table.FieldByName('tree') as tblobfield).SaveToStream(ms);
ms.Position:=0;
treeview1.LoadFromStream(ms);


indexlist:=tstringlist.Create;
ms.Clear;
(table.FieldByName('indexlist') as tblobfield).SaveToStream(ms);
ms.Position:=0;
indexlist.LoadFromStream(ms);
ms.Free;

treeview1.Items.BeginUpdate;

if treeview1.Items.Count >0 then begin
for i:=0 to treeview1.Items.Count-1 do
treeview1.Items.Data:=pointer(strtoint(indexlist.Strings));
end;
 
支持
我的邮箱lvpozaixian@163.com
 
twcard@163.com,来一个
 
hongsheng2000@tom.com
谢谢大侠,也麻烦发一份给我!
 
想要一份,谢了

decayedapple@163.com
 
非常感谢,正需要这样的代码
我的邮箱:dacsd@163.com
 
adoquery使用batchupdate模式,然後就可以刪除了,最後cancelbatch就可以了,不會真正刪除資料,還有,先使用過濾,再刪除,這樣效率最高了
 
我也想要一个,学习学习
matcher@163.com
谢谢
 
偶想要个
438656@163.com
谢谢
 
给我一份:
jxl_king2000@yahoo.com.cn
 
搂主:
我想知道,按你的算法,从数据库中加载数据生成树的效率怎么样测试过吗
我想你的数据库操作太频繁了,效率应该不会太高
 
这是一个窗体中加载树的完整代码:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, ADODB, StdCtrls, ComCtrls, ExtCtrls;

type
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
TreeView1: TTreeView;
Button1: TButton;
ADOQuery1: TADOQuery;
ADOConnection1: TADOConnection;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FParentList:TStringList;
FChildList:TStringList;
{ Private declarations }
procedure DropTemp;
procedure OpenEmpData;
procedure MakeTree;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.DropTemp;
begin
with ADOQuery1 do
begin
Close;
Sql.Clear;
Sql.Add('drop table #Temp ');
try
ExecSQL;
except
end;
end;
end;

procedure TForm1.OpenEmpData;
begin
with ADOQuery1 do
begin
Close;
Sql.Clear;
Sql.Add('declare @Level int ');
Sql.Add('declare @WorkCount int ');
Sql.Add(' ');
Sql.Add('set @Level=1 ');
Sql.Add(' ');

Sql.Add('select @Level C001, sal_no C002, up_sal_no C003 into #temp from salm where up_sal_no is null ');
Sql.Add(' or up_sal_no = '''' ');
Sql.Add(' ');
Sql.Add('Select @WorkCount = count(*) from #temp ');
Sql.Add(' ');
Sql.Add('while @WorkCount > 0 ');
Sql.Add('begin ');
Sql.Add(' set @Level=@Level + 1 ');
Sql.Add(' ');
Sql.Add(' insert into #temp ');
Sql.Add(' select @Level, b.sal_no, b.up_sal_no ');
Sql.Add(' from #temp a inner join salm b on a.C002 = B.up_sal_no ');
Sql.Add(' where a.c001 = @level-1 ');
Sql.Add(' ');
Sql.Add(' Select @WorkCount = count(*) from #temp where C001 = @Level ');
Sql.Add(' ');
Sql.Add('end ');
Sql.Add(' ');
Sql.Add('select ');
Sql.Add(' A.C001, B.SAL_NO, B.NAME, A.C003 ');
Sql.Add('from #temp A Inner Join SALM B ');
Sql.Add('on A.C002 = B.SAL_NO ');
Sql.Add('order by 1,2 ');
Open;
end;
end;

procedure TForm1.MakeTree;
var
PTreeNode: TTreeNode;
CTreeNode: TTreeNode;
iLevel : Integer;
begin
with TreeView1.Items do
begin
Clear;
FParentList.Clear;
FChildList.Clear;
PTreeNode := Add(nil, 'Root'); // Create Root
FParentList.AddObject('',PTreeNode);
iLevel := 1;
with ADOQuery1 do
while not Eof do
begin
if iLevel <> FieldByName('C001').AsInteger then
begin
FParentList.Clear;
FParentList.Assign(FChildList);
FChildList.Clear;
iLevel := iLevel + 1;
end;
PTreeNode :=
TTreeNode(FParentList.Objects[FParentList.IndexOf(FieldByName('C003').AsString)]);
if ASSigned(PTreeNode) then
begin
CTreeNode := AddChild(PTreeNode, FieldByName('SAL_NO').AsString +' '+FieldByName('NAME').AsString);
FChildList.AddObject(FieldByName('SAL_NO').AsString, CTreeNode);
end;
Next;
end;
end;
//TreeView1.FullExpand ;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
DropTemp;
OpenEmpData;
MakeTree;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FParentList:=TStringList.Create ;
FChildList:=TStringList.Create ;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
FParentList.Free;
FChildList.Free;
end;

end.
 
你好,兄弟给份我参考.
liuyajune@126.com
 
您好!给我一个。
fan_hongtao@163.com
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
628
import
I
I
回复
0
查看
590
import
I
顶部