目录
定义二叉树
- #其中TElemType可以是int或者是char,根据要求自定
- typedef struct BiNode{
- TElemType data;
- struct BiNode, *lchild,*rchild;
-
- }BiNode,*BiTree;
-
- void visit(TElemType data) {
- printf("%d ", data);
- }
- void PreOrderTraverse(BiTree T)
- {
- if(T==NULL)
- return ok;//空二叉树
- else
- {
- visit(T);//访问根节点
- PreOrderTraverse(T->lchild);//递归遍历左子树
- PreOrderTraverse(T->rchild);//递归遍历右子树
- }
- }
- void InOrderTraverse(BiTree T)
- {
- if(T==NULL)
- return ok;//空二叉树
- else
- {
- InOrderTraverse(T->lchild);//递归遍历左子树
- visit(T);//访问根节点
- InOrderTraverse(T->rchild);//递归遍历右子树
- }
- }
- void PostOrderTraverse(BiTree T)
- {
- if(T==NULL)
- return ok;//空二叉树
- else
- {
- PostOrderTraverse(T->lchild);//递归遍历左子树
- PostOrderTraverse(T->rchild);//递归遍历右子树
- visit(T);//访问根节点
- }
- }
遍历的规则,以先序遍历为例:

如果去掉输出语句,从递归角度,三种算法是完全相同的,三种算法访问路径是相同的,只是访问时机不同

第一次经过时访问=先序遍历
第二次经过时访问=中序遍历
第三次经过时访问=后序遍历
- typedef struct BiTNode {
- char data;
- struct BiTNode *lchild, *rchild;
- } BiTNode, *BiTree;
-
- typedef struct {
- BiTree data[MAX_SIZE];
- int top;
- } Stack;
-
- void InitStack(Stack** S) {
- *S = (Stack*)malloc(sizeof(Stack));
- (*S)->top = -1;
- }
-
- int StackEmpty(Stack* S) {
- return (S->top == -1);
- }
-
- int StackFull(Stack* S) {
- return (S->top == MAX_SIZE - 1);
- }
-
- void push(Stack* S, BiTree elem) {
- if (StackFull(S)) {
- printf("Stack is full. Cannot push element.\n");
- return;
- }
- S->top++;
- S->data[S->top] = elem;
- }
-
- void pop(Stack* S, BiTree* elem) {
- if (StackEmpty(S)) {
- printf("Stack is empty. Cannot pop element.\n");
- return;
- }
- *elem = S->data[S->top];
- S->top--;
- }
-
- int GetTop(Stack* S, BiTree* elem) {
- if (StackEmpty(S)) {
- printf("Stack is empty. Cannot get top element.\n");
- return 0;
- }
- *elem = S->data[S->top];
- return 1;
- }
(1)从根结点开始先压左路结点,并访问结点,直到把根结点和左路结点全部压入栈。
(2)若左子树和为空,说明左路和根结点已经全部压栈并且已经访问过了,开始取栈顶元素来访问上一层父节点的右子树。把右子树看成子问题继续进行(1)
(3)依次进行上述(1)和(2)压栈访问和出栈操作,直到栈为空或者右子树为空这说明遍历完毕

- void PreOrderTraverse(BiTree T)
- {
- Stack* S;
- BiTree p, q;
- InitStack(&S);
- p = T;
- while (p || !StackEmpty(S))
- {
- if (p)
- {
- printf("%c", p->data);
- push(S, p); // 将节点 p 入栈
- p = p->lchild;
- }
- else
- {
- pop(S, &q);
- p = q->rchild;
- }
- }
-
- free(S); // 释放 Stack 结构体内存
- }
中序遍历和先序遍历思路类似,区别在于,先序遍历先访问根,在访问左,中序遍历先访问左,在访问根,最后都再访问右
- void InOrderTraverse(BiTree T)
- {
- Stack* S;
- BiTree p, q;
- InitStack(&S);
- p = T;
- while (p || !StackEmpty(S))
- {
- if (p)
- {
- push(S, p);
- p = p->lchild;
- }
- else
- {
- pop(S, &q);
- printf("%c", q->data);
- p = q->rchild;
- }
- }
-
- free(S); // 释放 Stack 结构体内存
- }
后续遍历必须访问完左右子树之后才可以访问父亲结点,所以访问完左子树时,现在得去访问右子树,通过栈找到父亲结点(这是第一次top父亲结点),然后找到父亲结点的右子树进行访问,当把右子树访问完成后,再通过栈找到父亲结点进行访问(这是第二次top父亲结点A)。那么怎么才知道这时是第一次top和第二次top呢?如果不做处理的话这里就会一直认为是第一次top父亲节点,不出栈,就会造成死循环,所以怎样解决呢?
这里创建一个prev结点,用来记录上一次出栈的结点,若上一次出栈的结点为右子树,这说明可以访问根结点了,说明是已经第二次top父亲结点
- void PostOrderTraverse(BiTree T)
- {
- Stack* S;
- BiTree p = T;
- InitStack(&S);
- BiTree prev = NULL;
-
- while (p || !StackEmpty(S))
- {
- while (p)
- {
- push(S, p);
- p = p->lchild;
- }
-
- BiTree q;
- if (GetTop(S, &q) && (q->rchild == NULL || q->rchild == prev))
- {
- printf("%c ", q->data);
- prev = q;//更新q结点
- pop(S, &p);
- p = NULL;
- }
- else if (q->rchild != NULL)
- {
- p = q->rchild;
- }
- }
-
- free(S);
- }