<H3>左儿子右兄弟表示法</H3>< >树的左儿子右兄弟表示法又称为<FONT face=楷体_GB2312><B>二叉树表示法</B></FONT>或<FONT face=楷体_GB2312><B>二叉链表表示法</B></FONT>。每个结点除了data域外,还含有两个域,分别指向该结点的最左儿子和右邻兄弟。这种表示法常用二叉链表实现,因此又称为<FONT face=楷体_GB2312><B>二叉链表表示法</B></FONT>。但是实际应用中常用游标(静态链表)来代替链表,请参见<a href="http://algorithm.myrice.com/datastructure/basic/list/chapter3_3.htm" target="_blank" >表的游标实现</A>。</P>< >若用指针实现,其类型定义为:</P><DIV align=center><CENTER><TABLE 10pt" cellPadding=5 width="90%" bgColor=#e0e0e0 border=0><TR><TD width="100%">< 5px; MARGIN-BOTTOM: 5px">Type</P><P 5px; MARGIN-BOTTOM: 5px"> TPosition=^NodeType;</P><P 5px; MARGIN-BOTTOM: 5px"> NodeType=record</P><P 5px; MARGIN-BOTTOM: 5px"> Label abelType;</P><P 5px; MARGIN-BOTTOM: 5px"> Leftmost_Child,Right_Sibling:TPosition;</P><P 5px; MARGIN-BOTTOM: 5px"> end;</P><P 5px; MARGIN-BOTTOM: 5px"> TreeType=TPosition; </P></TD></TR></TABLE></CENTER></DIV><P>若用游标实现,其类型定义为:</P><DIV align=center><CENTER><TABLE 10pt" cellPadding=5 width="90%" bgColor=#e0e0e0 border=0><TR><TD width="100%"><P 5px; MARGIN-BOTTOM: 5px">Type</P><P 5px; MARGIN-BOTTOM: 5px"> TPosition=integer;</P><P 5px; MARGIN-BOTTOM: 5px"> NodeType=record</P><P 5px; MARGIN-BOTTOM: 5px"> Label abelType;</P><P 5px; MARGIN-BOTTOM: 5px"> Leftmost_Child,Right_Sibling:TPosition;</P><P 5px; MARGIN-BOTTOM: 5px"> end;</P><P 5px; MARGIN-BOTTOM: 5px"> CellspaceType=array [1..MaxNodeCount] of NodeType;</P><P 5px; MARGIN-BOTTOM: 5px"> TreeType=TPosition;</P><P 5px; MARGIN-BOTTOM: 5px">var</P><P 5px; MARGIN-BOTTOM: 5px"> Cellspace:CellspaceType;</P><P 5px; MARGIN-BOTTOM: 5px"> Tree:TreeType; </P></TD></TR></TABLE></CENTER></DIV><P>此时树类型TreeType是整数类型,它指示树根在cellspace中的游标。例如图5(a)中树的左儿子右兄弟表示法的指针和游标实现分别如图5(b)和(c)所示。</P><P align=center><img src="http://algorithm.myrice.com/datastructure/basic/tree/images/img7.gif"></P><P align=center>(a)</P><P align=center><img src="http://algorithm.myrice.com/datastructure/basic/tree/images/img8.gif"></P><P align=center>(b)</P><P align=center><img src="http://algorithm.myrice.com/datastructure/basic/tree/images/img6.gif"></P><P align=center>(c)</P><P align=center>图5 树的左儿子右兄弟表示法</P><P>
用树的左儿子右兄弟表示法可以直接实现树的大部分操作,只有在对树结点作Parent操作时需遍历树。如果要反复执行Parent操作,可在结点记录中再开辟一个指向父结点的指针域,也可以利用最右儿子单元中的Right_Sibling作为指向父结点的指针(否则这里总是空指针)。当执行Parent(v)时,可以先通过Right_Sibling逐步找出结点v的最右兄弟,再通过最右兄弟的Right_Sibling(父亲指针)找到父结点。这个结点就是结点v的父亲。在这样的表示法下,求一个结点的父亲所需要的时间正比于该结点右边的兄弟个数。不过,这时每个记录中需要多用一位(bit)空间,用以标明该记录中的right_sibling是指向右邻兄弟还是指向父亲。</P><P>考虑到对于现在的计算机,内存已经不是很重要的限制因素了。我们下面就采取增加一个parent域的方案,以改进左儿子右兄弟表示法中Parent操作的效率。因此重新定义树的类型如下:</P><P>若用指针实现,其类型定义为:</P><DIV align=center><CENTER><TABLE cellPadding=5 width="90%" bgColor=#e0e0e0 border=0><TR><TD width="100%"><P 5px; MARGIN-BOTTOM: 5px">Type</P><P 5px; MARGIN-BOTTOM: 5px"> TPosition=^NodeType;</P><P 5px; MARGIN-BOTTOM: 5px"> NodeType=record</P><P 5px; MARGIN-BOTTOM: 5px"> Label abelType;</P><P 5px; MARGIN-BOTTOM: 5px"> Parent,Leftmost_Child,Right_Sibling:TPosition; {增加一个Parent域}</P><P 5px; MARGIN-BOTTOM: 5px"> end;</P><P 5px; MARGIN-BOTTOM: 5px"> TreeType=TPosition;</P><P 5px; MARGIN-BOTTOM: 5px">var</P><P 5px; MARGIN-BOTTOM: 5px"> Tree:TreeType; </P></TD></TR></TABLE></CENTER></DIV><P>若用游标实现,其类型定义为:</P><DIV align=center><CENTER><TABLE cellPadding=5 width="90%" bgColor=#e0e0e0 border=0><TR><TD width="100%"><P 5px; MARGIN-BOTTOM: 5px">Type</P><P 5px; MARGIN-BOTTOM: 5px"> TPosition=integer;</P><P 5px; MARGIN-BOTTOM: 5px"> NodeType=record</P><P 5px; MARGIN-BOTTOM: 5px"> Label:LabelType;</P><P 5px; MARGIN-BOTTOM: 5px"> Parent,Leftmost_Child,Right_Sibling:TPosition; {增加一个Parent域}</P><P 5px; MARGIN-BOTTOM: 5px"> end;</P><P 5px; MARGIN-BOTTOM: 5px"> CellspaceType=array [1..MaxNodeCount] of NodeType;</P><P 5px; MARGIN-BOTTOM: 5px"> TreeType=TPosition;</P><P 5px; MARGIN-BOTTOM: 5px">var</P><P 5px; MARGIN-BOTTOM: 5px"> Cellspace:CellspaceType;</P><P 5px; MARGIN-BOTTOM: 5px"> Tree:TreeType; </P></TD></TR></TABLE></CENTER></DIV><P>下面我们只针对上面的指针实现方案实现树的ADT操作。对于指针实现的树,空结点∧表示空指针nil。对于浮标实现的树,可以类似地实现下面的操作。</P><BLOCKQUOTE><P align=center><B>指针实现的左儿子右兄弟表示法实现的ADT树操作</B></P></BLOCKQUOTE><DIV align=center><CENTER><TABLE 10pt" cellPadding=5 width="90%" border=0><TR><TD width="100%" bgColor=#e0e0e0><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>函数 </B>Leftmost_Child(v,T)</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>功能</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">这是一个求最左儿子结点的函数。函数值为树T中结点v的最左儿子的位置。当v是叶结点时,函数值为nil,表示结点v没有儿子。</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>实现</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">Function Leftmost_Child(v:TPosition;var T:TreeType):TPosition;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">begin</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> return(v^.Leftmost_Child);</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">end;</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>说明</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">返回v的最左儿子的位置指针。</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>复杂性</B></P><BLOCKQUOTE><P>显然为<I>O</I>(1)。</P></BLOCKQUOTE></TD></TR><TR><TD width="100%" bgColor=#e0e0e0><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>函数 </B>Right_Sibling(v,T)</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>功能</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">这是一个求右邻兄弟的函数,函数值为树T中结点v的右邻兄弟。当v没有右邻兄弟时,函数值为nil。</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>实现</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">Function Right_Sibling(v:TPosition;var T:TreeType):TPosition;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">begin</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> return(v^.Right_Sibling);</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">end;</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>说明</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">返回v的右邻兄弟的位置指针。</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>复杂性</B></P><BLOCKQUOTE><P>显然为<I>O</I>(1)。</P></BLOCKQUOTE></TD></TR><TR><TD width="100%" bgColor=#e0e0e0><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>函数</B> Parent(v,T)</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>功能</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">这是一个求父结点的函数,函数值为树T中结点v的父亲在结点表中的位置。当v是根结点时,函数值为nil,表示结点v没有父结点。</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>实现</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">Function Parent(v:TPosition;var T:TreeType):TPosition;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">begin</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> return(v^.Parent);</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">end;</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>说明</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">返回v的父结点的位置指针。</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>复杂性</B></P><BLOCKQUOTE><P>显然为<I>O</I>(1)。</P></BLOCKQUOTE></TD></TR><TR><TD width="100%" bgColor=#e0e0e0><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>函数</B> Create(i,x,T<SUB>1</SUB>,T<SUB>2</SUB>,..,T<SUB>i</SUB>)</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>功能</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">这是一族建树过程。对于每一个非负整数i,该函数生成一个新树T,T的根结点v的标号为x,并令v有i个儿子,这些儿子从左到右分别为树T1,T2,..,Ti的根。当i=0时,v既是树根,又是树叶。</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>实现</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">Function Create(i:integer;var x:LabelType;var T<SUB>1</SUB>,T<SUB>2</SUB>,..,T<SUB>i</SUB>,T:TreeType);</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">begin</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> New(T); {建T的根结点}</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> T^.Label:=x;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> T^.Parent:=nil;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> T^.Right_Sibling:=nil;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> if i>0 then</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> begin</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> T^.Leftmost_Child:=T<SUB>1</SUB>;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> for k:=1 to i do</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> begin</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> T<SUB>k</SUB>^.Parent:=T;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> if k<i then T<SUB>k</SUB>^.Right_Sibling:=T<SUB>k+1</SUB></P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> else T<SUB>k</SUB>^.Right_Sibling:=nil;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> end; </P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"> end;</P><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">end;</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>说明</B></P><BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px">这个过程首先生成新树的根结点,其中存储的数据为x;然后对于每一个T<SUB>k</SUB>,1≤k≤i,将T<SUB>k</SUB>的根结点的父亲指向T,将T<SUB>k</SUB>的根结点的右兄弟指向T<SUB>k+1</SUB>(对于k=i的T<SUB>k</SUB>其右兄弟为nil)。这里我们假设输入的参数T<SUB>k</SUB><>nil,1≤k≤i。</P></BLOCKQUOTE><P 5px; MARGIN-BOTTOM: 5px; WORD-SPACING: 5px"><B>复杂性</B></P><BLOCKQUOTE><P>显然为<I>O</I>(i)。</P></BLOCKQUOTE></TD></TR></TABLE></CENTER></DIV><P>Label,Root和MakeNull比较简单,这里就不一一实现了。</P><P>我们看到,用这种左儿子右兄弟表示法实现树,可以高效地实现树的ADT操作,缺点是占用了用来存储指针的空间。不过我们还是推荐用这种表示法来表示树</P> |