二叉树的部分操作

本文介绍了一种二叉树的实现方法,并详细展示了二叉树的创建及多种遍历方式,包括前序、中序、后序、非递归中序(栈实现)、层序(队列实现)和中序线索化遍历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下代码包括二叉树的创建、前中后序遍历(递归)、非递归中序遍历(栈实现)、层序遍历(队列实现)和中序线索化遍历。

  1. main
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include"Tree.h"
#include"Queue.h"
#include"Stack.h"
#include"Tree.h"
#include"Marco.h"

using namespace std;
BiThrTree pre;//全局变量,表示刚刚访问过的结点


int main()
{
    BiThrTree  T = NULL;

    printf("二叉树测试程序开始:\n");

    printf("1.创建非空二叉树:\n");
    CreateBiThrTree(T);

    printf("\n2.前序遍历二叉树:\n");
    PreOrderTraverse(T);

    printf("\n3.中序遍历二叉树:\n");
    InOrderTraverse(T);

    printf("\n4.后序遍历二叉树:\n");
    PostOrderTraverse(T);

    printf("\n5.非递归中序遍历二叉树(用栈实现):\n");
    NoRecursionInTraverse(T);

    printf("\n6.层序遍历二叉树(用队列实现):\n");
    LevelOrderTraverse(T);


    printf("\n7.中序线索化遍历二叉树:\n");
    BiThrTree Thrt;
    InOrderThreading( Thrt,T );
    InOrderAfterThreading(Thrt);

    cout << "\n二叉树测试程序结束!" << endl;
    return OK;
}

2.Tree.c

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include"Tree.h"
#include"Stack.h"
#include"Queue.h"
#include"Marco.h"
using namespace std;

extern BiThrTree pre;


/********************对二叉树的操作********************/


//1.创建二叉树
int CreateBiThrTree(BiThrTree &T)
{
    char data;
    scanf("%c", &data);
    if (' ' == data)
    {
        T = NULL;                                       //如果字符为空,则根节点为空
    }
    else
    {
        if (!(T = (BiThrTree)malloc(sizeof(BiThrNode))))//否则建立根节点
        {
            printf("出错:创建结点时分配空间错误!");
            exit(OVERFLOW);
        }
        T->data = data; //根节点数据域
        T->LTag = Link;
        T->RTag = Link;
        CreateBiThrTree(T->lchild);                 //构造左子树
        CreateBiThrTree(T->rchild);                 //构造右子树
    }
    return OK;
}

//2.前序遍历
void PreOrderTraverse(BiThrTree T)
{
    if (T)
    {
        printf("%c", T->data);
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
}


//3.中序遍历
void InOrderTraverse(BiThrTree T)
{
    if (T)
    {
        InOrderTraverse(T->lchild);
        printf("%c", T->data);
        InOrderTraverse(T->rchild);
    }
}

//4.后序遍历
void PostOrderTraverse(BiThrTree T)
{
    if (T)
    {
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        printf("%c", T->data);
    }
}

//5.非递归中序遍历
void NoRecursionInTraverse(BiThrTree T)
{
    BiThrTree p;
    Stack s;

    if (!(s.base = (BiThrTree*)malloc(sizeof(BiThrNode))))  //初始化栈
    {
        printf("出错:栈初始化失败时分配存储空间失败!\n");
        exit(1);
    }
    s.top = s.base;
    s.stackSize = STACK_INIT_SIZE;


    p = T;
    while(p || (s.top - s.base))
    {
        while (p)                           //遍历左子树,直到最左下角的节点
        {
            Push(s, p);
            p = p->lchild;
        }

        if((s.top-s.base))                              //左子树为空,根结点退栈,再遍历右子树
        {
            Pop(s, p);
            printf("%c", p->data);
            p = p->rchild;
        }
    }
}


//6.层序遍历
void LevelOrderTraverse(BiThrTree T)
{
    Queue Q;
    BiThrTree p=T;                                     //p在过程中不断被赋予新的结点地址

    Q.front = Q.rear = (QPtr)malloc(sizeof(QNode));    //初始化链队列
    if (!Q.front)
    {
        cout << "\n初始化分配存储空间失败!\n" << endl;
        exit(1);
    }
    Q.front->next = NULL;

    if (p)
        EnQueue(Q, p);
    while (Q.front != Q.rear)
    {
        DelQueue(Q, p);                                 //将被删除的结点赋予p,从而实现结点的更新
        cout << p->data;
        if (p->lchild != NULL)
        {
            EnQueue(Q, p->lchild);
        }
        if (p->rchild != NULL)
        {
            EnQueue(Q, p->rchild);
        }
    }//while
}
//7.中序线索化遍历
int InOrderThreading(BiThrTree &Thrt,BiThrTree T)
{
    if (!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
    {
        printf("出错:分配空间错误!");
        exit(-2);
    }

    Thrt->LTag = Link;                          //建立头节点
    Thrt->RTag = Thread;
    Thrt->rchild = Thrt;                            //右指针回指指向头节点

    if (!T)                                     //二叉树空,头节点的lchild指向根节点
    {
        Thrt->lchild = Thrt;
    }
    else
    {
        Thrt->lchild = T;                       //T不为空,头节点的lchild连接根结点
        pre = Thrt;                             //全局变量pre初始化,始终指向刚刚访问过的结点
        InThreading(T);                         //中序遍历进行中序线索化,传入的是根结点
        pre->rchild = Thrt;
        pre->RTag = Thread;
        Thrt->rchild = pre;                     //最后一个结点进行线索化   
    }
    return OK;
}

void InThreading(BiThrTree p)
{
    if (p)
    {
        InThreading(p->lchild);                 //递归,左子树线索化,直至最左下角的结点,其左子树为空,不在继续递归

        //中间部分为对 当前结点 的线索化
        if (!p->lchild)                         //当前结点 没有左子树,前驱线索
        {
            p->LTag = Thread;
            p->lchild = pre;                        //p->lchild指向直接前驱
        }
        if (!pre->rchild)                       //刚访问过的结点 没有右子树,后继线索
        {
            pre->RTag = Thread;
            pre->rchild = p;                        //
        }
        pre = p;                                //保持pre指向刚刚访问过的结点
        InThreading(p->rchild);                 //递归,右子树线索化
    }
}

//利用已经线索化的二叉树进行中序遍历输出, 非递归
void InOrderAfterThreading(BiThrTree Thrt)          //传入的是pre,传入前进行的最后操作为:                                              
{                                               //pre->rchild = Thrt;pre->RTag = Thread;Thrt->rchild = pre;
    BiThrTree p;
    p = Thrt->lchild;

    while (p != Thrt)
    {
        while (p->LTag == Link)
        {
            p = p->lchild;
        }
        cout << p->data;
        while (p->RTag == Thread && p->rchild != Thrt)
        {
            p = p->rchild;
            cout << p->data;
        }
        p = p->rchild;
    }
}

3.Stack.c

#include<stdio.h>
#include<stdlib.h>
#include"Stack.h"
#include"Tree.h"
/***********************对栈的操作***********************/

//1.Push
void Push(Stack &s, BiThrTree e)
{
    // 栈满,追加空间
    if (s.top - s.base >= s.stackSize)
    {
        s.base = (BiThrTree *)realloc(s.base, (s.stackSize + STACKINCREMENT) * sizeof(BiThrNode));
        if (!s.base)
            exit(0);

        s.top = s.base + s.stackSize;
        s.stackSize = s.stackSize + STACKINCREMENT;
    }

    *(s.top) = e;      // 存放数据
    s.top++;
}

//2.Pop
void Pop(Stack &s, BiThrTree &e)
{
    if (s.top == s.base)
    {
        printf("\n出错:出栈时栈为空!\n");
        exit(-2);
    }

    e = *(--s.top);   // 将栈顶元素弹出并修改栈指针
}

4.Queue.c

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include"Queue.h"
#include"Marco.h"
#include"Tree.h"
using namespace std;
/*******************对队列的操作***************************/
//1.EnQueue
void EnQueue(Queue &Q, BiThrTree e)
{
    QPtr q;
    if (!(q = (QPtr)malloc(sizeof(QNode))))
    {
        printf("出错:队列分配存储空间失败!\n");
        exit(OVERFLOW);
    }

    q->data = e;
    q->next = NULL;
    Q.rear->next = q;
    Q.rear = q;
}

//2.DelQueue
void DelQueue(Queue &Q, BiThrTree &e)
{
    if (Q.front == Q.rear)
    {
        cout << "出错:执行删除操作的队列为空!" << endl;
        exit(1);
    }
    QPtr p = Q.front->next;
    e = p->data;
    Q.front->next = p->next;
    if (Q.rear == p)
    {
        Q.rear = Q.front;
    }
    free(p);
}

5.Tree.h

#ifndef TREE_H_
#define TREE_H_
#include<stdio.h>
#define STACK_INIT_SIZE 100
#define STACKINCREMENT  10

typedef enum PointerTag { Link, Thread };           //Link==0,表示指针,Thread==1,表示线索

typedef struct BiThrNode
{
    char data;
    struct BiThrNode *lchild;
    struct BiThrNode *rchild;
    PointerTag LTag;
    PointerTag RTag;
}BiThrNode, *BiThrTree;

/********************对二叉树的操作********************/
//1.创建
int CreateBiThrTree(BiThrTree &T);

//2.前序遍历
void PreOrderTraverse(BiThrTree T);

//3.中序遍历
void InOrderTraverse(BiThrTree T);

//4.后序遍历
void PostOrderTraverse(BiThrTree T);

//5.非递归中序遍历
void NoRecursionInTraverse(BiThrTree T);

//6.层序遍历
void LevelOrderTraverse(BiThrTree T);
//7.中序遍历并线索
int InOrderThreading(BiThrTree &Thrt,BiThrTree T);

void InThreading(BiThrTree p);

//利用已经线索化的二叉树进行中序遍历输出
void InOrderAfterThreading(BiThrTree Thrt);

#endif

6.Stack.h

#ifndef STACK_H_
#define STACK_H_
#include"Tree.h"
typedef struct
{
    BiThrTree *top;
    BiThrTree *base;
    int stackSize;
}Stack;                             //用于非递归遍历二叉树

/*******************需要的对栈的操作***********************/

//1.Push
void Push(Stack &s, BiThrTree e);

//2.Pop
void Pop(Stack &s, BiThrTree &e);

#endif

7.Queue.h

#ifndef QUEUE_H_
#define QUEUE_H_
#include"Tree.h"
typedef struct QNode                //用于层序遍历二叉树
{
    BiThrTree data;             //存储地址
    struct QNode *next;
}QNode, *QPtr;

typedef struct
{
    QPtr front;
    QPtr rear;
}Queue;

/******************对队列的操作****************************/
//1.EnQueue
void EnQueue(Queue &Q, BiThrTree e);

//2.DelQueue
void DelQueue(Queue &Q, BiThrTree &e);

#endif

8.Marco.h(此部分的代码作用暂时不大)

#ifndef MARCO_H_
#define MARCO_H_

#define OK 0
#define ERROR 1
//#define OVERFLOW -2

#endif

图片中结果的格式和上面的代码运行结果的格式不完全相同,但对结果并无影响
在编写二叉树的线索化的代码时,一直不清楚线索化的具体过程,尽管看上去很容易理解。希望在调试的过程中理解过程,但很难进行下去,因为并没有能够运行的代码,每当想到这里就果断放弃调试,感觉是对时间的浪费。终于,今天静下心来,搜到了一个二叉树动态线索化的网页,观看后勉强理解了,代码写出后,进行调试,进一步理解过程。当然,写代码时不断抄袭书中内容的习惯一直是硬伤,鉴于二叉树的重要性,打算完全靠自己重新写一次。望天道酬勤!

ps:在写这个程序期间,学习了部分C++的知识,但在上述代码中所夹杂的C++代码都是基本的输出,没有输入。(如有错误,望各位指出)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值