【数据结构和算法】【二叉树】二叉树遍历的代码实现
二叉树的顺序存储结构:
使用数组表示,将二叉树填充为完全二叉树并依次自上而下、自左至右进行编号[1-n],而后将编号为[1-n]的结点元素一一对应地存储在数组下标为[0-(n-1)]的数组元素中。
二叉树的链式存储结构:
1、二叉链表:结点中有两个链域(指针),分别指向左儿子、右儿子;
2、三叉链表:结点中有三个链域(指针),分别指向左儿子、右儿子、双亲;
3、线索链表:二叉链表的升级版本,将结点中的空链域利用起来,如:左空链域指向遍历的前一个结点,而右空链域指向遍历的后一个结点。
特殊的二叉树概念:
线索二叉树:使用线索链表表示的二叉树。也就是基于二叉链表表示的二叉树,将其结点中的空链域利用起来,使其左空链域指向遍历的前一个结点,右空链域指向遍历的后一个结点。
二叉树的遍历方式:先序遍历、中序遍历、后续遍历、层次遍历。
根据L、D、R(分别表示遍历左子树、访问根节点、遍历右子树)的组合,共有6种排列顺序。约定“先L后R”,则只有3中排列顺序,分别称之为:先序遍历DLR、中序遍历LDR、后序遍历LRD。
拿到一颗二叉树,快速写出各类遍历方式的结点访问顺序的方法参考《数据结构》P130“图6.10 三种遍历过程示意图”。
结点穿越原则:1、方向向下时,总是指向儿子结点的左侧;2、方向向上时,作为左儿子则指向双亲的左侧,作为右儿子则指向双亲的右侧;3、左儿子指向双亲后,再指向右儿子。
三种遍历的非递归实现(空指针不入栈)总体步骤:
步骤1:建立堆栈并初始化;
步骤2:根指针入栈;(中序遍历时,根指针无需入栈)
步骤3:遍历过程;(重点!!)
步骤4:销毁堆栈。
注:
1、入栈时要判定指针是否为空,空的话就不入栈,以确保栈中的指针都是有对应节点的;
2、出栈时可以立即访问该节点(出栈==遍历/访问),因为入栈保证了都是非空节点。
遍历方式
| 辅助变量 |
循环原则
| 每次循环做的事情(空指针不入栈) |
代码框架
|
先序遍历
|
p为出栈指针
|
栈不空时进行循环
|
出栈访问 -> 右子树入栈 -> 左子树入栈
| while (栈不空) pop visit; push right; push left; |
中序遍历 |
p为出栈指针和遍历指针,并初始为T
|
p不空或栈不空时进行循环
|
p不空则将p入栈,并将p指向其左子树;
p空则出栈访问,并将p指向栈顶结点的右子树;
|
while (栈不空 || p不空)
if (p) { push(p); p = p->left; }
else { pop visit; p = p->right; }
|
后续遍历 |
p为出栈指针;pre为已完成出栈/遍历的结点指针,并初始为NULL
|
栈不空时进行循环
|
查看栈顶指针(GetTop):如果左右子树都完成了遍历或者pre为其左儿子或者pre为其右儿子则出栈访问并刷新pre;否则右子树入栈 -> 左子树入栈
|
while (栈不空)
GetTop(p);
if () { pop visit; pre = p; }
else { push right; push left; }
|
先序遍历二叉树(非递归 - 根指针不入栈)
- void PreOrderTraverseNoRec(BiTree T)
- {
- SqStack S;
- BiTree p;
-
-
- if (!T) return;
-
-
- (void)InitStack(&S);
-
-
- (void)Push(&S, &T);
-
-
- while (!StackEmpty(&S))
- {
- (void)Pop(&S, &p);
- Visit(p->data);
- if (p->rchild) (void)Push(&S, &p->rchild);
- if (p->lchild) (void)Push(&S, &p->lchild);
- }
-
-
- (void)DestroyStack(&S);
-
- return;
- }
中序遍历二叉树(非递归 - 空指针不入栈)
- void InOrderTraverseNoRec2(BiTree T)
- {
- SqStack S;
- BiTree p;
-
-
- if (!T) return;
-
-
- (void)InitStack(&S);
-
-
-
-
-
- p = T;
- while (p || !StackEmpty(&S))
- {
- if (p)
- {
- (void)Push(&S, &p);
- p = p->lchild;
- }
- else
- {
- (void)Pop(&S, &p);
- Visit(p->data);
- p = p->rchild;
- }
- }
-
-
- (void)DestroyStack(&S);
-
- return;
- }
后序遍历二叉树(非递归 - 空指针不入栈)
- void PostOrderTraverseNoRec(BiTree T)
- {
- SqStack S;
- BiTree p;
- BiTree pre = NULL;
-
-
- if (!T) return;
-
-
- (void)InitStack(&S);
-
-
- (void)Push(&S, &T);
-
-
- while (!StackEmpty(&S))
- {
- (void)GetTop(&S, &p);
- if ((!p->lchild && !p->rchild)
- || (pre && ((p->lchild == pre) || (p->rchild == pre))))
- {
- (void)Pop(&S, &p);
- Visit(p->data);
- pre = p;
- }
- else
- {
- if (p->rchild) (void)Push(&S, &p->rchild);
- if (p->lchild) (void)Push(&S, &p->lchild);
- }
- }
-
-
- (void)DestroyStack(&S);
-
- return;
- }
二叉树遍历的全部代码实现:
- <span style="font-family:SimSun;">
-
- #include <stdio.h>
- #include <stdlib.h>
- #include "sq_stack.h"
-
- #ifndef _OK_
- #define OK 0
- #endif
-
- #ifndef _ERROR_
- #define ERROR 1
- #endif
-
- #ifndef _TRUE_
- #define TRUE 1
- #endif
-
- #ifndef _FALSE_
- #define FALSE 0
- #endif
-
- #ifndef _BiTNode_
- #define _BiTNode_
- typedef char TElemType;
-
- typedef struct BiTNode
- {
- TElemType data;
- struct BiTNode *lchild;
- struct BiTNode *rchild;
- } BiTNode, *BiTree;
- #endif // _BiTNode_
-
-
-
-
-
-
-
- void CreateBiTree(BiTree *pT)
- {
- char c;
- scanf("%c", &c);
-
- if (' ' == c)
- {
- *pT = NULL;
- }
- else
- {
- *pT = (BiTNode *)malloc(sizeof(BiTNode));
- (*pT)->data = c;
- CreateBiTree(&(*pT)->lchild);
- CreateBiTree(&(*pT)->rchild);
- }
-
- return;
- }
-
-
- void Visit(char data)
- {
- printf("%c", data);
- return;
- }
-
-
- void PreOrderTraverse(BiTree T)
- {
- if (!T) return;
- Visit(T->data);
- PreOrderTraverse(T->lchild);
- PreOrderTraverse(T->rchild);
- return;
- }
-
-
- void PreOrderTraverseNoRec(BiTree T)
- {
- SqStack S;
- BiTree p;
-
-
- if (!T) return;
-
-
- (void)InitStack(&S);
-
-
- (void)Push(&S, &T);
-
-
- while (!StackEmpty(&S))
- {
- (void)Pop(&S, &p);
- Visit(p->data);
- if (p->rchild) (void)Push(&S, &p->rchild);
- if (p->lchild) (void)Push(&S, &p->lchild);
- }
-
-
- (void)DestroyStack(&S);
-
- return;
- }
-
-
- void InOrderTraverse(BiTree T)
- {
- if (!T) return;
- InOrderTraverse(T->lchild);
- Visit(T->data);
- InOrderTraverse(T->rchild);
- return;
- }
-
-
- void InOrderTraverseNoRec1(BiTree T)
- {
- SqStack S;
- BiTree p;
-
-
- if (!T) return;
-
-
- (void)InitStack(&S);
-
-
- (void)Push(&S, &T);
-
-
- while (!StackEmpty(&S))
- {
- while ((OK == GetTop(&S, &p)) && p)
- {
- (void)Push(&S, &p->lchild);
- }
-
- (void)Pop(&S, &p);
-
- if (!StackEmpty(&S))
- {
- (void)Pop(&S, &p); Visit(p->data);
- (void)Push(&S, &p->rchild);
- }
- }
-
-
- (void)DestroyStack(&S);
-
- return;
- }
-
-
- void InOrderTraverseNoRec2(BiTree T)
- {
- SqStack S;
- BiTree p;
-
-
- if (!T) return;
-
-
- (void)InitStack(&S);
-
-
-
-
-
- p = T;
- while (p || !StackEmpty(&S))
- {
- if (p)
- {
- (void)Push(&S, &p);
- p = p->lchild;
- }
- else
- {
- (void)Pop(&S, &p);
- Visit(p->data);
- p = p->rchild;
- }
- }
-
-
- (void)DestroyStack(&S);
-
- return;
- }
-
-
- void PostOrderTraverse(BiTree T)
- {
- if (!T) return;
- PostOrderTraverse(T->lchild);
- PostOrderTraverse(T->rchild);
- Visit(T->data);
- return;
- }
-
-
- void PostOrderTraverseNoRec(BiTree T)
- {
- SqStack S;
- BiTree p;
- BiTree pre = NULL;
-
-
- if (!T) return;
-
-
- (void)InitStack(&S);
-
-
- (void)Push(&S, &T);
-
-
- while (!StackEmpty(&S))
- {
- (void)GetTop(&S, &p);
- if ((!p->lchild && !p->rchild)
- || (pre && ((p->lchild == pre) || (p->rchild == pre))))
- {
- (void)Pop(&S, &p);
- Visit(p->data);
- pre = p;
- }
- else
- {
- if (p->rchild) (void)Push(&S, &p->rchild);
- if (p->lchild) (void)Push(&S, &p->lchild);
- }
- }
-
-
- (void)DestroyStack(&S);
-
- return;
- }
-
- int main()
- {
- BiTree T = NULL;
- int input;
-
- while (1)
- {
- printf("----------------------------------\n");
- printf("二叉树基本操作\n");
- printf("----------------------------------\n");
- printf("0.建立二叉树的存储结构\n");
- printf("1.求解二叉树的前序遍历\n");
- printf("2.求解二叉树的中序遍历\n");
- printf("3.求解二叉树的后序遍历\n");
- printf("9.退出系统\n");
- printf("----------------------------------\n");
- printf("请选择:");
- scanf("%d", &input);
- getchar();
-
- switch (input)
- {
- case 0:
- printf("输入二叉树的先序序列结点值: --> ");
- CreateBiTree(&T);
- printf("二叉树的链式存储结构建立完成!\n");
- break;
-
-
- case 1:
- printf("该二叉树的前序遍历序列(递归)是: --> ");
- PreOrderTraverse(T);
- printf("\n");
-
- printf("该二叉树的前序遍历序列(非递归)是: --> ");
- PreOrderTraverseNoRec(T);
- printf("\n");
- break;
-
- case 2:
- printf("该二叉树的中序遍历序列(递归)是:--> ");
- InOrderTraverse(T);
- printf("\n");
-
- printf("该二叉树的中序遍历序列(非递归 空指针入栈)是:--> ");
- InOrderTraverseNoRec1(T);
- printf("\n");
-
- printf("该二叉树的中序遍历序列(非递归 空指针不入栈)是:--> ");
- InOrderTraverseNoRec2(T);
- printf("\n");
- break;
-
- case 3:
- printf("该二叉树的后序遍历序列(递归)是: --> ");
- PostOrderTraverse(T);
- printf("\n");
-
- printf("该二叉树的后序遍历序列(非递归)是: --> ");
- PostOrderTraverseNoRec(T);
- printf("\n");
- break;
-
- case 9:
- printf("系统已退出!\n");
- exit(0);
-
- default:
- printf("输入错误,退出!\n");
- exit(0);
- }
- }
-
- return 0;
- }
- </span>
参考文章:http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html