本部分中的非递归方式的3种遍历方式相对复杂。
非递归 先序 遍历
Traverse 美 [trəˈvɜrs] n.穿过; 横贯,横切; 横木; [建]横梁 vt.横越,横贯; 通过; [法]否认,反驳; [木工]横刨 vi.来回移动; 旋转; 横越; adj.横贯的; 横切的;
//b: 指向二叉树的根节点void PreOrderTraverse(BiTree b){//建栈InitStack(S);//设置临时的辅助指针,功能: 遍历结点,初值为指向根节点BiTree p = b;//p指向的结点不为空 || 栈不为空while(p || !IsEmpty(S)){//1. 从根结点走到左下角最下面的结点:每个结点,先访问(E.g 打印该结点数据),再压栈;//简记:只要左子树存在,就一直循环下去(访问+压栈),否则跳出当前循环;while(p){printf("%c",p->data); //先访问:先序先遍历当前p指向的结点Push(S,p); //压栈:将指向当前结点的指针(简记:将当前结点压栈),先压进栈保存p=p->lchild; //让当前指针指向左孩子;}//2. 先将最左下角结点出栈(即:top保存的结点出栈),然后访问它的右子树,直到栈为空;//先判断当前栈是否有数据,如果有则出栈;if(!IsEmpty(S)){//让临时指针指向当前栈顶元素出栈,让p指向栈顶对应的结点:p = Pop(S);//然后让临时指针再指向当前结点的右孩子(右子树):p = p->rchild;}}}

非递归 中序 遍历
void MidOrderTraverse(BiTree b){//建栈InitStack(S);//设置临时的辅助指针,功能: 遍历结点,初值为指向根节点BiTree p = b;//p指向的结点不为空 || 栈不为空while(p || !IsEmpty(S)){//1. 从根结点走到左下角最下面的结点:每个结点,先访问(E.g 打印该结点数据),再压栈;//简记:只要左子树存在,就一直循环下去(访问+压栈),否则跳出当前循环;while(p){//printf("%c",p->data); //先访问:先序先遍历当前p指向的结点Push(S,p); //压栈:将指向当前结点的指针(简记:将当前结点压栈),先压进栈保存p=p->lchild; //让当前指针指向左孩子;}//2. 先将最左下角结点出栈(即:top保存的结点出栈),然后访问它的右子树,直到栈为空;//先判断当前栈是否有数据,如果有则出栈;if(!IsEmpty(S)){//让临时指针指向当前栈顶元素出栈,让p指向栈顶对应的结点:p = Pop(S);//把访问放到这里:printf("%c",p->data); //访问:先序先遍历当前p指向的结点//然后让临时指针再指向当前结点的右孩子(右子树):p = p->rchild;}}}

非递归 后续 遍历
void PostOrderTraverse(BiTree b){//建栈InitStack(S);//设置临时的辅助指针,功能: 遍历结点,初值为指向根节点BiTree p = b;//用于记录刚刚访问过的右子树的父结点:BiTree r = NULL;//p指向的结点不为空 || 栈不为空while(p || !IsEmpty(S)){//1. 从根结点到最左下角的左子树都入栈;//因为外循环while()已经包含了p的情况,所以这里可以直接判断:if(p){//压栈:将指向当前结点的指针(简记:将当前结点压栈),先压进栈保存Push(S,p);//让当前指针指向左孩子;p=p->lchild;//然后返回到外循环while(),再继续判断p左孩子是否存在,如果存在则继续压栈;}//2. 返回栈顶的2种情况,需要分别处理:else{//只取栈顶的元素,先不出栈。相当于先试读一下栈顶的元素(让p指向栈顶对应的结点):GetTop(S,p);//2.1 如果从左子树返回父结点,右子树还没有访问,则让p指向当前结点的右子树://p指向的当前结点的右子树存在 && 相邻两次访问的结点是右结点if(p->rchild && p->rchild != r){p = p->rchild;}//2.2 如果从右子树返回其父节点,则出栈,else{//让临时指针指向当前栈顶元素出栈,让p指向栈顶对应的结点://不让p指向该栈顶结点元素,下面一句真么访问打印其内容呢?呵呵,所以要出栈。Pop(S,p);//然就访问该结点:printf("%c",p->data);//让r指向p,进行备份p的值,目的是让下次比较其是否相等,如果相等说明已经访问了右子树,如果不相等则说明还没有访问右子树:r = p;//置空的目的:保证从左侧返回到根结点或某个结点的左侧子树全部访问完,使其可以访问对应的右子树,所以这里将p置空,直接跳过上面if(p)的判断,直接去执行栈顶元素的右子树。p = NULL;}}}}

线索 二叉树 遍历
//中序遍历线索二叉树void InOrderTraverse(ThreadTree T){//临时指针p指向传递过来的二叉树的根结点:ThreadTree p = T;while(p){//1. 找最左孩子//如果左标志位为0,即p当前指向的结点,其左孩子存在的话,则一直循环,找到最左下角结点:while(p->Itag == 0){//再找其左孩子:p = p->lchild;}//2. 根据中序遍历的要求,访问结点//访问: E.g 这里的打印该结点的数据内容printf("%c", p->data);//3. 再访问它的右子树://p当前指向的结点没有右孩子(即 p->rtag == 1,表示存在后继) && 后继指针指向的结点存在(因为最后右侧的后继指针=NULL,为了结束外循环)while(p->rtag == 1 && p->rchild){//让p指向其对应的右结点:p = p->rchild;//访问该右结点:printf("%c", p->data);}//当上面一个while循环的p->tag=0时且其右孩子时(E.g B结点),那么下面的一句让其指向其右孩子结点:(避免漏掉此情况);//当指向C结点时其右孩子指向为NULL,同时即可跳出当前所在的外循环:p->rchild;}}

