二叉树的遍历

目录

1.先序

        1.1递归形式

        1.2非递归形式

2.中序

        2.1递归形式

        2.2非递归形式

3.后序

        3.1递归形式

        3.2非递归形式

4.层序

        4.1层序遍历的核心问题 

        4.1队列实现 

 5.二叉树及其遍历C语言实现

6.二叉树遍历的总结 


提纲挈领的说,先序中序后序的遍历区别在于遍历根节点的时机。 

1.先序

        1.1递归形式

 遍历过程为:

① 访问结点; ② 先序遍历其左子树; ③ 先序遍历其右子树

void PreOrderTraversal( BinTree BT )
{
    if( BT ) {
     printf(“%d”, BT->Data);
     PreOrderTraversal( BT->Left );
     PreOrderTraversal( BT->Right );
    }
}

        1.2非递归形式

使用一个栈,按照根节点、右子树、左子树的顺序入栈。 

void PreOrderTraversal(BinTree BT) {
    if (BT == NULL) return;

    Stack S = CreatStack(100); /* 示例最大大小,根据需要调整 */
    Push(&S, BT);

    while (!IsEmpty(S)) {
        BinTree T = Pop(&S);
        printf("%5d ", T->Data);
        
        if (T->Right) Push(&S, T->Right);  // 右子节点先入栈
        if (T->Left) Push(&S, T->Left);    // 左子节点后入栈
    }
}

2.中序

        2.1递归形式

遍历过程为: ① 中序遍历其左子树; ② 访问根结点; ③ 中序遍历其右子树。 

void InOrderTraversal( BinTree BT )
{
 if( BT ) {
     InOrderTraversal( BT->Left );
     printf(“%d”, BT->Data);
     InOrderTraversal( BT->Right );
 }
}

        2.2非递归形式

中序遍历的顺序是:左子树 -> 根节点 -> 右子树。使用栈的方式进行遍历时,通常先遍历左子树直到没有左子节点,然后访问根节点,最后遍历右子树。 

中序遍历非递归遍历算法【使用堆栈

 遇到一个结点,就把它压栈,并去遍历它的左子树;

 当左子树遍历结束后,从栈顶弹出这个结点并访问它;

 然后按其右指针再去中序遍历该结点的右子树。 

void InOrderTraversal( BinTree BT )
{ 
    BinTree T=BT;
    Stack S = CreatStack( MaxSize ); /*创建并初始化堆栈S*/
    while( T || !IsEmpty(S) ){
         while(T){ /*一直向左并将沿途结点压入堆栈*/
             Push(S,T);
             T = T->Left;
         }
         if(!IsEmpty(S)){
             T = Pop(S); /*结点弹出堆栈*/
             printf(“%5d”, T->Data); /*(访问)打印结点*/
             T = T->Right; /*转向右子树*/
         }
    }
}

3.后序

        3.1递归形式

 遍历过程为: ① 后序遍历其左子树; ② 后序遍历其右子树; ③ 访问根结点

void PostOrderTraversal( BinTree BT )
{
 if( BT ) {
     PostOrderTraversal( BT->Left );
     PostOrderTraversal( BT->Right);
     printf(“%d”, BT->Data);
 }
}

        3.2非递归形式

        使用两个栈,第一个栈用于存储节点,第二个栈用于存储遍历结果,最后反向打印第二个栈的内容。

void PostOrderTraversal(BinTree BT) {
    if (BT == NULL) return;

    Stack S1 = CreatStack(100);  // 用于保存节点
    Stack S2 = CreatStack(100);  // 用于保存遍历结果

    Push(&S1, BT);

    while (!IsEmpty(S1)) {
        BinTree T = Pop(&S1);
        Push(&S2, T);  // 将节点压入S2

        if (T->Left) Push(&S1, T->Left);
        if (T->Right) Push(&S1, T->Right);
    }

    // 打印结果栈中的节点数据,顺序为后序遍历结果
    while (!IsEmpty(S2)) {
        BinTree T = Pop(&S2);
        printf("%5d ", T->Data);
    }
}

4.层序

        4.1层序遍历的核心问题 

我们需要从上到下,从左至右依次输出每个结点,这相当于“二维结构的线性化”

 从结点访问其左、右儿子结点

 访问左儿子后,右儿子结点怎么办?

 需要一个存储结构保存暂时不访问的结点

 存储结构:堆栈、队列 

        4.1队列实现 

         遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队、访问该结点、其左右儿子入队。

层序基本过程:

 先根结点入队,然后:

 从队列中取出一个元素;

 访问该元素所指结点;

 若该元素所指结点的左、右孩子结点非空, 则将其左、右孩子的指针顺序入队。 

void LevelOrderTraversal ( BinTree BT )
{ 
    Queue Q; 
    BinTree T;
    if ( !BT ) return; /* 若是空树则直接返回 */
    Q = CreatQueue( MaxSize ); /*创建并初始化队列Q*/
    AddQ( Q, BT );
    while ( !IsEmptyQ( Q ) ) {
         T = DeleteQ( Q );
         printf(“%d\n”, T->Data); /*访问取出队列的结点*/
         if ( T->Left ) AddQ( Q, T->Left );
         if ( T->Right ) AddQ( Q, T->Right );
    }
}

 5.二叉树及其遍历C语言实现

二叉树示例

代码示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义学生信息结构体
typedef struct student {
    char num[50];   // 学号
    char name[50];  // 姓名
    char sex[10];   // 性别
    int age;        // 年龄
} ElementType;

typedef struct TreeNode *BinTree;
typedef BinTree Position;

struct TreeNode {
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

// 栈结构体及相关操作函数的声明
typedef struct StackNode *Stack;
Stack CreateStack(int MaxSize);
void Push(Stack S, BinTree BT);
BinTree Pop(Stack S);
int IsEmpty(Stack S);

// 队列结构体及相关操作函数的声明
typedef struct QueueNode *Queue;
Queue CreateQueue(int MaxSize);
void AddQ(Queue Q, BinTree BT);
BinTree DeleteQ(Queue Q);
int IsEmptyQ(Queue Q);

// 递归先序遍历
void PreOrderTraversalRecursive(BinTree BT) {
    if (BT) {
        printf("%s ", BT->Data.num);
        PreOrderTraversalRecursive(BT->Left);
        PreOrderTraversalRecursive(BT->Right);
    }
}

// 非递归先序遍历
void PreOrderTraversal(BinTree BT) {
    if (BT == NULL) return;

    Stack S = CreateStack(100); /* 示例最大大小,根据需要调整 */
    Push(S, BT);

    while (!IsEmpty(S)) {
        BinTree T = Pop(S);
        printf("%s ", T->Data.num);

        if (T->Right) Push(S, T->Right);  // 右子节点先入栈
        if (T->Left) Push(S, T->Left);    // 左子节点后入栈
    }
}

// 递归中序遍历
void InOrderTraversalRecursive(BinTree BT) {
    if (BT) {
        InOrderTraversalRecursive(BT->Left);
        printf("%s ", BT->Data.num);
        InOrderTraversalRecursive(BT->Right);
    }
}

// 非递归中序遍历
void InOrderTraversal(BinTree BT) {
    BinTree T = BT;
    Stack S = CreateStack(100); /* 示例最大大小,根据需要调整 */
    while (T || !IsEmpty(S)) {
        while (T) { /* 一直向左并将沿途结点压入堆栈 */
            Push(S, T);
            T = T->Left;
        }
        if (!IsEmpty(S)) {
            T = Pop(S); /* 结点弹出堆栈 */
            printf("%s ", T->Data.num); /* (访问)打印结点 */
            T = T->Right; /* 转向右子树 */
        }
    }
}

// 递归后序遍历
void PostOrderTraversalRecursive(BinTree BT) {
    if (BT) {
        PostOrderTraversalRecursive(BT->Left);
        PostOrderTraversalRecursive(BT->Right);
        printf("%s ", BT->Data.num);
    }
}

// 非递归后序遍历
void PostOrderTraversal(BinTree BT) {
    if (BT == NULL) return;

    Stack S1 = CreateStack(100);  // 用于保存节点
    Stack S2 = CreateStack(100);  // 用于保存遍历结果

    Push(S1, BT);

    while (!IsEmpty(S1)) {
        BinTree T = Pop(S1);
        Push(S2, T);  // 将节点压入S2

        if (T->Left) Push(S1, T->Left);
        if (T->Right) Push(S1, T->Right);
    }

    // 打印结果栈中的节点数据,顺序为后序遍历结果
    while (!IsEmpty(S2)) {
        BinTree T = Pop(S2);
        printf("%s ", T->Data.num);
    }
}

// 层序遍历
void LevelOrderTraversal(BinTree BT) {
    if (BT == NULL) return;

    Queue Q = CreateQueue(100); /* 创建并初始化队列 */
    AddQ(Q, BT);
    while (!IsEmptyQ(Q)) {
        BinTree T = DeleteQ(Q);
        printf("%s ", T->Data.num); /* 访问取出队列的结点 */
        if (T->Left) AddQ(Q, T->Left);
        if (T->Right) AddQ(Q, T->Right);
    }
}

// 栈和队列相关函数的占位符实现
struct StackNode {
    BinTree *Data;
    int Top;
    int MaxSize;
};

struct QueueNode {
    BinTree *Data;
    int Front, Rear;
    int MaxSize;
};

Stack CreateStack(int MaxSize) {
    Stack S = (Stack)malloc(sizeof(struct StackNode));
    S->Data = (BinTree *)malloc(MaxSize * sizeof(BinTree));
    S->Top = -1;
    S->MaxSize = MaxSize;
    return S;
}

void Push(Stack S, BinTree BT) {
    if (S->Top < S->MaxSize - 1) {
        S->Data[++S->Top] = BT;
    } else {
        printf("Stack Full\n");
    }
}

BinTree Pop(Stack S) {
    if (S->Top > -1) {
        return S->Data[S->Top--];
    } else {
        printf("Stack Empty\n");
        return NULL;
    }
}

int IsEmpty(Stack S) {
    return S->Top == -1;
}

Queue CreateQueue(int MaxSize) {
    Queue Q = (Queue)malloc(sizeof(struct QueueNode));
    Q->Data = (BinTree *)malloc(MaxSize * sizeof(BinTree));
    Q->Front = Q->Rear = 0;
    Q->MaxSize = MaxSize;
    return Q;
}

void AddQ(Queue Q, BinTree BT) {
    if ((Q->Rear + 1) % Q->MaxSize != Q->Front) {
        Q->Data[Q->Rear] = BT;
        Q->Rear = (Q->Rear + 1) % Q->MaxSize;
    } else {
        printf("Queue Full\n");
    }
}

BinTree DeleteQ(Queue Q) {
    if (Q->Front != Q->Rear) {
        BinTree BT = Q->Data[Q->Front];
        Q->Front = (Q->Front + 1) % Q->MaxSize;
        return BT;
    } else {
        printf("Queue Empty\n");
        return NULL;
    }
}

int IsEmptyQ(Queue Q) {
    return Q->Front == Q->Rear;
}

// 创建一个简单的二叉树用于测试
BinTree CreateSampleTree() {
    BinTree node1 = (BinTree)malloc(sizeof(struct TreeNode));
    BinTree node2 = (BinTree)malloc(sizeof(struct TreeNode));
    BinTree node3 = (BinTree)malloc(sizeof(struct TreeNode));
    BinTree node4 = (BinTree)malloc(sizeof(struct TreeNode));
    BinTree node5 = (BinTree)malloc(sizeof(struct TreeNode));

    strcpy(node1->Data.num, "1");
    strcpy(node2->Data.num, "2");
    strcpy(node3->Data.num, "3");
    strcpy(node4->Data.num, "4");
    strcpy(node5->Data.num, "5");

    node1->Left = node2;
    node1->Right = node3;
    node2->Left = node4;
    node2->Right = node5;
    node3->Left = node3->Right = NULL;
    node4->Left = node4->Right = NULL;
    node5->Left = node5->Right = NULL;

    return node1;
}

int main() {
    // 创建一个样例二叉树
    BinTree root = CreateSampleTree();

    // 测试递归先序遍历
    printf("递归先序遍历: ");
    PreOrderTraversalRecursive(root);
    printf("\n");

    // 测试非递归先序遍历
    printf("非递归先序遍历: ");
    PreOrderTraversal(root);
    printf("\n");

    // 测试递归中序遍历
    printf("递归中序遍历: ");
    InOrderTraversalRecursive(root);
    printf("\n");

    // 测试非递归中序遍历
    printf("非递归中序遍历: ");
    InOrderTraversal(root);
    printf("\n");

    // 测试递归后序遍历
    printf("递归后序遍历: ");
    PostOrderTraversalRecursive(root);
    printf("\n");

    // 测试非递归后序遍历
    printf("非递归后序遍历: ");
    PostOrderTraversal(root);
    printf("\n");

    // 测试层序遍历
    printf("层序遍历: ");
    LevelOrderTraversal(root);
    printf("\n");

    return 0;
}

程序运行结果: 

 

6.二叉树遍历的总结 

先序、中序和后序遍历过程:遍历过程中经过结点的路线一 样,只是访问各结点的时机不同

 图中在从入口到出口的曲线上用三种符号分别标 记出了先序中序后序访问各结点的时刻

 

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值