中序线索化二叉树数据结构.当用二叉链表作为二叉树的存储结构时,因为每个结点中只有指向其左、右孩子结点的指针,所以从任一结点出发只能直接找到该结点的左、右孩子。
在一般情况下靠它无法直接找到该结点在某种遍历次序下的前驱和后继结点。
如果在每个结点中增加指向其前驱和后继结点的指针,将降低存储空间的效率。
与此同时,我们可以证明:在n个结点的二叉链表中含有n+1个空指针。
因为含n个结点的二叉链表中含有2n个指针,除了根结点,每个结点都有一个从父结点指向该结点的指针,因此一共使用了n-1个指针,所以在n个结点的二叉链表中含有2n-(n-1)=n+1个空指针。
因此,可以利用这些空指针,存放指向结点在某种遍历次序下的前驱和后继结点的指针。
这种附加的指针称为线索,加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。
为了区分一个结点的指针是指向其孩子的指针,还是指向其前驱或后继结点的线索,可在每个结点中增加两个线索标志。
这样,线索二叉树结点类型定义为:LchildLtagDataRtagRchild其中:1. Ltag=0时,表示Lchild指向该结点的左孩子;2. Ltag=1时,表示Lchild指向该结点的线性前驱结点;3. Rtag=0时,表示Rchild指向该结点的右孩子;4. Rtag=1时,表示Rchild指向该结点的线性后继结点;以二叉链表结点数据结构所构成的二叉链表作为二叉树的存储结构,叫做线索二叉链表;指向结点的线性前驱或者线性后继结点的指针叫做线索;加上线索的二叉树称为线索二叉树;对二叉树以某种次序遍历将其变为线索二叉树的过程叫做线索化。
中序线索化是指用二叉链表结点数据结构建立二叉树的二叉链表,然后按照中序遍历的方法访问结点时建立线索。
例如有如上图所示二叉树,则中序遍历的顺序是:O / J * I + H A G【参考程序】#include <stdio.h>#include <malloc.h>typedef enum{Link,Thread} PointerTag; /*指针标志*/typedef char DataType;typedef struct BiThreTree{ /*定义结点元素*/PointerTag LTag,RTag;DataType data;struct BiThreTree *lchild,*rchild;}BiThreTree;BiThreTree *pre; /*全局变量,用于二叉树的线索化*/BiThreTree *CreateT ree() /*按前序输入建立二叉树*/{BiThreTree *T;DataType ch;scanf("%c",&ch);if(ch==’#’)T=NULL;else{T=(BiThreTree *)malloc(sizeof(BiThreTree));T->data=ch;T->LTag=Link; /*初始化时指针标志均为Link*/T->RTag=Link;T->lchild=CreateTree();T->rchild=CreateTree();}return T;}void InThread(BiThreTree *T){BiThreTree *p;p=T;if(p){InThread(p->lchild);if(!p->lchild){ p->LTag=Thread;p->lchild=pre;}if(!pre->rchild){ pre->RTag=Thread;pre->rchild=p;}pre=p;InThread(p->rchild);}}BiThreTree *InOrderThrTree(BiThreTree *T) /*中序线索化二叉树*/ {BiThreTree *Thre; /*Thre为头结点的指针*/ Thre=(BiThreTree *)malloc(sizeof(BiThreTree));Thre->lchild=T;Thre->rchild=Thre;pre=Thre;InThread(T);pre->RTag=Thread;pre->rchild=Thre;Thre->rchild=pre;return Thre;}void InThrTravel(BiThreTree *Thre) /*中序遍历二叉树*/{BiThreTree *p;p=Thre->lchild;while(p!=Thre) /*指针回指向头结点时结束*/ {while(p->LTag==Link)p=p->lchild;printf("%4c",p->data);while(p->RTag==Thread&&p->rchild!=Thre){p=p->rchild;printf("%4c",p->data);}p=p->rchild;}}void main(){BiThreTree *T,*Thre;printf(“PreOrder Create Binary Tree:\n”);T=CreateTree();Thre=InOrderThrTree(T);printf(“InOrder Traverse Binary Tree:\n”);InThrTravel(Thre);system("pause");}【调试举例】(1)建立二叉树时,按先序遍历方式输入:“ABD##EH##I##CF##G##”,其中“#”表示空指针。
(2)建立的二叉树为:AB CD E F GH I(3)程序输出为中序遍历线索化二叉树的结果:DBHEIAFCG已知A、B和C为三个递增有序的线性表,现要求对A表作如下操作:删除那些既在B表中出现又在C表中出现的元素。
【实验步骤】1.试对顺序表编写实现上述操作的算法并上机编写代码,要求算法尽可能高效。
在实验报告中分析你的算法的时间复杂度。
2.A表中要删除的元素实际上就是在三个表中都存在的元素。
注意这三个线性表都是递增有序的线性表!可以利用这一性质减少对线性表“扫描”的趟数。
3.改用单链表作为存储结构编写算法,请释放A表中无用的结点空间,并上机编程实现。
【算法思想】先从B和C中找出共有元素same,再从A中从当前位置开始,凡小于same的元素均保留,等于same的就跳过,大于same时就再找下一个same。
【顺序存储结构算法描述】void SqList_Delete(SqList&A, SqList B, SqList C){i=0;j=0;m=0;/*i指示A中元素原来的位置,m为移动后的位置*/while(i<A.length&&j<B.length&&k<C.length){if(B.elem[j]<C.elem[k]) j++;else if(B.elem[j]>C.elem[k])k++;else{same= B.elem[j];/*找到了相同元素same*/while(B.elem[j]==same)j++;while(C.elem[k])==same)k++;/*j,k后移到新的元素*/while(i<A.length&&A.elem[i]<same)A.elem[m++]=A.elem[i++];/*需要保留的元素移动到新位置*/while( i<A.length&&A.elem[i]==same)i++;}/*else*/}/*while*/while(i<A.length)A.elem[m++]=A.elem[i++];/*A的剩余元素重新存储*/A.length=m;}/*SqList_Delete*/【顺序存储结构参考程序】#include<stdio.h>main(){#define N 3/*宏定义,代表数组维数*/#define M 4#define T 5int i,j,k,r,m,same;/*定义变量分别指向数组a,b,c*/int a[N],b[M],c[T];printf(“please input numbers:\n”);for (i=0;i<N;i++) scanf("%d",&a[i]);for (j=0;j<M;j++) scanf("%d",&b[j]);for (k=0;k<T;k++) scanf("%d",&c[k]);i=0;j=0;m=0;k=0;/*分别赋值为0,即指向数组的第一元素*/ while(i<N&&j<M&&k<T){if(b[j]<c[k])j++;else if(b[j]>c[k]) k++;else{same=b[j];while(b[j]==same)j++;while(c[k]==same)k++;while(i<N&&a[i]<same)a[m++]=a[i++];while(i<N&&a[i]==same) i++;}}while(i<N)a[m++]=a[i++];printf("a[%d]={",m);/*输出删除元素后的数组a/*for (r=0;r<m-1;r++)printf("%d,",a[r]);printf("%d",a[m-1]);printf("}\n");return;}【程序调试】程序运行是屏幕显示:please input numbers: 此时输入三组测试数据,数据间用空格隔开:2 3 4回车3 4 5 6 回车4 5 6 7 8 回车程序输出结果:a[3]={2,3},即删除了数组a中即在b和c中都出现的元素。
【单链表存储结构参考程序】# include <stdio.h># include <stdlib.h>Typedef struct LNode{int data;struct LNode *next;}Lnode,*LinkList;/*定义链表节点的结构*/void main ( ){/*功能:建立单链表A,B,C,并且删除A中均在B和C中出现的数据。