← 数据结构(2019) 2019-数据结构-数据结构4-Tree 2020-01-17 约 57 分钟阅读 阅读 — 次
4 Tree
1. Tree 树
定义: A tree T is a collection of nodes(element). 树T是结点的集合
The collection can be empty; otherwise, a tree consists of a distinguished node r, called the root, and zero or more nonempty(sub)trees T1 , T2 , ……, Tk (这个集合可能为空,否则这个树是由一个特殊的根节点和0个或多个子树组成)
1.1. 树的一些定义
Degree of an elements(node) 节点的度数:有多少个子节点
Degree of a tree 树的度:树里面结点的最大的度数。
Leaf 叶节点:树里面度数为0的节点。
Branch 分支节点:树里面度数不为0的节点。
Level 层:各节点的层次为0或1,节点的层次等于其父结点的层次+1
树的高度:所有节点的最大层次数。
2. 二叉树
二叉树的定义:A binary tree t is a finite (possibly empty) collection of elements.(二叉树 t 是一个有限的节点的集合)
二叉树的特点:
二叉树的每个结点的度数为2
如果有子树,则子树均为二叉树,并且被称为左子树和右子树。
二叉树的左右子树是有区别的
2.1. 二叉树的应用
运算式的计算:转化成语法树后自带括号(运算次序)
2.2. 二叉树的性质(考前重点)
n个结点的二叉树之间有n-1条边。
第i层的节点数最多是2i 个
高度为h(从0开始计)的二叉树中结点最少h+1个,最多2h+1 -1
如果一颗二叉树有n0 个树叶,并且结点度数为2的节点有n2 个,则n0 =n2 +1个
证明:设度数为1的节点为n1 ,则n=n0 +n1 +n2
n = B + 1,B为分支数(总节点数 = 边数 + 1 )
B = 1 * n1 + 2 * n2
不会证明用数学归纳法
有n个结点的二叉树的高度最大为n-1,最小为log2 (n+1)(向上取整)-1
2.3. 满二叉树
将二叉树排满,也就是如果高度为n的树,其节点数为2n+1 -1个
2.3.1. 完全二叉树
定义:Suppose we number the elements in a full binary tree of height h using the number 1 through 2h+1 (假设我们为一个高度为h的满二叉树进行使用1 - 2h+1 的数字进行编码)
We began at level 0 and go down to level h.Within levels the elements are numbered left to right. (我们从0层到h层,从左向右进行编码)
从上到下,从左到右进行编码
性质六: Let i, 0 <= i <= n-1,be the number assigned to an element of a complete binary tree. The following are true.(假设i,1<=i<=n-1,是一个确定二叉树的一个节点的编号)
if i=0, then this element is the root of the binary tree. if i>0,then the parent of this element has been assigned the number (i-1)/2 (向下取整)(如果i=0,则是根节点,不然其父结点的编号为 (i-1)/2 (向下取整))
if 2i+1 >= n,then this element has no left child. Otherwise,its left child has been assigned the number **2 i+1**.(如果2*i+1>=n,那么这个元素没有左子女,不然左子女的编号就是这个数字)
if 2i+2>=n, then this element has no right child, Otherwise its right child has been assigned the number **2 i+2**.(如果2*i+2>=n,那么这个元素没有右子女,不然右子女的编号就是这个数字)
完全二叉树和满二叉树是不同的,完全二叉树的最后一层可以不全满,但是必须从左开始顺序无空缺。
2.4. 物理实现二叉树
2.4.1. 数组实现二叉树
其标记为其在数组中的下标,使用数组来存储。
常规二叉树的数组表示的位置上一定有空的。
很稀疏的二叉树会导致数组存储二叉树有大量的内存空间被浪费掉。
2.4.2. 链表实现二叉树
Linked representation( also called L-R linked storage) 也被称为L-R链表存储。
二叉树节点
1 2 3 4 5 6 7 8 9 10 class BinaryNode { BinaryNode (){Left=Right=0 ;} BinaryNode (Object e) {element=e; Left=Right=0 ;} BinaryNode (Object e, BinaryNode l, BinaryNode r) {element=e; Left=l; Right=r; } Object element; BinaryNode left; BinaryNode right; };
二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 template <class T >class BinaryTree { public : BinaryTree (){root=0 ;}; ~BinaryTree (){}; bool IsEmpty () const {return ((root)?false :true );} bool Root (T& x) const ; void MakeTree (const T& data, BinaryTree<T>& leftch, BinaryTree<T>& rightch) ; void BreakTree (T& data , BinaryTree<T>& leftch, BinaryTree<T>& rightch) ; void PreOrder (void (*visit)(BinaryNode<T>*u)) {PreOrder (visit, root);} void InOrder (void (*visit)(BinaryNode<T>*u)) {InOrder (visit, root);} void PostOrder (void (*visit)(BinaryNode<T>*u)) {PostOrder (visit, root);} void LevelOrder (void (*visit)(BinaryNode<T> *u)) ; private : BinaryNode<T>* root; void PreOrder (void (*visit)(BinaryNode<T> *u), BinaryNode<T>*t) ; void InOrder (void (*visit)(BinaryNode<T> *u), BinaryNode<T>*t) ; void PostOrder (void (*visit) (BinaryNode<T> *u), BinaryNode<T>*t) ; };
正常二叉树操作
In this class ,we employ a linked representation for binary trees.在这个class中我们使用链表来代表二叉树
The function visit is used as parameter to the traversal methods,so that different operations can be implemented easily 函数visit被用作遍历方法的一个参数所以我们可以实现不同的操作更加简单
2.4.3. 链表具体实现方法细节
补充C++知识:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 template <class T >void BinaryTree<T>::MakeTree (const T& data, BinaryTree<T>& leftch,BinaryTree<T>& rightch){ root=new BinaryNode <T>(data, leftch.root, rightch.root); leftch.root = rightch.root=0 ; }template <class T >void BinaryTree<T>::BreakTree (T& data, BinaryTree<T>& leftch,BinaryTree<T>& rightch) { if (!root) throw BadInput (); data=root.element; leftch.root=root.Left; rightch.root=root.Right; delete root; root=0 ; }
二叉树的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream.h> #include <binary.h> int count=0 ; BinaryTree<int >a,x,y,z;template <class T>void ct (BinaryTreeNode<T>*t) {count++;}void main (void ) { a.MakeTree (1 ,0 ,0 ); z.MakeTree (2 ,0 ,0 ); x.MakeTree (3 ,a,z); y.MakeTree (4 ,x,0 ); y.PreOrder (ct); cout<<count<<endl; }
2.5. 二叉树遍历
以下算法中的二叉树是通过链表实现的。
Each element is visited exactly once
V-----表示访问一个结点 vertice
L-----表示访问V的左子树 left tree
R-----表示访问V的右子树 right tree
所有的遍历顺序:VLR\LVR、LRV、VRL、RVL、RLV
常用的遍历顺序
先序遍历:VLR
中序遍历:LVR
后序遍历:LRV
广度优先遍历:先处理树根节点,然后处理靠近的第一层的节点
2.5.1. 例子
2.5.2. 先序遍历
VLR
1 2 3 4 5 6 7 8 9 10 template <class T>void PreOrder (BinaryNode<T>* t) { if (t){ visit (t); PreOrder (t->Left); PreOrder (t->Right); } }
2.5.3. 中序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 template <class T>void InOrder (BinaryNode<T>* t) { if (t){ InOrder (t->Left); visit (t); InOrder (t->Right); } }void Inorder (BinaryNode <T>*t) { Stack<BinaryNode<T>*> s (10 ); BinaryNode<T>*p = t; for (;;){ while (p!=NULL ){ s.push (p); p = p->Left; } if (!s.IsEmpty ()){ p = s.pop (); cout << p->element; p = p->Right; }else return ; } }
2.5.4. 后序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 template <class T>void InOrder (BinaryNode<T>* t) { if (t){ InOrder (t->Left); InOrder (t->Right); visit (t); } }struct StkNode { BinaryNode <T> * ptr; int tag; }void Postorder (BinaryNode <T> * t) { Stack <StkNode<T>> s (10 ); StkNode<T> Cnode; BinaryNode<T>*p = t; for (;;) { while (p!=NULL ){ Cnode.ptr = p; Cnode.tag = 0 ; s.push (Cnode); p = p->Left; } Cnode = s.pop (); p = Cnode.ptr; while (Cnode.tag == 1 ) { cout << p->element; if (!s.IsEmpty ()){ Cnode = s.pop (); p = Cnode.ptr; }else { return ; } } Cnode.tag = 1 ; s.push (Cnode); p = p->Right; } }
2.5.5. 广度优先遍历
根据level order(树的层数)
数组实现
直接按顺序访问数组即可
链表实现
1 2 3 4 5 6 7 8 9 10 template <class T> void LevelOrder (BinaryNode<T>* t) { LinkedQueue<BinaryNode<T>*> Q; while (t){ visit (t); if (t->Left) Q.Add (t->Left); if (t->Right) Q.Add (t->Right); try {Q.Delete (t);}catch (OutOfBounds){return ;} } }
2.6. 建立二叉树
2.6.1. 利用MakeTree函数
2.6.2. 利用先序、中序唯一的构造一颗二叉树
2.6.3. 利用二叉树的中序、后序遍历确定一颗二叉树
后序的最后是根节点,根据中序进行划分
2.6.4. 利用二叉树的广义表来构造一颗二叉树
2.6.5. 利用二叉树的后缀表示来构造一颗二叉树
2.6.6. 利用二叉树的后缀表示来构造一颗二叉树
3. 精讲:利用先序、中序唯一的构造一颗二叉树(string)
字符串(简称串)的定义以及一些术语
串:是n(n>=0)个字符的一个有限序列,开头结尾用双引号""括起来。
串的长度:串中所包含的字符个数n(不包括分界符‘ " ’,也不包括串的结束符‘\0’)
空串:长度为0的串。或者说只包含串结束符‘\0’的串,空串不等同于空白串。
子串:串中任一连续子序列
3.1. 其他的二叉树的方法
PreOutput():output the data fields in preorder
InOutput():output the data fields in inorder
PostOutput():output the data fields in postorder
LevelOutput():output the data fields in level order
Delete():delete a binary tree,freeing up its nodes
Height():return the tree height
Size():return the number of nodes in the tree
The height of the tree is determined as: max{hl, hr}+1
1 2 3 4 5 6 7 8 template <class T > int BinaryTree<T>::Height (BinaryNode<T> *t)const { if (!t) return 0 ; int hl=Height (t->Left); int hr=Height (t->Right); if (hl>hr) return ++ hl; else return ++hr; }
3.2. String
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const int maxlen=128 ;class String { public : String (const String & ob); String (const char * init); String ( ); ~String ( ) {delete [ ] ch;} int Length ( ) const {return curlen;} String & operator ( ) (int pos, int len) ; int operator == (const String & ob) const { return strcmp (ch, ob.ch)= =0 ; } int operator !=(const String &ob) const { return strcmp (ch, ob.ch)!=0 ; } int operator ! () const { return curlen= =0 ; } String & operator = (const String & ob); String & operator +=(const String & ob); char & operator [ ](int i); int Find (String pat) const ; private : int curLen; char * ch; }
3.3. String部分方法的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 String & String::operator () (int pos, int len) { String *temp=new String; if (pos<0 || pos+len-1 >= maxlen ||len<0 ) { temp->curLen=0 ; temp->ch[0 ]="\0" ; }else { if (pos+len-1 >=curLen) len=curLen-pos; temp->curLen=len; for (int i=0 , j=pos; i<len; i++, j++) temp->ch[i] = ch[j]; temp->ch[len]=‗'\0' ; } return *temp; } String & String ::operator =(const String &ob) { if (&ob!=this ) { delete [ ] ch; ch=new char [maxLen+1 ]; if (!ch){ cerr<< "Out Of Memory! \n" ‖; exit (1 ); } curLen=ob.curLen; strcpy (ch, ob.ch); }else cout<<"Attempted assignment of a String to itself! \n" ; return *this ; }
3.4. 根据先序遍历和中序遍历生成二叉树的思路
先序遍历的第一个一定是树根,然后在中序遍历中找树根,然后在中序中树根左边是左子树,右边是右子树
3.5. C++实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 BinaryNode<Type>*void CreateBT (String pres, ins) { int inpos; BinaryNode <Type>* temp; String prestemp, instemp; if (pres.length ()==0 ) return NULL ; else { temp = new BinaryNode; temp->element=pres.ch[0 ]; inpos=0 ; while (ins.ch[inpos]!=temp->element) inpos++; prestemp = pres (1 ,inpos); instemp= ins (0 ,inpos-1 ); temp->left = CreateBT (prestemp, instemp); prestemp=pres (inpos+1 , pres.length ()-1 ); instemp=ins (inpos+1 , pres.length ()-1 ); temp->right = CreateBT (prestemp, instemp); return temp; } }
3.6. 已知其他的遍历顺序来生成二叉树
3.6.1. 已知后序遍历和中序遍历
先序遍历的树根在头部,而后序遍历串的树根在尾部。
3.6.2. 已知先序遍历和后续遍历串
先序遍历串的第二个位置是左子树(左右子树分界点),然后我们和后序遍历串结合。
3.7. 二叉树的应用
3.7.1. 二叉树的表示方式
Binary-Tree Representation of a Tree 树的存储方式:三种
广义表表示:a(b(f,g),c,d(h,i,j),e)
双亲表示法;记下自己的父结点位置,问题是:找子节点需要遍历一遍。
左子女—右兄弟表示法
!(img/cpt5/4.png)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class TreeNode : T data; TreeNode *firstchild, *nextsibling;class Tree : TreeNode * root, *current;template <class T > void Tree <T>::Insertchild (T value) { TreeNode<T>*newnode = new TreeNode <T>(value); if (current->firstchild == NULL ) current->firstchild = newnode; else { TreeNode<T>*p = current->firstchild; while ( p->nextsibling!=NULL ) p = p->nextsibling; p->nextsibling = newnode; } }
3.7.2. 将森林转换成二叉树
3.8. 树的遍历
3.8.1. 深度优先遍历(DFS)
3.8.2. 广度优先遍历
3.9. 森林的遍历
应用左子女-右兄弟的二叉树进行遍历
3.9.1. 深度优先遍历
Eg.
生成左子女-右兄弟二叉树后正常遍历即可
4. 线索二叉树
目的:让二叉树遍历的速度更快
特点:在树的节点中加入一个指针(比如指向下一个节点)
n个结点的二叉树有2n个链域,其中真正有用的是n–1个,其它n+1个都是空域(null)。为了充分利用结点中的空域,使得对某些运算更快,如前驱或后继等运算。
4.1. 例子
虚线是本身被置为NULL的部分
使用左指针指向中序遍历前项,使用右指针指向中序遍历的后项。
唯二空指针:最左边节点的左指针,最右边节点的右指针
整个树只会有两个空指针
4.2. 线索二叉树的结点的数据结构
4.3. 线索二叉树类的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template < class Type > class ThreadNode { friend class ThreadTree ; private : int leftThread, rightThread; ThreadNode<Type>* leftchild, *rightchild; Type data; public : ThreadNode (const Type item):data (item), leftchild (0 ), rihgtchild (0 ), leftThread (0 ), rightThread (0 ) {} };template < class Type > class ThreadTree { public : private : ThreadNode<Type> * root; ThreadNode<Type> *current };
4.4. 中序遍历已有的中序线索二叉树
按中序遍历中序线索树
遍历算法(以中序为例):
这里前提是中序线索树, 所以既不要递归, 也不要栈。
遍历算法:
找到中序下的第一个结点(first)
不断找后继(Next)
如何找后继?
情况一:如果p结点没有右子树(p->rightthread == 1)则 p=p->rightchild(右链就是后继)
p有右子树(p->rightThread==0) 则
p=p->rightchild
while(p->leftThread==0) p=p->leftchild;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template <class Type > ThreadNode<Type>* ThreadInorderIterator<Type>::First () { while (current->leftThread==0 ){ current = current->leftchild; } return current; }template <class Type > ThreadNode<Type>* ThreadInorderIterator<Type>::Next () { ThreadNode<Type>*p = current->rightchild; if (current->rightThread==0 ) while (p->leftThread==0 ){ p=p->leftchlid; } current=p; }template <class Type > void ThreadInorderIterator<Type>:: Inorder () { ThreadNode<Type> *p; for ( p=Frist (); p!=NULL ; p=Next ()) cout<< p->data << endl; }
4.5. 建立中序线索二叉树
对已存在的一棵二叉树建立中序线索树
分析:与中序遍历算法差不多,但是要填左空域,右空域的前驱、后继指针。所以除了流动指针p外,还要加一个pre指针,它总是指向遍历指针p的中序下的前驱结点。
Eg.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Void Inthread (threadNode<T> * T) { stack <threadNode <T>*> s (10 ) ThreadNode <T> *p = T ; ThreadNode <T> *pre = NULL ; for (;;) { while (p!=NULL ) { s.push (p); p = p ->leftchild; } if (!s.IsEmpty ()){ p = s.pop; if (pre != NULL ) { if (pre ->rightchild == NULL ){ pre ->rightchild = p; pre ->rightthread = 1 ; } if ( p -> leftchild == NULL ) { p -> leftchild = pre; p ->leftthread = 1 ; } } pre = p ; p = p -> rightchild ; } else return ; } }
5. 树的应用
5.1. 哈夫曼树(Huffman Tree)
5.1.1. 一些概念
增长树(使得原来的树的每一个度数都为2)
对原二叉树中度为1的结点,增加一个空树叶
对原二叉树中的树叶,增加两个空树叶
外通路长度(外路径)E 根到每个外结点 (增长树的叶子)的路径长度的总和(边数)
E = 3+3+2+3+4+4+3+3=25,如右上图例
内通路长度(内路径)I:根到每个内结点 (非叶子)的路径长度的总和(边数)。原来的树上每一个节点到树根的长度的综合
结点的带权路径长度:一个结点的权值与结点的路径长度的乘积。
带权的外路径长度:各叶结点的带权路径长度之和。
带权的内路径长度:各非叶结点的带权路径长度之和。
例子如下
从形状上来讲,二叉树有以上三种大致形状。
5.1.2. Huffman算法
思想:权大的外结点靠近根,权小的远离根。
算法:从m个权值中找出两个最小值W1,W2构成
就是把计算结果放进去和其他节点一起选出两个,进行迭代
所以我们就是把数字比较大的挂到距离根比较近的地方
内节点不会只有一个叶节点。
5.1.3. 霍夫曼编码
是霍夫曼树在数据编码中一种应用。具体的讲用于通信的二进制编码中。设一电文出现的字符为D={M,S,T,A,Q, K},每个字符出现的频率为W={10,29,4,8,15,7},如何对上面的诸字符进行二进制编码,使得
该电文的总长度最短。
为了译码,任一字符的编码不应是另一字符的编码的前缀
根据树情况,我们知道编码是不具有二义性的,必然唯一对应,一个叶节点就一个结果
6. 考研例题
6.1. 2019年
D
4题:C 48+63(第六层:8个叶节点+24个根节点)
5题:B 左子女右兄弟,枚举法,v有四种情况,按照左子女右兄弟即可
最左边:不是父子也不是兄弟关系
第二个:父子
第三个:无关系
第四个:兄弟
6.2. 2020年
3题:D
5题:B
总结点数:204+10 3+12+10 1+1-(20+10+1+10)=82
6题:A
7. 广义表
7.1. 广义表定义
定义为n(n>=0)个表元素a0,a1,a2,……an-1组成的有限序列, 记作: LS=(a0,a1,a2,……an-1)
其中每个表元素ai可以是原子,也可以是子表.
原子: 某种类型的对象,在结构上不可分(用小写字母表示).
子表: 有结构的。(用大写字母表示)
Eg.L = (3,(),(b,c),(((d))))
7.2. 广义表基础概念
长度:表中元素的个数
广义表的表头,表尾
head= a0;
tail= (a1, a2,……an-1)
C=(a,(5,3,x)) 表头为a,表尾为((5,3,x))
广义表的深度:表中所含括号的最大层数
7.3. 广义表的性质
有序性
有长度,有深度
可递归,如上面例6
可共享,如E中B为E,D所共享
各种广义表都可用一种示意图来表示,用圆表示表元素, 用长方形表示原子
7.4. 广义表的操作
7.5. 广义表的实现
7.6. 广义表的类声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #define HEAD 0 #define INTGR 1 #define CH 2 #define LST 3 class GenList ;class GenListNode { friend class GenList ; private : int utype; GenListNode * tlink; union { int ref; int intgrinfo; char charinfo; GenListNode * hlink; } value; public : GenListNode & info (GenListNode * elem) ; int nodetype (GenListNode * elem) {return elem->utype;} void setinfo (GenListNode * elem,GenListNode & x) ; };class GenList { private : GenListNode * first; GenListNode * Copy (GenListNode * ls) ; int depth (GenListnode * ls) ; int equal (GenlistNode * s, Genlistnode * t) ; void Remove (GenlistNode * ls) ; public : GenList ( ); ~GenList ( ); GenListNode & Head ( ) ; GenListNode * Tail ( ) ; GenlistNode * First ( ) ; GenlistNode * Next (GenListNode * elem) ; void Push (GenListNode & x) ; GenList & Addon ( GenList & list, GenListNode & x) ; void setHead (GenListNode & x) ; void setNext (GenlistNode * elem1, GenlistNode * elem2) ; void setTail (GenList & list) ; void Copy (const GenList & l) ; int depth ( ) ; int Createlist (GenListNode * ls, char * s) ; }
7.7. 广义表的实现
7.7.1. 求解广义表深度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public : int GenList::depth ( ) { return depth (first); }private : int GenList::depth (GenListNode*ls) { if ( ls-->tlink==NULL ) return 1 ; GenListNode*temp=ls-->tlink; int m=0 ; while ( temp!=NULL ) { if ( temp-->utype==LST) { int n=depth (temp-->value.hlink); if (m<n)m=n; } temp=temp-->tlink; } return m+1 ; }
7.7.2. 判断两个广义表的相等关系
相等的条件: 具有相同的结构,对应的数据元素具有相等的值
1 2 3 if (两个广义表都为空表) return 相等else if (都为原子^值相等) 递归比较同一层的后面的表元素else return 不相等.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int operator ==(const GenList&l,const GenList&m) { return equal (l.first, m.first); }int equal (GenListNode*s, GenListNode*t) { int x; if (s-->tlink==NULL &&t-->tlink==NULL ) return 1 ; if ((s-->tlink!=NULL &&t-->tlink!=NULL &&s-->tlink-->utype==t-->tlink-->utype) { if (s-->tlink-->utype==INTGR) if (s-->tlink-->value.intgrinfo== t-->tlink-->value.intgrinfo)x=1 ; else x=0 ; else if (s-->tlink-->utype==CH) if (s-->tlink-->value.charinfo==t-->tlink-->value.charinfo)x=1 ; else x=0 ; else x=equal (s-->tlink-->value.hlink, t-->tlink-->value.hlink); if (x)return equal (s-->tlink, t-->tlink); } return 0 ; }
7.7.3. 广义表的复制算法
分别复制表头,表尾,然后合成,前提是广义表不可以是共享表或递归表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public : void GenList::copy (const GenList&l) {first=copy (l.first);}private : GenListNode*GenList::copy (GenListNode*ls) { GenListNode*q=NULL ; if (ls!=NULL ) { q=new GenListNode; q-->utype=ls-->utype; Switch (ls-->utype) { case HEAD: q-->value.ref=ls-->value.ref; break ; case INTGR: q-->value.intgrinfo=ls-->value.intgrinfo; break ; case CH: q-->value.charinfo=ls-->value.charinfo; break ; case LST: q-->value.hlink=ls-->value.hlink; break ; } q-->tlink=copy (ls-->tlink); } return q; }
7.7.4. 广义表析构函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public : GenList::~GenList (){ remove (first); }private : void GenList::remove (GenListNode*ls) { ls->value.ref--; if (!ls->value.ref) { GenListNode*y=ls; while (y-->tlink!=NULL ) { y=y-->tlink; if (y-->utype= =LST) remove (y-->value.hlink); } y-->tlink=av; av=ls; } }
评论