1、1vocabulary:.predecessor:前任,前辈immediate predecessor:直接前趋immediate successor:直接后继crunode/node:节点algorithm:算法algorithm analysis:算法分析stack:堆积pop:突然离去 pop off:突然死去parameter:参数substring:子串,子链concatenation:联接,一系列nave:朴素的,无经验的,单纯的,天真的,轻信的NaiveStrMatch:朴素的串匹配算法tuple:元组,数组trituple:三元数组matrix:矩阵 (pl):matrices
2、/matrixes:inverse matrix:逆矩阵correlation matrix:相关矩阵,转矩阵transposed matrix:转置矩阵discrete:分离的,不相关联的descend:下来,下去 descendable:可遗传的descendance:后裔 descendant:后代,后裔traversal:遍历, (横向)往返移动preorder traversal:前序遍历postorder traversal:后序遍历probability:概率vertex: 顶,顶点edge:边,棱,边缘multibaseoutput:多基输出base:基,基数adjacent:
3、邻近的,邻近点adjacence:接近,毗连factorial:阶乘,阶乘积 factor:因子,因数,因素,要素variable:可变因数,变数,弯化的,可变的,易变的,变量local variable:局布变量symmetry:对称(性) ,匀称,整齐infinity:无穷大,无限大spanning:生成的 spanning tree:生成树 spanning set:生成集 spanning space:生成空间 spanning forest:生成森林 spanning subgraph:生成子树in-place sort:就地排序sentinel:(n):哨兵,(vt):守卫,放哨p
4、ivot:(n):枢轴;中心点;基准,支点partition:划分;分开;分割,heap:堆,许多,累积;(vt):堆,堆积;( vi)堆起来heapify:堆化merge:合并,使合并;吞没;融合encode:把译成密码(或电码) ;把.编码decode:解码radix:根; 数基数 -pl:radices/radixescylinder:柱面,圆筒,汽缸track/magnetic track:磁道hash:(n):剁碎的食物,杂乱无章的一大堆.(vt):切碎dense index:稠密索引sparse index:稀疏索引sequential storage structure:顺序存储
5、结构linked storage structure:链接存储结构binary tree:二叉树sibling:兄弟 ancestor:祖先Huffman:哈夫曼WPL(Weighted Path Length of Tree):带树路径长度2.线性表:Linear List约定俗的,线性表就形如:(a1,a2,a3,.,an),但在计算机中数组是从 a0开始的,这里就有个转化问题基本操作:1:InitList(L)2:ListLength(L)3:GetNode(L,i)4:LocateNode(L,x) /在线性表中按关键词 x 查找5:InsertList(L,x,i)6:DeleteL
6、ist(L,i)2.1:顺序表(Sequential List )定义:#define ListSize 100typedef int DataType;typedef struct DataType dataListSize;int length;Seqlist;顺序表上实现的操作:void InsertList(SeqList *L,DataType x,int i)int j;if(iL-length+1)printf(“position error!n”);exit(1);if(L-length=ListSize)printf(“overflow”);exit(1);for(j=L-l
7、ength-1;j=i-1;j-)L-dataj+1=L-dataj;L-datai-1=x; L-length+;void DeleteList(SeqList *L,int i)int j;if(iL-length)printf(“position errorn”);exit(1); if(L-lengthlength-1;j+)L-dataj=L-dataj+1;L-length-;2.2 链表(Linked List)2.21 单链表(Single Linked List)结构描述:typedef char DataType;typedef struct node DataType d
8、ata;struct node *next;ListNode;typedef ListNode *LinkList;ListNode *p;LinkList head;单链表的建立:1).头插法建立单链表:LinkList CreateListF(void)char ch;ListNode *s; /工作结点;LinkList head; /头指针head=NULL;ch=getchar();while(ch!=n)s=(ListNode *)malloc(sizeof(ListNode);s-data=ch;s-next=head;head=s;ch=getchar();return hea
9、d;2).尾插法建立单链表:LinkList CreateListR(void)LinkList head;ListNode *s,*r; /r 为尾指针char ch;head=r=NULL;while(ch=getchar()!=n)s=(ListNode *)malloc(sizeof(ListNode);s-data=ch;if(head=NULL)head=s;elser-next=s;r=s; / end of whileif(r!=NULL)r-next=NULL;return head; 3).尾插法建立带头结点的单链表:LinkList CreateListR1(void)c
10、har ch;ListNode *s,*r;LinkList head=(LinkList)malloc(sizeof(ListNode);r=head; while(ch=getchar()!=n)s=(ListNode *)malloc(sizeof(ListNode);s-data=ch;r-next=s;r=s;r-next=NULL;return head; 单链表的查找运算:1).按序号查找:ListNode *GetNode(LinkList head,int i)int j;ListNode *p;p=head; j=0;while(p-nextj+;if(i=j)return
11、 p;return NULL; 2).按值查找:(以带头结点为例:)ListNode *LocateNode(LinkList head,DataType key)ListNode *p=head-next;while(preturn p;单链表的插入运算(仍以带头结点为例 ):void InsertList(LinkList head,DataType x,int i)ListNode *p;ListNode *s;p=GetNode(head,i-1);if(p=NULL)printf(“position error!n”);exit(1);s=(ListNode *)malloc(siz
12、eof(ListNode)s-data=x;p-next=s;s-next=p-next;单链表的删除运算(仍以带头结点为例 ):void DeleteList(LinkList head,int i)ListNode *p,*r;p=GetNode(head,i-1); if(p=NULL|p-next=NULL) /注意这个条件很重要,仔细思考一下。printf(“position error!n”);exit(1);r=p-next;p-next=r-next;free (r);2.22.循环链表(Circular Linked List):即首尾相接的链表:2.23.双链表(Doubl
13、e Linked List)描述:typedef char DataType;typedef struct dlistnode DataType data;struct dlistnode *prior,*next;DListNode;typedef DListNode *DLinkList;DLinkList head;双链表的前插操作:void DInsertBefore(DListNode *p,DataType x)DListNode *s=(DListNode *)malloc(sizeof(DListNode);s-data=x;s-prior=p-prior;s-next=p;p
14、-prior-next=s; p-prior=s;双链表上删除操作:void DDeleteNode(DListNode *p)p-prior-next=p-next;p-next-prior=p-prior;free(p);3.栈(stack) 约定好的,栈顶用 Top,栈底用 Bottom;栈的基本操作:1).InitStack(S)2).StackEmpty(S)3).StackFull(S)4).Push(S,x)5).Pop(S)6).StackTop(S)3.1:顺序栈结构描述:#define StackSize 100typedef char DataType;typedef s
15、truct DataType dataStackSize;int top;SeqStack;基本操作的实现:void InitStack(SeqStack *S)S-top=-1;int StackEmpty(SeqStack *S)return S-top=-1;int StackFull(SeqStack *S)return S-top=StackSize-1;void Push(SeqStack *S,DataType x)if(StackFull(S)printf(“Stack overflow!n”);exit(1);S-data+S-top=x;DataType Pop(SeqSt
16、ack *S)if(StackEmpty(S)printf(“Stack underflow!n”);exit(1);return S-dataS-top-;DataType StackTop(SeqStack *S)if(StackEmpty(S)printf(“Stack is empty!n”);exit(1);return S-dataS-top;3.2.链栈结构描述:typedef char DataType;typedef struct stacknode DataType data;struct stacknode *next;StackNode;typedef struct S
17、tackNode *top;LinkStack;基本操作的实现:void InitStack(LinkStack *S)S-top=NULL:int StackEmpty(LinkStack *S)return S-top=NULL;void Push(LinkStack *S,DataType x)StackNode *p=(StackNode *)malloc(sizeof(StackNode);p-data=x;p-next=S-top;S-top=p;DataType Pop(LinkStack *S)DataType temp;StackNode *p=S-top;if(StackE
18、mpty(S)printf(“Stack underflow!n”);exit(1);temp=p-data;S-top=p-next;free(p);return temp;DataType StackTop(LinkStack *S)if(StackEmpty(S)printf(“Stack is empty!n”);exit(1);return S-top-data;4.队列(Queue)队列上实现的操作:1).InitQueue(Q)2).QueueEmpty(Q)3).QueueFull(Q)4).EnQueue(Q)5).DeQueue(Q)6)QueueFront(Q)4.1.顺
19、序队列(循环队列)结构描述:#define QueueSize 100typedef char DataType;typedef struct DataType dataQueueSize;int front;int rear;int count;CirQueue;基本操作的实现:/这里要清楚,队列中的 rear 指针始终是指向下一个将要被插入的数据的位置,而这个位置,理论是应该是空的内存块。void InitQueue(CirQueue *Q)Q-front=Q-rear=0;/联想到循环队列的圆盘模型,仅从 Q-front=Q-rear 无法判定该队列是空还是满,所以必须加下第二个语句。Q
20、-count=0;int QueueEmpty(CirQueue *Q)return Q-count=0;int QueueFull(CirQueue *Q)return Q-count=QueueSize;void EnQueue(CirQueue *Q,DataType x)if(QueueFull(Q)printf(“Queue overflow!n”);exit(1);Q-dataQ-rear=x;Q-rear=(Q-rear+1)%QueueSize; /更新尾指针指向。Q-count+; /更新数据个数DataType DeQueue(CirQueue *Q)DataType te
21、mp;if(QueueEmpty(Q)printf(“Queue underflow!n”);exit(1);temp=Q-dataQ-front;Q-count-;Q-front=(Q-front+1)%QueueSize;return temp;DataType QueueFront(CirQueue *Q)if(QueueEmpty(Q)printf(“Queue is empty!n”);exit(1);return Q-dataQ-front;4.2.链队列:结构描述:typedef char DataType; / front-|-|-|typedef struct queueno
22、de / rear-DataType data;struct queuenode *next;QueueNode;typedef struct QueueNode *front;QueueNode *rear; /实际这里考虑实际应用,可以再加上一个结点计数器 int count;LinkQueue;基本操作的实现:void InitQueue(LinkQueue *Q)Q-front=Q-rear=NULL;int QueueEmpty(LinkQueue *Q)return Q-front=NULL;void EnQueue(LinkQueue *Q,DataType x) QueueNo
23、de *p=(QueueNode *)malloc(sizeof(QueueNode);p-data=x;p-next=NULL;/为了防止指针乱指,一开始就令指针域为 NULL;防患于未然if(QueueEmpty(Q)Q-front=Q-rear=p;/注意第一个数据的插入方法else Q-rear-next=p;Q-rear=p;DataType DeQueue(LinkQueue *Q)DataType temp;QueueNode *p;if(QueueEmpty(Q)printf(“Queue underflow!n”);exit(1);p=Q-front;temp=p-data;
24、Q-front=p-next;if(Q-rear=p) /*这点必须考虑到,当队列中只有一个节点时,尾指针的处理。Q-rear=NULL;free(p);return temp;DataType QueueFront(LinkQueue *Q)if(QueueEmpty(Q)printf(“Queue is empty!n”);exit(1);return Q-front-data;5.串(String) d 注意区分”空串”和”空白串”的概念空串:指长度为零的串空白串:指仅由一个或多个空格组成的串。串上的基本操作,在中:int strlen(char *s);char *strcpy(cha
25、r *to,char *from);char *strcat( char *to,char *from);int strcmp(char *s1,char *s2);char *strchr(char *s,char c);/返回 c 在 s 中第一次出现的位置,找不到就返回 NULL;5.1.串的存储结构:5.11.串的顺序存储:串的静态顺序存储:Way1: #define MaxStrSize 256typedef char SeqStringMaxStrSize;SeqString S;Way2: #define MaxStrSize 256typedef struct char chM
26、axStrSize;int length;SeqString;串的动态顺序存储:typedef struct char *s;int length;HString;5.12.串的链式存储:typedef struct node char data;struct node *next;LinkStrNode;typedef LinkStrNode *LinkString;LinkString S;在实际应用中,可以根据结点的类型不同而设定一下:#define NodeSize 80typedef struct node char dataNodeSize;struct node *next;Li
27、nkStrNode;typedef LinkStrNode *LinkString;LinkString S;5.2.串上的操作(子串定位)子串定位又称模式匹配(Pattern Matching)或串匹配(String Matching)在串匹配中,一般将主串称为目标(串) ,子串称为模式(串) ,假设以 T 为目标(串) ,P 为模式(串) ,形如:T=”t(0)t(1)t(2)t(n-1)”,P=”p(0)p(1)p(2)p(m-1)”, (0data=p-data)t=t-next;p=p-next;else shift=shift-next;t=shift;p=P; /end of w
28、hileif(p=NULL)return shift; /匹配成功elsereturn NULL; 下面是我自己写的算法,并且调试好了,也能达到预期的效果。LinkStrNode *LinkStrMatch(LinkString T,LinkString P)LinkStrNode *m,*n;while(T)m=T;n=P;while(m-data=n-datan=n-next;if(n=NULL)return T;T=T-next;return NULL;6多维数组和广义表:数组的两种顺序存储方法:1).行优先顺序:形如:a11,a12,a1n,a21,a22,a2n,am1,am2,am
29、n;2).列优先顺序:形如:a11,a21,am1,a12,a22,am2,a13,a23,am3;默认的都以行优先顺序存储数组,其地址计算方法也模式化了:二维数组 Amn: LOC(aij)=LOC(a11)+(i-1)*n+(j-1)*d;三维数组 Amnp:LOC(aijk)=LOC(a111)+(i-1)*n*p+(j-1)*p+(k-1)*d;*注:这里二维数组可以看成是 m 长 n 宽的矩形,三维数组可以看成是 m 长 n 宽 p 高,这里 d 表示存储单元长度(逻辑上可以认为是 1) ; 7.矩阵的压缩存储:7.1.特殊矩阵:7.11 对称矩阵:即在 n 阶方阵 A 中,元素满足
30、:aij=aji,0=j)对于 aij,在 i 行之前有 0,1,i-1,又第 i 行有 i+1 个元素,在 j 之前有 0,1,j-1,也有 j 个元素,于是:k=i(i+1)/2+j; 0j /这里是常数 c 存储的位置对于下三角矩阵:k=i(i+1)/2 当 i=jk=n(n+1)/2 当 im=a-n;b-n=a-m;b-t=a-t;q=0;if(b-tn;col+)for(p=0;pt;p+)if(a-datap.j=col)b-dataq.i=a-datap.j;b-dataq.j=a-datap.i;b-dataq.v=a-datap.v;q+; /TransMatrix7.22
31、.带行表的三元组表:有时为了方便某些矩阵运算,可以在按行优先存储的三元组表中,加入一个行表(RowTab)来记录稀疏矩阵中每行的非零元在三元组表中的起始位置,当将行表作为三元组表的一个新增属性加以描述 时,就会得到稀疏矩阵的另一种顺序存储结构 :带行表的三元组表.其类型描述如下:#define MaxSize 100 /按实际需要可以更改#define MaxRow 100 /在三元组表定义前加入此最大行定义typedef int DataType;typedef struct int i,j;DataType v; /非零元素的值 valueTriTupleNode;typedef stru
32、ct TriTupleNode dataMaxSize;int RowTabMaxRow;int m,n,t;RTriTupleTable;7.3.广义表的概念:广义表(Lists,又称列表)是线性表的推广,线性表的元素仅限于原子项,原子是作为结构上不可分割的成分,它可以是一个数或一个结构,若放松对表元素的这种限制,容许它们具有其自身构这就产生了广义表的概念。EG:E=()L=(a,b)A=(x,L)=(x,(a,b)B=(A,y)=(x,(a,b),y)C=(A,B)=( (x,(a,b), (x,(a,b),y)D=(a,D)=(a,(a,(a,() /D 为无限的广义表;*表的深度:指表
33、从里往外数的层数;8.树(tree)8.1.二叉树(binary tree)满二叉树(Full Binary Tree):一棵深度为 k 且有 2k-1 个结点的二叉树称为满二叉树(直观上就是树上叶子长满了)完全二叉树(Complete Binary Tree): 若一棵二叉树最多只有最下面的两层上结点的度数可以小于2,并且最下一层上的结点都集中在该层最左边的若干个位置上,则此二叉树称为完全二叉树。性质 1:二叉树第 i 层上的结点数目最多为 2(i-1).(第一层有 2(1-1)个结点,第二层有 2(2-1)个结点)性质 2:深度为 k 的二叉树至多有 2k-1 个结点(因为 20+21+2
34、(k-1)=2k-1)性质 3:在任意一棵二叉树中,若终端结点的个数为 n0,度为 2 的结个数为 n2,则 n0=n2+1.*性质 3 的证明见书本。性质 4:具有 n 个结点的完全二叉树的深度为 log2(n+1).(推导:2(k-1)-11,则 Ki 的双亲编号为 int(i/2),若 i=1,则 Ki 无双亲,它是根结点(2).若 2iint(n/2)的结点都是叶子。(3).若 2i+1data=ch;CreateBinTree(CreateBinTree(*在这里说明一下为什么用到指向指针的指针(即二级间访的指向指针)我们知道函数的值传递是改变了不原来的值的,如int a=10;vo
35、id add(int x)x+=10;当调用 add(a);时,a 的值不会增加,因为值传递是单向的,值传不回去,如果想让值传回去,可有用指针。如:int a=10;*关于中遍历和后序遍历的构造方法暂时还没想出来。void add( int *p)*p+=10;同样的,对于二叉链表,如果仅把 BinTree T 的 T 当参数传给函数 CreateTree(),那么显然值是传不回来的,所以要把它的地址传给函数,在函数 CreateTree()内部要用运算符*取指针的值.8.13 二叉树的遍历(traversal)1)中序遍历(Inorder Traversal )void Inorder(Bi
36、nTree T) if(T)Inorder(T-lchild);printf(“%c”,T-data);Inorder(T-rchild); 2)前序遍历(Preorder Traversal)void Preorder(BinTree T) if(T)printf(“%c”,T-data);Preorder(T-lchild);Preorder(T-rchild); 3)后序遍历(Postorder Traversal)void Postorder(BinTree T)if(T)Postorder(T-lchild);Postorder(T-rchild);printf(“%c”,T-dat
37、a);8.14 线索二叉树(Threaded Binary Tree)*问题的提出:当用二叉链表作为二叉树的存储结构时,因为每个结点中只有指向其左,右孩子结点的指针域,所以从任一结点出发只能直接找到该结点的左右孩子,而一般情况下无法直接找到该结点在某种遍历中的前趋和后继结点,又一个 n 个结点的二叉树有 n+1 个指针域是空着的,因此可以把它们利用起来,存放指向结点在某种遍历次序下的前趋和后继结点,这种把这些空指针域利用起来的二叉树称为线索二叉树(Threaded Binary Tree)线索化:把二叉树变为线索二叉树的过程称为二叉树的线索化。这里要对二叉树的结构做小小的修改:Struct m
38、odel: lchildltagdatartagrchildtypedef enum Link,Thread PointerTag;typedef char DataType;typedef struct nodeDataType data;PointerTag ltag,rtag; /左右标志struct node *lchild,*rchild;BinThrNode;typedef BinThrNode *BinThrTree;1).二叉树的线索化算法:(这个算法有点小复杂,又是递归,又是全局量指针的)BinThrNode *pre=NULL; /全局量void InorderThread
39、ing(BinThrTree p)if(p)InorderThreading(p-lchild);p-ltag=(p-lchild) ? Link:Thread;p-rtag=(p-rchild) ? Link:Thread;if(pre)if(pre-rtag=Thread)pre-rchild=p;if(p-ltag=Thread)p-lchild=pre;pre=p;InorderThreading(p-rchild);/endif /InorderThreading 2).线索二叉树上的运算:查找某结点*p 在指定次序下的前趋和后继结点.在中序线索二叉树中,查找结点*p 的中序后继分两
40、种情况:(1).若结点*p 的右子树为空(即 p-rtag=Thread),那么它的右指针域指向的就是它的中序后继(2).若结点*p 的右子树不为空(即有右孩子),那么它的中序后继结点必是沿着它的右孩子开始,沿着该孩子的左链往下找,直到找到第一个没有左孩子的结点,因为只有这样的结点,它的左指针域才能空出来指向它的直接前趋。简单的说,就是结点*p 的“右孩子的最左下的结点“.相应的算法。BinThrNode *InorderSuccessor(BinThrNode *p)BinThrNode *q;if(p-rtag=Thread)return p-rchild;elseq=p-rchild;/
41、其实这里为了减少变量,可以直接令:p=p-rchild;while(q-ltag=Link)q=q-lchild;return q;由于树的左右孩子具有对称性,所以可直接给出求中序前趋的算法为(思路和上面的分析一样,*p的中序前趋是*p 的“左孩子的最右下的结点“):BinThrNode *InorderPredecessor(BinThrNode *p)BinThrNode *q;if(p-ltag=Thread)return p-lchild;elseq=p-lchild;while(q-rtag=Link)q=q-rchild;return q; /end if 3).线索二叉树分析:在
42、经线索化后的二叉树中,对于结点*p,若*p 的左右孩子非空,则*p 的中序前趋(或中序后继)是从*p 的左孩子(或右孩子)开始往下找,由于二叉链表中的结点是向下链接的,所以即使在非线索化的二叉树也能做到求出其中序前趋(或中序后继) ;若*p 的左右孩子为空,则它的左右指针域的指向就是对应的中序前趋(或中序后继) ,但如果二叉树之前没有经过线索化,由于树的结点中没有指向其双亲的指针,就无法找到其中序前趋(或中趋后继) ,必须从根结点开始遍历才行,由此可见,线索使得查找中序前趋和中序后继变得简单而有效,然而线索对于查找指定结点的前序前趋和后序后继却没有什么帮助.*在后序线索二叉树中(注意,这里的二
43、叉树已经按后序规律被线索化了) ,查找指定结点*p 的后序前趋结点规律如下(注意讨论):(1).若*p 的左子树为空,那么,它有没有右子树都没关系,它的左指针域都指向它的后序前趋(当它也没有右子树时,它是叶子,可以画图看一下,它的左指针域确实指向它的后序前趋,当它有右孩子,它的左指针域指向它的右孩子,它的右孩子就是它的后序前趋,因为它作为双亲,总是最后一个被访问的)(2).若*p 折左子树非空,则 p-lchild 不是前趋线索,但因为在后序遍历时,根是在遍历其左右子树之后被访问的,故*p 的后序前趋必是两子树中最后一个遍历到的结点。现在讨论,当*p 的右子树非空,很简单,*p 的后序前趋就是
44、它的右子树;当*p 的右子树为空的,则按照后序遍历规则(先左子树,后右子树,两双亲) ,这里右子树为空了,访问完左子树后就直接访问对亲*p,因此,*p 的后序前趋就是其左子树查找结点*p 的后序后继结点规律:(1).若*p 为根,则*p 是最后一个被访问到的结点。(2).若*p 是其双亲的右孩子,则*p 的后序后继结点就是其双亲(3).若*p 是其双亲的左孩子,且*p 无右兄弟,则*p 的后序后继结点也同样是其双亲;(4).若*p 是其双亲的左孩子,但*p 有右兄弟,则*p 的后序后继结点是其双亲的右子树中第一个后序遍历到的结点,它是该子树中“最左下的叶结点“;*从以上分析要知,仅从*p 出发
45、就能找到其后序前趋结点(这点在以上讨论过了,确实可以) ,但要找*p 的后序后继结点,仅当*p 的右子树为空时, p-rchild 才能空出来作为线索指向它的后序后继(想一下) ,其它情况下,由于*p 的唯一可以作为线索的指针域都被占用了,从而从*p 无法找到它的双亲,基于以上总结上找*p 的后序后继结点的规律都没法用,所以只能从根结点开始进行后序遍历来找*p 的后序后继结点,此时线索对于这种情况也无济于事。*在前序线索二叉树中,同样可以总结类似的查找指定结点*p 的前序前趋和前序后继结点的规律:求结点*p 的前序后继结点规律:(1).当*p 有左孩子时,其左孩子就是它的前序后继结点。(2).
46、当*p 没有左孩子,但有右孩子,其右孩子就是它的前序后继结点。(3).当*p 没有左右孩子时(即它是叶子) ,它的右指针域指向它的前序后继结点。求结点*p 的前序前趋结点规律:(1).当*p 为其双亲的左孩子,则*p 的前序前趋结点就是其双亲;(2).当*p 是其双亲的右孩子,且*p 没有左兄弟,*p 的前序前趋结点出同样是其双亲;(3). 当*p 是其双亲的右孩子,但 *p 有左兄弟,则*p 的前序前趋结点是其双亲左子树中最后一个前序遍历到的结点,它是该子树中“最右下的叶结点“;由于无法判断*p 是其双亲的左孩子还是右孩子,所以不易找到其前序前趋;4).遍历线索二叉树:*遍历线索二叉树时,只
47、要按照其种遍历次序,反复找到结点的后继结点就行了,这对于中序后继和前序后继很容易实现,但对于前序后继不好实现。下面给出中序线索二叉树的算法:void TraverseInorderThrTree(BinThrTree p)if(p)while(p-ltag=Link)p=p-lchild;/从根结点往下找最左下结点,即中序遍历的开始结点doprintf(“%c“,p-data);p=InorderSuccessor(p); /函数 InorderSuccessor()要上面实现。while(p); /endif8.2.树和森林8.2.1.树,森林与二叉树的转换(规律是死的,remmber it
48、)树到二叉树的转化:(1).在所有兄弟结点之间加一虚线(指同一个双亲的兄弟,一个奶的堂兄弟不能连)(2).对每个结点,除了保留与其长子的连线外,去掉该结点与其它孩子的连线(不能去掉虚线)二叉树到树和森林的转化:如果结点 x 是其双亲 y 的右孩子,则把 x 的右孩子,右孩子的右孩子,都与 y 用连线连起来,最后去掉所有双亲到右孩子的连线(但刚刚连的线不要碰它,它们不算在内)8.2.2树的存储结构8.2.21 双亲链表表示法(基于每个结点的双亲是惟一的 ):#define MaxTreeSize 100typedef char DataType;typedef struct DataType data;int parent;PTreeNode;typedef struct PTreeNodeMaxTree