现在的位置: 首页 > 综合 > 正文

网络中树型菜单实现方法及其效率研究

2013年10月21日 ⁄ 综合 ⁄ 共 6820字 ⁄ 字号 评论关闭

摘要:对于树型菜单大家已经见得很多了,无论是软件中树菜单的制作还是基于WEB的树型菜单的应用,这个看似很简单的菜单在具体实现和效率方面有很大的差别,对于节点数量小,节点层数小的树型菜单来说我们用各种方法实现的结果基本差不多,但是对于层树很多,节点数量很大,关系复杂的树壮菜单而言各种实现办法之间是相差很大的,本文基于几种常用的实现方法来研究其实现方法和效率的问题。

关键字:树型菜单 效率

前言:对于网页中的树状菜单其实现结构大概可以分为以下几种结构:根节点,分支节点,叶节点,树支,对于内层结构可以分为:静态代码实现方式,异步载入模式,而异步载入模式中又可以分为:总体树载入模式和单节点载入模式,对于异步载入模式主要是出于对数据库的操作。同时对于构造树的算法方面大致最常用的也就是:父子节点编号法,和前缀码编号法,而节点的传输方面又可以分为:服务器端动态生成HTML方式,服务器端静态生成HTML方式,客户端保存HTML方式,可以看到这里实现方法很多,也很复杂,所以本文仅仅研究了几种比较成功的例子,虽然部分代码和程序来源于网络,但我还是具体实现了一种利用APPLET方式生成动态树,并且是单节点刷新的方法,而且能重用,具体实现思想和设计模式将在本文最后的实例分析中可以看到。

正文:

1.理论分析:

1.1语言实现方法分析:各种实现方法之间由于所在的平台不同可能表现出的优越性不同,但是其本质,也就是编译方式和解释方式决定了其效率的高低,下面我们比较几种实现方式的具体差异,从最低层来看看他们本应该存在的差异。

1.1.1Javascript

运行原理:作为一种脚本语言,用于实现HTML网页中的动态操作,其运行原理和一般程序不一样,而是在程序运行的过程中被逐行解释的,同时它是以事件驱动的方式完成对事件的处理。

特点及其局限性:跨平台可以说是它最大的特点,给它带来优点的同时也带来了很多局限性,比如:游览器的局限性和安全性有关的局限性,但是因为它和HTML很好的结合模式,从而也导致了它是应用很广的一门脚本语言。

1.1.2Java-Applet

运行原理:属于嵌入到游览器环境中的程序,必须由游览器的虚拟机(JVM)负责执行。当在本地编译完成以后,生成字节码文件,这样我们就可以通过导入字节码文件的方式,来实现我们的操作。

特点及其局限性:和Javascript一样也有垮平台性,但是我们只需要对其编译完以后用户就可以很方便的实现其功能,同时因为是java的一种嵌入式开发模式,我们可以很方便的利用SWING组件和其中的类,这样会给我来很高的效率。

1.2数据加载模式分析:具体各以分为一次性加载数据模式和异步加载模式。

1.2.1异步加载模式:事实上就是实现单节点的刷新模式,当用户点击某个节点的同时获得这个节点的信息,这样我们就可以通信服务器,从其数据库或者XML文件中读取子节点信息,并且加载到页面,完成显示工作。

1.2.2异步加载的优点:对于用户的一次操作我们需要通过传输的数据量很少,同时支持我们只对数据库进行操作时,比如:当用户没有点击某个节点的时候,如果这个时候对数据库中的数据更新,这样用户的到的也面效果也是最新的。其无限扩展性也是很好的,我们只需要修改我们的数据库或者XML文件,添加和删除节点,即使是数量很大也没有关系,对于用户的显示也只是通信时间上的问题。

1.2.3异步加载的缺点:设计模式比数据一次性加载要复杂得多,要考虑到 B/S 之间的应答,要判断子节点是否含有孙节点,后台数据源的层级关系模型等。对网络传输的信赖性太大,每个节点的展开都需要连一次服务器,只要在取某节点数据时网络出现问题,就会导致该节点及其以下的子节点加载失败,同时对于服务器的通信次数太多(具体用户操作而言),这样会加重服务器的负担,所以这也是一个很大的缺点。

1.2.4一次性加载模式:相比上面这种数据加载模式而言,一次性加载模式是当用户获得网页后一次性从服务器把整个树的信息加载到游览器上面,虽然我们没有打开某些节点,但是我们事实上在本地已经获得了这些节点的信息,只是我们并没有展开父节点看到它而已。

1.2.5一次性加载的优点:相比异步模式,它的层次结构就更加清晰,实现方法也简单很多,。而采取数据一次加载的模式只要一次加载成功,服务器就可以不用管它了,服务器压力减轻,脚本设计则完全独立,对整棵树节点的检索可以在客户端完成,节点展开响应速度快等等优势,因此在节点数不多的情况下数据一次性加载更有优势。

1.2.6一次性加载的缺点:虽然对于服务器通信的次数很少,但是在第一次获得节点信息的时候数据量可能会很大,可能会由于网络环境的影响而严重影响用户的界面访问,对于节点总体节点信息量很大的情况不适合,同时对于服务器端的实时更新我们必须重新加载一次才能访问更新的内容。

1.3节点信息传输问题:在浏览器里显示的树结构其实都是一个个 HTML 元素组合起来的,在 WEB 页面里的树都是根据树节点的信息组合成一串的 HTML 元素列来显示,这一步从节点信息到 HTML 的转化可以在两个地方生成:一个是在服务器端,一个是在客户端。

1.3.1服务器端动态生成HTML方式:在服务器端生成的优点在于不须考虑客户端的浏览器的兼容性,节点信息的可控性非常强,但是它的缺点也是非常大的:加重服务器的负担,增加网络传输量。在服务器端直接生成树节点的 HTML 给服务器带来的压力是显而易见的,也是非常巨大的,估计只要有几十个并发连接就能让服务器暂时停止响应了。

1.3.2服务器端静态生成HTML方式:当然可以直接将树生成为一个静态文件放在服务器端,这种做法对于树节点相对固定不变的情况还是非常有利的,只需要生成一次,以后就不需要再生成了,服务器的压力也非常小,但它的弊病在于可变化性太小,比如说不同的权限能看到的树节点的不同这种情况,用这种生成静态树放在服务器端的做就没有办法解决。

1.3.3客户端保存HTML方式:这样虽然解决了传输量大的问题,但是当节点信息量很大时,我们在客户端本地保存的信息也是很大,可能会占用大量的本地的硬盘资源,并且每次的访问是独立的一次,当我们的信息量很大,而且用户的访问次数很多时,我们使得用户的负担加重。

1.4树结构实现算法分析:

1.4.1父子节点编码法:我们可以很容易就想到链表中的指针的概念,这种编码方法也是基于这种思想,当我们的每个节点都有唯一的ID号的时候,我们在描叙一个树节点的时候,只在储存其节点ID的同时储存其父节点的ID,这样我们就可以很容易通过寻找父节点的方法实现一棵树的建立。

1.4.2编码实例:

     

ID

父节点ID

1

1

2

1

3

1

4

3

5

1

6

5

 

搜索成的树型图:(图1.3.2.A

+ 1

  + 2

      + 3

        + 4

      + 5

       + 6

 

1.4.3编码的优点:我们可以很清晰的看出每个父子节点的信息,所需要的数据结构和数据库设计也很简单,很便于节点数量少的树型菜单设计方式,即使是对于层次复杂的树型结构我们也只对单个节点描叙ID和父节点ID的信息。

1.4.4编码的缺点:对于数据库的搜索模式事实上也是采取的逐行扫描的方法实现的,这样我们如果采用这种编码方式的话,如果在访问数据库获得数据库内容的时候,如果我们没有进行排序操作的话,我们显示的节点信息可能会有很大的差别,请看下图(1.3.4.A),同时我们在搜索的时候可以采用两种搜索方法,第一种:我们按ID号大小分别作为父节点,分别搜索其子节点,这样的效率肯定不高,搜索的次数可能会很多,对数据库的访问次数也很多。第二种,我们采用递归搜索的方法,当搜索到一个节点的父节点的ID时,我们再把这个ID号作为子节点的ID号来进行搜索,从而利用递归的方法实现树型结构,但是这样的效率上和实现难度上有很高的要求。

     搜索结果不同:(图1.3.4.A

+ 1                                           + 1

  + 2                                           + 3

      + 3                                           + 2

        + 4                                           + 4

      + 5                                           + 5

       + 6                                     + 6

没有互换之前的搜索兔                         互换后的搜索图

*说明:我们把节点号为23的节点在数据库中互换位置,得到不同的结果,虽然这样一个节点的子节点个数和相关信息没有变化,但是对于自身在父节点中的位置也发生了变化,对于某些需要具体顺序的应用将产生很大影响。

 

1.4.1前缀码编码法:我们可以很容易用数字描叙树结构中的层次关系和顺序关系,例如:0代表根节点,0.1代表其下的第一个子节点,利用这种编码方法,我们很容易就可以描叙一棵树形结构。

1.4.2编码的优点:在进行建立树结构的过程中我们很容易就可以找到其子节点的信息,只要以父节点的ID号作为前缀码,按顺序获得两个分割符之间的数字,这个数字事实上就是以这个父节点为根的子节点的索引号,这样我们可以把每个父节点看成一棵树的根,子节点的索引也就是在这个树下面的节点编号。

1.4.2编码的缺点:对于层次数量比较大的树型菜单我们在数据库中描叙其层次结构时很复杂,因为是前缀编码方法,所以不利于手动修改数据库信息,同时对于网络传输中,我们如果没有对数据进行压缩,这样我们的节点ID号方面的数据量会因为我们的层次数量的增大而增大。

编码例子:

ID

0

0.1

0.2

                                      0.2.1

                                      0.3

  0.3.1

 

 

搜索结果:

+ 0

  + 0.1

  + 0.2

    + 0.2.1

  + 0.3

  + 0.3.1

2.具体实现方法:

      由于涉及的语言方面的实现方法很多,本文只对网上比较流行的实现方法HTML结合javascript的方法还有java-applet实现方法进行了分析,同时对于各种软件制作树状菜单的原理也进行了分析。

2.1 HTML-javascript实现方法:我们利用HTML完成对节点信息的描叙,这完全是静态的添加HTML代码的操作,同时用利用javascript脚本来实现对节点的事件处理。

2.1.1静态实现代码:(对应于代码一)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

    <head>

        <title></title>

        <link type="text/css" href="css/tree.css" rel="stylesheet">

        <script language=javascript>

        function ChangeStatus(o)

        {

            if (o.parentNode)

            {

                if (o.parentNode.className == "Opened")

                {

                    o.parentNode.className = "Closed";

                }

                else

                {

                    o.parentNode.className = "Opened";

                }

            }

        }

        </script>

    </head>

    <body>

<div class="TreeMenu" id="CategoryTree">

<h4>CSS树形菜单</h4>

<ul>

  <li class="Opened"><img class=s src="css/s.gif" onclick="javascript:ChangeStatus(this);"><a href="#">根节点</a>

  <ul>

    <li class="Opened"><img class=s src="css/s.gif" onclick="javascript:ChangeStatus(this);"><a href="#">我的文档</a>

      <ul>

       <li class="Opened"><img class=s src="css/s.gif" onclick="javascript:ChangeStatus(this);"><a href="#">JavaScript</a>

        <ul>

         <li class="Child"><img class=s src="css/s.gif"><a href="#">1</a></li>

         <li class="Child"><img class=s src="css/s.gif"><a href="#">2</a></li>

         <li class="Child"><img class=s src="css/s.gif"><a href="#">3</a></li>

         <li class="Child"><img class=s src="css/s.gif"><a href="#">4</a></li>

         <li class="Child"><img class=s src="css/s.gif"><a href="#">5</a></li>

         <li class="Child"><img class=s src="css/s.gif"><a href="#">6</a></li>

         <li class="Child"><img class=s src="css/s.gif"><a href="#">生成node</a></li>

        </ul></li>

</ul>

</div>

    </body>

</html>

2.1.2代码功能分析:对于各个节点的操作控制我们用下面的脚本:

<liclass="Opened"><imgclass=ssrc="css/s.gif"onclick="javascript:ChangeStatus(this);"><a href="#">根节点</a> 进行控制,对于每个分支节点我们都需要添加这条,对于各个父节点的子节点的数量我们必须通过添加如下代码实现,<li class="Child"><img class=s src="css/s.gif"><a href="#">1</a></li>,这样我们就可以实现HTML的静态显示,用javascript来实现事件控制,对于图片加载还需要说明的是,我们看到的节点的图片是加载进去的,同时对于连线的效果也是加载进去的,这也是这次研究的一个发现,对于这个代码如何处理事件是利用函数ChangeStatus来控制的。

2.1.3代码优缺点分析:代码很简洁明了,对于实现层次结构不复杂,节点数量不多的树型菜单的时候很方便就可以实现功能,避免了对数据库的访问,这样使得服务器的负担减轻。但是我们每次都是手动的去添加节点的信息,这样会造成效率很低,而且整个HTML文件的数量也很大。

2.2 HTML-javascript动态加载实现方法:(说明:这个实例是引用网友“meizz”提供的MzTreeView1.0,其控件被CSDN论坛进行修改,而作为其论坛的树状导航菜单)这里的动态加载实现方法事实上就是从数据库中获得相关的节点信息,再构造出树结构。

2.2.1实现代码:.(对应于文件夹代码二)

2.2.2设计思想分析:

A.采用数据一次性加载:把获得的树信息一次性加载给用户,减轻了服务器的负担和访问次数。

B.节点信息的压缩传输:节约了在传送节点信息的HTML文件的时候文件过于庞大。

C.数据库设计:采用父子节点编码方法,结构简单,清晰,同时为每个节点添加了对应的脚本操作,这样节省了打开各个节点时的时间。

D.异步展示:对于整个节点的HTML文件的生成不是以整体的方式展示在用户面前,而是以单单要显示的页面而生成其HTML

E.采用文字树线:这样避免了对于图片树线的加载,使得展开速度更加快。

F.控件的扩展性:控件的扩展性和重用性都比较高。

抱歉!评论已关闭.