
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Tree.aspx.cs" Inherits="MyTeachers.web.Tree" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TreeView ID="TreeView1" runat="server" Height="257px" ImageSet="WindowsHelp"
Width="142px" Target="rightFrame">
</asp:TreeView>
</div>
</form>
</body>
</html>
后台
using System
using System.Collections.Generic
using System.Linq
using System.Web
using System.Web.UI
using System.Web.UI.WebControls
using System.Web.Security
using System.Web.UI.WebControls.WebParts
using System.Web.UI.HtmlControls
using System.Data
namespace MyTeachers.web
{
public partial class Tree : System.Web.UI.Page
{
DataView dv
DataTable dt
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
int id =Convert.ToInt32(Session["userID"])
//数据库执行查询的方法就不写了。
//Operator op = new Operator()
//这里执行的是:select * from tabmenu
dt = BLL.tabMenuBLL.GetAlltabMenut(id)
//第一次加载时调用方法传参
CreateTree(0, null, dt, this.TreeView1)
}
}
/// <summary>
/// 创建一个树
/// </summary>
/// <param name="parentID">父ID</param>
/// <param name="node">节点</param>
/// <param name="dt">DataTable</param>
/// <param name="treeView">TreeView的名称</param>
public void CreateTree(int parentID, TreeNode node, DataTable dt, TreeView treeView)
{
//实例化一个DataView dt = 传入的DataTable
dv = new DataView(dt)
//筛选(相当于select * from tabMenu where menuParentID = 传入的 parentID)
dv.RowFilter = "[pid]=" + parentID
//用foreach遍历dv
foreach (DataRowView row in dv)
{
//第一次加载时为空
if (node == null)
{
//创建根节点
TreeNode root = new TreeNode()
//root.Target = "rightFrame"
//必须与数据库的对应
root.Text = row["menuName"].ToString()
root.Value = row["menuID"].ToString()
//添加根节点
this.TreeView1.Nodes.Add(root)
//递归调用方法本身
CreateTree(int.Parse(row["menuID"].ToString()), root, dt, treeView)
}
else
{
//添加子节点
TreeNode childNode = new TreeNode()
childNode.Text = row["menuName"].ToString()
childNode.Value = row["menuID"].ToString()
childNode.NavigateUrl = row["menuUrl"].ToString()
node.ChildNodes.Add(childNode)
CreateTree(int.Parse(row["menuID"].ToString()), childNode, dt, treeView)
}
}
}
}
}
这是代码,你可以自己调试一下。数据结构如下:
CREATE TABLE dtree (
idint,
pid int,
name varchar(200),
url varchar(200),
title varchar(200),
target varchar(200),
iconvarchar(200),
iconopen varchar(200),
openedbit)
为了实现获取数据库变量功能,需要建立一个DTree类,并编译生成CLASS文件,放入\WEB-INF\classes文件夹下。
DTree类代码如下:
package work3
public class DTree {
private int id
private int pid
private String name
private String url
private String title
private String target
private String icon
private String iconOpen
private int opened
public int getId() {
return id
}
public void setId(int id) {
this.id = id
}
public int getPid() {
return pid
}
public void setPid(int pid) {
this.pid = pid
}
public String getName() {
return name
}
public void setName(String name) {
this.name = name
}
public String getUrl() {
return url
}
public void setUrl(String url) {
this.url = url
}
public String getTitle() {
return title
}
public void setTitle(String title) {
this.title = title
}
public String getTarget() {
return target
}
public void setTarget(String target) {
this.target = target
}
public String getIcon() {
return icon
}
public void setIcon(String icon) {
this.icon = icon
}
public String getIconOpen() {
return iconOpen
}
public void setIconOpen(String iconOpen) {
this.iconOpen = iconOpen
}
public int getOpened() {
return opened
}
public void setOpened(int opened) {
this.opened = opened
}
}
work3.jsp代码如下:
<%@ page language="java" contentType="text/htmlcharset=GB18030" pageEncoding="GB18030"%>
<%@ page import="java.sql.*"%>
<jsp:useBean id='settree' scope="application" class="work3.DTree" />
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/htmlcharset=GB18030">
<link rel="StyleSheet" href="dtree.css" type="text/css" />
<script type="text/javascript" src="dtree.js"></script>
<title>dTree in MySQL</title>
</head>
<body>
<h2>
Example
</h2>
<div class="dtree">
<p>
<a href="javascript: d.openAll()">open all</a>|
<a href="javascript: d.closeAll()">close all</a>
</p>
<script type="text/javascript">
<!--
d = new dTree('d')
<%
//驱动程序名
String driverName = "com.microsoft.jdbc.sqlserver.SQLServerDriver"
//数据库用户名
String userName = "sa"
//密码
String userPwd = "1"
//数据库名
String dbName = "master"
//表名
String tableName = "dtree"
//连接字符串
String url="jdbc:microsoft:sqlserver://localhost:1433DatabaseName="+dbName
//加载驱动
Class.forName(driverName).newInstance()
//连接数据库
java.sql.Connection conn = DriverManager.getConnection(url,userName,userPwd)
//得到Statement实例
java.sql.Statement statement = conn.createStatement()
//查询数据
String sql = "select * from " + tableName
//返回结果
java.sql.ResultSet rs = statement.executeQuery(sql)
//获取变量
while (rs.next()) {
settree.setId(rs.getInt(1))
settree.setPid(rs.getInt(2))
settree.setName(rs.getString(3))
settree.setUrl(rs.getString(4))
settree.setTitle(rs.getString(5))
settree.setTarget(rs.getString(6))
settree.setIcon(rs.getString(7))
settree.setIconOpen(rs.getString(8))
settree.setOpened(rs.getInt(9))
if(settree.getPid()==0)
settree.setOpened(1)
%>
d.add(<%=settree.getId()%>,<%=settree.getPid()%>,'<%=settree.getName()%>','<%=settree.getUrl()%>','<%=settree.getTitle()%>','<%=settree.getTarget()%>','','',<%=settree.getOpened()%>)
<%
}
%>
document.write(d)
//-->
</script>
</div>
</body>
</html>
树状结构的数据保存在数据库中的常用方法有一下两种:1、邻接表(adjacency list model)
2、预排序遍历树算法(modified preorder tree traversal algorithm)
用一下的例子讨论这两种方法的差异:
现有一棵树如下:
邻接表模式:
这种模式我们经常用到,很多的教程和书中也介绍过。我们通过给每个节点增加一个属性 parent 来表示这个节点的父节点从而将整个树状结构通过平面的表描述出来。根据这个原则,例子中的数据可以转化成如下的表:
我们看到 Pear 是Green的一个子节点,Green是Fruit的一个子节点。而根节点'Food'没有父节点。 为了简单地描述这个问题, 这个例子中只用了name来表示一个记录。 在实际的数据库中,你需要用数字的id来标示每个节点,数据库的表结构大概应该像这样:id, parent_id, name, description。
以下是代码:
<?php
// $parent is the parent of the children we want to see
// $level is increased when we go deeper into the tree,
//used to display a nice indented tree
function display_children($parent, $level)
{
// 获得一个 父节点 $parent 的所有子节点
$result = mysql_query('SELECT name FROM tree '.
'WHERE parent="'.$parent.'"')
// 显示每个子节点
while ($row = mysql_fetch_array($result))
{
// 缩进显示节点名称
echo str_repeat(' ',$level).$row['name']."n"
//再次调用这个函数显示子节点的子节点
display_children($row['name'], $level+1)
}
}
?>
对整个结构的根节点(Food)使用这个函数就可以打印出整个多级树结构,由于Food是根节点它的父节点是空的,所以这样调用: display_children('',0)。将显示整个树的内容:
Food
Fruit
Red
Cherry
Yellow
Banana
Meat
Beef
Pork
如果你只想显示整个结构中的一部分,比如说水果部分,就可以这样调用:display_children('Fruit',0)
几乎使用同样的方法我们可以知道从根节点到任意节点的路径。比如 Cherry 的路径是 "Food >Fruit >Red"。 为了得到这样的一个路径我们需要从最深的一级"Cherry"开始, 查询得到它的父节点"Red"把它添加到路径中, 然后我们再查询Red的父节点并把它也添加到路径中,以此类推直到最高层的"Food"
以下是代码:
<?php
// $node 是那个最深的节点
function get_path($node)
{
// 查询这个节点的父节点
$result = mysql_query('SELECT parent FROM tree '.
'WHERE name="'.$node.'"')
$row = mysql_fetch_array($result)
// 用一个数组保存路径
$path = array()
// 如果不是根节点则继续向上查询
// (根节点没有父节点)
if ($row['parent']!='')
{
// the last part of the path to $node, is the name
// of the parent of $node
$path[] = $row['parent']
// we should add the path to the parent of this node
// to the path
$path = array_merge(get_path($row['parent']), $path)
}
// return the path
return $path
}
?>
如果对"Cherry"使用这个函数:print_r(get_path('Cherry')),就会得到这样的一个数组了:
Array
(
[0] =>Food
[1] =>Fruit
[2] =>Red
)
接下来如何把它打印成你希望的格式,就是你的事情了。
缺点:
这种方法很简单,容易理解,好上手。但是也有一些缺点。主要是因为运行速度很慢,由于得到每个节点都需要进行数据库查询,数据量大的时候要进行很多查询才能完成一个树。另外由于要进行递归运算,递归的每一级都需要占用一些内存所以在空间利用上效率也比较低。
预排序遍历树算法
现在让我们看一看另外一种不使用递归计算,更加快速的方法,这就是预排序遍历树算法(modified preorder tree traversal algorithm) 这种方法大家可能接触的比较少,初次使用也不像上面的方法容易理解,但是由于这种方法不使用递归查询算法,有更高的查询效率。
我们首先将多级数据按照下面的方式画在纸上,在根节点Food的左侧写上 1 然后沿着这个树继续向下 在 Fruit 的左侧写上 2 然后继续前进,沿着整个树的边缘给每一个节点都标上左侧和右侧的数字。最后一个数字是标在Food 右侧的 18。 在下面的这张图中你可以看到整个标好了数字的多级结构。(没有看懂?用你的手指指着数字从1数到18就明白怎么回事了。还不明白,再数一遍,注意移动你的手指)。
这些数字标明了各个节点之间的关系,"Red"的号是3和6,它是 "Food" 1-18 的子孙节点。 同样,我们可以看到 所有左值大于2和右值小于11的节点 都是"Fruit" 2-11 的子孙节点
这样整个树状结构可以通过左右值来存储到数据库中。继续之前,我们看一看下面整理过的数据表。
注意:由于"left"和"right"在 SQL中有特殊的意义,所以我们需要用"lft"和"rgt"来表示左右字段。 另外这种结构中不再需要"parent"字段来表示树状结构。也就是 说下面这样的表结构就足够了。
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11
看到了吧,只要一个查询就可以得到所有这些节点。为了能够像上面的递归函数那样显示整个树状结构,我们还需要对这样的查询进行排序。用节点的左值进行排序:
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)