二叉树的遍历
二叉树的遍历指的是从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。
二叉树的遍历方法:
前序遍历:规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void PreOrderTraverse(BiTree T) 2 { 3 if(T == NULL) 4 return; 5 printf("%c",T->data);/*显示结点数据,可以更改为其他对结点操作*/ 6 PreOrderTraverse(T->lchild);/* 再先序遍历左子树*/ 7 PreOrderTraverse(T->rchild);/*最后先序遍历右子树*/
中序遍历:规则是若树为空,则空操作返回,否则从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void InOrderTraverse(BiTree T) 2 { 3 if(T == NULL) 4 return; 5 InOrderTraverse(T->lchild);/*中序遍历左子树*/ 6 printf("%c",T->data);/*显示结点数据,可以更改为其他对结点操作*/ 7 InOrderTraverse(T->rchild);/*最后中序遍历右子树*/ 8 }
后序遍历:规则是若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void PostOrderTraverse(BiTree T) 2 { 3 if(T == NULL) 4 return; 5 PostOrderTraverse(T->lchild);/*先后序遍历左子树*/ 6 PostOrderTraverse(T->rchild);/*再后序遍历右子树*/ 7 printf("%c",T->data);/*显示结点数据,可以更改为其他对结点操作*/ 8 }
层序遍历:规则是若树为空,则空操作返回,否则从树的第一层也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。
二叉树的建立:将二叉树中每个结点的空指针引出一个虚结点,其值为特定值,我们称这种处理后的二叉树为原二叉树的扩展二叉树。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /*按前序输入二叉树中结点的值*/ 2 /*#表示空树,构造二叉链表表示二叉树T。*/ 3 void CreateBiTree(BiTree *T) 4 { 5 TElemType ch; 6 scanf("%c",&ch); 7 if(ch == '#') 8 *T = NULL; 9 else 10 { 11 *T = (BiTree)malloc(sizeof(BiTNode)); 12 if( !*T) 13 exit(OVERFLOW); 14 (*T)->data = ch;/*生成根结点*/ 15 CreateBiTree(&(*T)->lchild);/*构造左子树*/ 16 CreateBiTree(&(*T)->rchild);/*构造右子树*/ 17 } 18 }
线索二叉树:
线索链表:指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表。相应的二叉树称为线索二叉树。
线索化:对二叉树以某种次序遍历使其变为线索二叉树的过程。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 typedef enum {Link,Thread} PointerTag;/* Link ==0表示指向左右孩子的指针,Thread==1表示指向前驱或后继的线索*/ 2 typedef struct BiThrNode/*二叉线索存储结点结构*/ 3 { 4 TElemType data;/*结点数据*/ 5 struct BitThrNode *lchild,*rchild;/*左右孩子指针*/ 6 PointerTag LTag; 7 PointerTag RTag;/*左右标志*/ 8 }BiThrNode,*BiThrTree;
线索化的实质就是把二叉链表中的空指针改为指向前驱或后继的线索。
线索化的过程就是在遍历的过程中修改空指针的过程。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 BiThrTree pre;/*全局变量,始终指向刚刚访问过的结点*/ 2 void InThreading(BiThrTree p) 3 { 4 if(p) 5 { 6 InThreading(p->lchild);/*递归左子树线索化*/ 7 if(!p->lchild)/*没有左孩子*/ 8 { 9 p->LTag = Thread;/*前驱线索*/ 10 p->lchild = pre;/*左孩子指针指向前驱*/ 11 } 12 if(!pre->rchild)/*前驱没有右孩子*/ 13 { 14 pre->RTag = Thread;/*后继线索*/ 15 pre->rchild = p;/*前驱右孩子指针指向后继*/ 16 } 17 pre = p;/*保持pre指向p的前驱*/ 18 InThreading(p->rchild);/*递归右子树线索化*/ 19 } 20 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Status InOrderTraverse_Thr(BiThrTree T) 2 { 3 BiThrTree p; 4 p = T->lchild;/*p指向根结点*/ 5 while(p != T)/*空树或遍历结束时,p== T*/ 6 { 7 while(p->LTag == Link);/*当LTag==0时循环到中序序列第一个结点*/ 8 p = p->lchild; 9 printf("%c",p->data);/*显示结点数据,可以更改为其他对结点操作*/ 10 while(p->RTag == Thread && p->rchild != T) 11 { 12 p = p->rchild; 13 printf("%c",p->data); 14 } 15 p = p->rchild;/*p进至其右子树根*/ 16 } 17 return OK; 18 }