二叉树的递归遍历和非递归遍历

简介: 二叉树的递归遍历和非递归遍历

一.二叉树的递归遍历

定义二叉树


#其中TElemType可以是int或者是char,根据要求自定
typedef struct BiNode{
    TElemType data;
    struct BiNode, *lchild,*rchild;
}BiNode,*BiTree;
void visit(TElemType data) {
    printf("%d ", data); 
}

1.先序遍历二叉树

void PreOrderTraverse(BiTree T)
{
    if(T==NULL)
        return ok;//空二叉树
    else
    {
        visit(T);//访问根节点
        PreOrderTraverse(T->lchild);//递归遍历左子树
        PreOrderTraverse(T->rchild);//递归遍历右子树
    }
}

2.中序遍历二叉树

void InOrderTraverse(BiTree T)
{
    if(T==NULL)
        return ok;//空二叉树
    else
    {
        InOrderTraverse(T->lchild);//递归遍历左子树
        visit(T);//访问根节点
        InOrderTraverse(T->rchild);//递归遍历右子树
    }
}

3.后序遍历二叉树

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.先序遍历

(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 结构体内存
}

2.中序遍历

中序遍历和先序遍历思路类似,区别在于,先序遍历先访问根,在访问左,中序遍历先访问左,在访问根,最后都再访问右


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 结构体内存
}


3.后序遍

后续遍历必须访问完左右子树之后才可以访问父亲结点,所以访问完左子树时,现在得去访问右子树,通过栈找到父亲结点(这是第一次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);
}



目录
相关文章
|
8月前
|
存储 C++
非递归遍历二叉树
非递归遍历二叉树
39 0
|
1月前
|
存储
详解二叉树的各种非递归遍历
详解二叉树的各种非递归遍历
|
1月前
递归遍历二叉树
递归遍历二叉树的思路
96 0
|
10月前
|
存储
线索化二叉树
线索化二叉树
40 0
二叉树的前序、中序和后序遍历
二叉树的前序、中序和后序遍历
|
JavaScript 前端开发 Java
二叉树的先序、中序、后序遍历
二叉树的先序、中序、后序遍历
111 0
二叉树的先序、中序、后序遍历
先序、中序、后序遍历确定唯一树
快速学习先序、中序、后序遍历确定唯一树
先序、中序、后序遍历确定唯一树
15分钟精通二叉树,二叉树的先序,中序,后序,层次遍历顺序
🍀🍀🍀理解,掌握二叉树先序,中序,后序,层次四种遍历顺序
139 0
15分钟精通二叉树,二叉树的先序,中序,后序,层次遍历顺序
二叉树中序非递归遍历
二叉树中序非递归遍历 二叉树中序非递归遍历
106 0