悬赏捉拿算法高手

SZHHP 2002-10-30 08:36:39
1、有数据表如下:
项目ID 父项目ID 项目名称
0A * 在建项目
0B * 完工项目
SH_1 0A 上海项目1
SH_2 0A 上海项目2
SH_3 0B 上海项目3
SZ_1 0A 深圳项目1
SZ_2 0B 深圳项目2
SZ_3 0A 深圳项目3
.......


从父子的层次上是不固定的,可能2层,也可能4-5层或更多
记录数可能高达5000。

2、要求:用TREEVIEW显示,所以要将表织成树(利用“项目ID”,和“父项目ID”)
由于层次不定,记录过多,所以,要求算法得当,避免影响速度,让人无法忍受。
并且要一次全部织完。
请高手赐教。
...全文
71 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
SZHHP 2002-11-17
  • 打赏
  • 举报
回复
jieyf(天马行空) :的比较完整
SZHHP 2002-11-17
  • 打赏
  • 举报
回复
该结帖了,告诉大家我最后采用的是 chenbinghui(阿炳)的方法。
“我认为最主要的问题不是织树,而是查找”这个观点我同意。
大家的意见有两种倾向:
1、发送SQL到SQLSERVER,让其发挥其强项---检索数据
2、将数据一次调入缓存,采用适当方法查找。
第1种倾向会受到环境的制约比较多,频繁的向服务器请求数据有时不是好的方法。
在遍历结点上有人建议用递归,光从递归的方法上看,大家都知道递归是很没效率的。所以我不采用递归。
我查了帮助,哈希表在查找上有其优势。
有朋友建议,先产生一级结点,需要时再产生子级结点。我认为这是个技巧,
你最终还是要涉及查找。
感谢 chenbinghui(阿炳) 和其他所有朋友
DragonFly-9 2002-11-17
  • 打赏
  • 举报
回复
========================
数据库表设计
必须包含下列字段:
字段名 字段类型 字段说明 PrimaryKey
==========================================
NodeID varchar 节点标识 Yes
NodeName varchar 节点显示名
ParentID varchar 父节点标识
....

//节点信息类
public class NodeInfo
{
public string NodeID;
public string NodeName;
public string ParentID;
public string PrivateData;
///...更多的属性定义
public NodeInfo()
{
}
}

public class UserTool
{
public static void Load(DataTable dt,ref TreeView tv)
{
Hashtable ht = new Hashtable();
int iCount = dt.Rows.Count;
DataRow dr;
NodeInfo nodeInfo;
string [] keyArray = new string[iCount];//保存哈西表中的键值
//创建所有树节点,保存在哈西表中
for(int i=0;i<iCount;i++)
{
nodeInfo = new NodeInfo();

dr = dt.Rows[i];
nodeInfo.NodeID = dr["NodeID"].ToString();
nodeInfo.NodeName = dr["NodeName"].ToString();
nodeInfo.ParentID = dr["ParentID"].ToString();
nodeInfo.PrivateData = dr["ParentID"].ToString();
///...更多的字段处理

keyArray[i] = nodeInfo.NodeID;
TreeNode tn = new TreeNode(nodeInfo.NodeName); //创建节点
tn.Tag = nodeInfo; //设置节点数据区
ht.Add(nodeInfo.NodeID,tn);
}
//建立节点关系,并将根节点加入到TreeView中
for(int i=0;i<iCount;i++)
{
TreeNode tn = (TreeNode)ht[keyArray[i]];
nodeInfo = (NodeInfo)tn.Tag;
if(nodeInfo.ParentID == null || nodeInfo.ParentID == "")
tv.Nodes.Add(tn);//这是根节点
else //这是子节点
{
TreeNode tnd1 = (TreeNode)ht[nodeInfo.ParentID];//找父节点对象,注意:可能找不到父节点对象
if(tnd1!=null)
tnd1.Nodes.Add(tn);//找到父节点:把该节点加到父节点的子节点列表中
else
{
//未找到父节点:或把它设为根节点,或抛弃,你看着办了
//tv.Nodes.Add(tn); //设为根节点
}
}
}
}
}

chenbinghui 2002-11-17
  • 打赏
  • 举报
回复
不要把所有问题都留给电脑去解决,一个能用o(n)的算法解决的问题为什么要使用o(n^2),o(n^3)的方法去实现????????
SZHHP 2002-11-14
  • 打赏
  • 举报
回复
to ahu9870(阿胡9870):
能再具体点吗?
ahu9870 2002-11-13
  • 打赏
  • 举报
回复
庸人自扰!
关系数据库自身的B+树索引及数据库管理界面的优化查找功能可轻易地实现5000的X数量级的瞬间查找!
SZHHP 2002-11-12
  • 打赏
  • 举报
回复
继续讨论
w_rose 2002-11-05
  • 打赏
  • 举报
回复
首先填第一层数据,然后启动线程填写深层数据。编例采用递归方法。
lgh3328 2002-11-05
  • 打赏
  • 举报
回复
up
chenbinghui 2002-11-04
  • 打赏
  • 举报
回复
刚才在公司里面,不敢多写,所以写得很烂,只是一个框架
class Project{
//下面这些都应该是property才好,为了不写得太长才写成变量
public string mID;
public string mParent;
public string mName;
public arraylist mChildren;
public Project(id,parent,name)
{
mID=id,mParent=parent,mName=name;
}
public AddChildren(Project child)
{
mChildren.Add(child);
}
}
class run{
public HashTable tree()
{
HashTable ht=new HastTable();
ArrayList roots=new ArrayList();
Project p;
foreach record//这里面应该是取得所有的记录,具体的函数我不是很熟悉
{
p=new Project(record.id,record.parent,record.name);
if(p.mParent.Trim()=="*")
{
roots.Add(p);
}
//加入hash table
ht.Add(record.id,p);
//取出父project,
((Project)ht[p.Parent]).AddChild(p);
}
return ht;
}
}
record.id,record.parent,record.name是当前记录的三个字段值,数据库的函数我不是很记得了,而且我现在的机器没有.Net,只好写成这个样了。
这样roots里面就保存好了树的根,只要遍历每一个roots就可以获得所有的节点。
eshao 2002-11-04
  • 打赏
  • 举报
回复
chenbinghui(阿炳)你写的我没有看懂,请指教
chenbinghui 2002-11-04
  • 打赏
  • 举报
回复
我认为最主要的问题不是织树,而是查找,
象这种查找最快的方法莫过于HashTable,
class Project{
string mID;
string mParent;
string mName;
arraylist mChildren;
public Project(id,parent,name);
public AddChildren(Project child)
}
class run{
public tree()
{
HashTable ht=new HastTable();
Project p;
foreach record
{
p=new Project(record.id,record.parent,record.name);
ht.Add(record.id,p);
((Project)ht[p.Parent]).AddChild(p);
}
}
}
这个算法的时间复杂性只是f(n)
eshao 2002-11-04
  • 打赏
  • 举报
回复
我原来用vb实现过,但并非填充树,而是返回记录机
可供参考

Function transNode(ByVal groupid As Integer)
On Error GoTo errorHandler:
Dim rs As New ADODB.Recordset
Dim sql As String
Dim connstr As String
Dim conn As New ADODB.Connection
connstr = m_dbh.GetConnectionString
conn.Open connstr
sql = "select * from groups where parent=" & groupid
rs.Open sql, conn, 1, 3
While Not (rs.EOF)
childStr = childStr & rs("groupid") & ","
transNode (rs("groupid"))
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
errorHandler:
Set rs = Nothing

Function GetChild(ByVal k As Integer) As ADODB.Recordset

Dim conn As New ADODB.Connection
Dim connstr As String
Dim sql As String
childStr = ""
Call transNode(k)
childStr = childStr & "0"
connstr = m_dbh.GetConnectionString
conn.Open connstr
sql = "select * from groups where groupid in (" & childStr & ")"
Set GetChild = conn.Execute(sql)


childStr = ""

End Function


程序调用getchild(parentID)就可以 得到下面所有的孩子,包括孩子的孩子。

如果想添充树,可以在transNode(k)函数中加入对树的操作。





End Function
sbf2000 2002-11-04
  • 打赏
  • 举报
回复
不好意思,我这里用了一个foreach,让大家非常不解,其实我只是用来表个意,并不是要直接用这个语句。
如果“父项目ID”是一个集合,当然没问题。
在这里,这个集合可以理解为:
Select * from 你的表 where 父项目ID=项目;
具体实现的办法,是用dataset还是什么,自己去写好了。

我用这个方法做了个显示XML Schema元素的TreeView,很好用的,特别是当各节点有循环包含时更有效,因为如果一次性填完整个树,肯定是死循环。
而用户实际使用时,不可能一下子用到所有的节点,所以,没有必要一次把所有数据填完,只要需要显示的有了,就行。
mcsedb 2002-11-03
  • 打赏
  • 举报
回复
foreach是集合操作,这样怎么做????
TheAres 2002-11-03
  • 打赏
  • 举报
回复
看看这篇帖子,是用存储过程作的,应该比较快.

如何在C#中快速实现数据库树形结构
http://www.aspxcn.com/dotnetbbs/View.aspx?fbId=23&Id=57150
yarshray 2002-11-02
  • 打赏
  • 举报
回复
foreach是集合操作,这样怎么做????
sbf2000 2002-11-01
  • 打赏
  • 举报
回复
public void FillTree(TreeNode n, 项目)
{
foreach(项目ID in 父项目ID)
{
TreeNode n2=new TreeNode(项目名称);
n2.tag=项目ID;
n.nodes.add(n2);
}
}
中的“项目”就是“父项目ID”,这里只是指示找一个父项目的所有子项目。所以不是5000*5000,而是最多5000次;
sbf2000 2002-11-01
  • 打赏
  • 举报
回复
1.因为你是从表中取记录,所以代码要进行调整。
2.我的算法不是一次性将所有记录填到TreeView中,而是当需要时才填充所选择的节点的子节点。
3.如果确实要一次性填充,可考虑多线程,为每一个节点的填充过程开一个单独线程。
SZHHP 2002-11-01
  • 打赏
  • 举报
回复
to sbf2000(围困);
还是不明白,

public void FillTree(TreeNode n, 项目)
{
foreach(项目ID in 父项目ID)
{
TreeNode n2=new TreeNode(项目名称);
n2.tag=项目ID;
n.nodes.add(n2);
}
}
参数 n 为欲增加子节点的节点,参数 项目 为该节点的 TAG 即 该节点的 ID 值

那么这一句我应该怎样理解?

foreach(项目ID in 父项目ID)
尤其是 “项目ID in 父项目ID”
如果如你所说 “项目”就是“父项目ID”,因为参数 项目 为该节点的 TAG 即 该节点的 ID 值 所以 “父项目ID”并不是一个集合或数组啊?
按照 foreach in 的语法解释, (项目ID in 父项目ID) 中的 项目ID 应为 父项目ID 中的一值,这样的话,这个迭代只执行一次了。
加载更多回复(4)

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧