二叉树以及二叉排序树的基本操作代码

二叉树的遍历操作代码

文件申明

主要包括数据域和左右指针

#include<iostream>
#include<string.h>
#include<stack>
#include<queue>
using namespace std;
#define ElemType int

typedef struct BiTNode{
    ElemType data;                      //数据域   
    struct BiTNode  *lchild;
    struct BiTNode  *rchild;     //左右孩子指针
}BiTNode, *BiTree;

visit函数

void visit(BiTree T){
    printf("%d",T->data);

}

二叉树的递归代码实现

先序遍历
//先序遍历
void PreOrder(BiTree T){
    if(T!=NULL){                    //序是指根节点在什么时候被访问
        visit(T);                   //先访问根节点,然后再访问左右子树
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}
中序遍历
//中序遍历
void InOrder(BiTree T){
    if(T!=NULL){
        InOrder(T->lchild);       //先访问左子树,然后访问根节点,最后访问右子树
        visit(T);
        InOrder(T->rchild);
    }
}

后续遍历
//后序遍历
void PostOrder(BiTree T){
    if(T!=NULL){
        PostOrder(T->lchild);      //先访问左子树,然后访问右子树,最后访问根节点
        PostOrder(T->rchild);
        visit(T);
    }
}

二叉树遍历的非递归代码实现

先序遍历

第一种思路,采用深度优先遍历的方式

//前序非递归遍历
//不断访问左孩子,如果左孩子已经访问完,则说明已经到叶子节点
//然后取叶子节点的根节点,访问其右孩子,然后再循环判断其右孩子的子树是否有左孩子
//如果为空就不断出栈,然后输出
void PreOrder_2(BiTree T){              //深度优先遍历实现
    stack<BiTree> Stack;
    BiTree p = T;
    while(p || Stack.empty()){
        if(p){
            visit(p);                   //如果p节点非空,访问当前节点,并入栈
            Stack.push(p);
            p = p->lchild;              //一直访问,直到左孩子为空
        }
        else{
            p = Stack.top();            //如果为空,则出栈,然后直接转向根节点的右孩子,因为左孩子和根节点都已经访问完
            Stack.pop();
            p = p->rchild;
        }
    }
}

第二种方式,类似于层次遍历

void PreOrder_3(BiTree T){              //广度优先遍历实现
    stack<BiTree> stack;
    BiTree p = T;
    stack.push(p);
    while(p){                           //右孩子先入栈,然后左孩子后入栈
        p = stack.top();                //取栈顶元素
        visit(p);
        stack.pop();
        if(p ->rchild != NULL)
            stack.push(p->rchild);
        if(p ->lchild != NULL)
            stack.push(p->lchild);
    }
}
中序遍历
//中序非递归遍历
//一直访问左孩子直到根节点
//出栈,然后访问栈顶元素,如果有右孩子就继续访问右孩子的左子树,没有右孩子就继续出栈遍历
void InOrder_2(BiTree T){
    stack<BiTree> Stack;
    BiTree p = T;
    while(p || Stack.empty()){
        if(p){
            Stack.push(p);              //如果p节点非空,访问当前节点,并入栈
            p = p->lchild;              //一直访问,直到左孩子为空
        }
        else{
            p = Stack.top();            //这里先输出叶子节点,也就是左孩子节点
            Stack.pop();
            visit(p);
            p = p->rchild;          
        }
    }
}
后序遍历

第一种思路:采用辅助指针方式

//后序非递归遍历
//加入一个辅助指针判断是否是第一次访问
//整体思路如下:首先不断访问其左孩子节点,当访问到叶子节点时,需要判断栈顶元素右孩子节点是否被访问过,
//如果没有被访问过,则继续访问右子节点,如果访问过,则输出该根节点,然后并记录目前访问的节点
void PostOrder_2(BiTree T){
    stack<BiTree> Stack;
    BiTree p = T;
    BiTree r = NULL;
    while(p || Stack.empty()){
        if(p){
            Stack.push(p);              //如果p节点非空,访问当前节点,并入栈
            p = p->lchild;              //一直访问,直到左孩子为空
        }
        else{
            p = Stack.top();            //取出栈顶元素判断是否被访问过
            if(p->rchild && p->rchild != r){    //未被访问过,则对其右子树进行访问
                p = p->rchild;
            }
            else{                       //已经访问过,则进行输出
                Stack.pop();            //将根节点弹出
                visit(p);
                r = p;                  //下次遍历的时候如果是其右子树,那么刚好已经访问过了,直接进行输出
                p = NULL;              //节点访问完后,重置p指针
            }
        }
    }
}

和第一种一样,添加一个标志位,作用类似于第一个的指针

typedef struct BiTNode{
    ElemType data;                      //数据域   
    struct BiTNode  *lchild;
    struct BiTNode  *rchild;     //左右孩子指针
    int flag;
}BiTNode, *BiTree;

//和2思路一致,在树的结构体中增加一个标志位,用于判断其右子树是否被访问过
void PostOrder_3(BiTree T){
    stack<BiTree> Stack;
    BiTree p = T;
    BiTree r = NULL;
    while(p || Stack.empty()){
        if(p){
            Stack.push(p);              //如果p节点非空,访问当前节点,并入栈
            p = p->lchild;              //一直访问,直到左孩子为空
        }
        else{
            p = Stack.top();            //取出栈顶元素判断是否被访问过
            if(p->rchild && T->flag == 0){    //未被访问过,则对其右子树进行访问
                p = p->rchild;
                p->flag = 1;
            }
            else{                       //已经访问过,则进行输出
                Stack.pop();            //将根节点弹出
                visit(p);
            }
        }
    }
}

第三种实现方式,修改先序遍历,(左右根)—>(右左根)
然后用另外一个栈保存,遍历完之后再输出就得到(右左根)

//先对其进行先序遍历,不过需要修改一下访问次序,先访问其右子树后在访问左子树
//然后在访问的时候加入另外一个栈中,这样得到的序列为根右左,最后对其进行出栈,得到左右根
void PostOrder_4(BiTree T){              
    stack<BiTree> stack1;
    stack<BiTree> stack2;
    BiTree p = T;
    stack1.push(p);
    while(p){                           //右孩子先入栈,然后左孩子后入栈
        p = stack1.top();                //取栈顶元素
        visit(p);
        stack2.push(p);                 //将遍历得到的序列加入第二个栈中
        stack1.pop();
        if(p ->rchild != NULL)
            stack1.push(p->lchild);
        if(p ->lchild != NULL)
            stack1.push(p->rchild);
    }
    while(stack2.empty()){              //再出栈
        visit(stack2.top());
        stack2.pop();
    }
}

层次遍历

需要采用辅助队列方式实现

//层次遍历
//需要一个辅助队列实现,首先访问根节点,入队
//出队,访问其左右子树,并将其入队,再次访问队头
void LeverOrder(BiTree T){
    queue<BiTree> Treeqe;           //树队列
    BiTree p;
    Treeqe.push(T);                 //根节点入队
    while(T){
        p = Treeqe.front();
        visit(p);                   //访问出队节点
        Treeqe.pop();
        if(p->lchild){              //左子树不为空,访问左子树
            Treeqe.push(p->lchild);
        }
        if(p->rchild){              //右子树不为空,访问右子树
            Treeqe.push(p->rchild);
        }
    }
}

中序二叉排序树基本操作

文件申明

#include<iostream>
using namespace std;
#define ElemType int



//线索二叉树,利用叶子结点的两个空指针找到前驱节点和后继节点

/* 增加两个标志域
ltag = 0  lchild指向结点的左孩子
ltag = 1  lchild指向结点的前驱节点

rtag = 0  rchild指向结点的右孩子
rtag = 1  rchild指向结点的后驱节点
*/

typedef struct ThreadNode{
    ElemType data;
    struct ThreadNode *lchild,*rchild;
    int ltag,rtag;
}ThreadNode,*ThreadTree;

中序实现二叉排序树的线索化

//中序遍历实现二叉树线索化
//pre为p的前驱节点
//在中序遍历的过程中,如果p的左指针为空,则指向pre
//如果pre的右子树为空,则指向p
void InThread(ThreadTree &p, ThreadTree &pre){
    if(p!=NULL){
        InThread(p->lchild,pre);  //递归,线索化左子树
        if(p->lchild == NULL){  //左子树为空,建立线索前驱
            p->lchild = pre;
            p->ltag = 1;
        }
        if(pre!=NULL  && pre->rchild == NULL){      //右子树为空,建立后继线索
            pre->rchild = p;
            pre->rtag = 1;
        }
        pre = p;
        InThread(p->rchild,pre);   //递归,线索化右子树
    }
}

void CreateInThread(ThreadTree T){
    ThreadTree pre = NULL;
    if(T != NULL){
        InThread(T,pre);
        pre->rchild = NULL;
        pre->rtag = 1;
    }
}

求中序线索二叉树下的第一个节点

//求中序线索二叉树下的第一个节点
ThreadNode *FirstNode(ThreadNode *p){       
    if(p->rtag == 0) p = p->lchild;     //最左下节点
    return p;
}

求中序线索二叉树结点p在中序序列下的后继

//求中序线索二叉树结点p在中序序列下的后继
ThreadNode *NextNode(ThreadNode *p){
    //如果右子树不为空,则下一个节点就是右子树的最左下节点
    if(p->rtag == 0) return FirstNode(p->rchild);
    //如果为空,直接返回线索后继
    else{
        return p->rchild;
    }
}

求中序线索二叉树最后一个节点

//求中序线索二叉树最后一个节点
ThreadNode *LastNode(ThreadNode *p){
    //最右下节点,为最后一个节点
    if(p->rtag == 0){           //最右下节点
        p = p->rchild;
    }
    return p;
}

求中序线索二叉树的结点p的前驱

//求中序线索二叉树的结点p的前驱
ThreadNode *FrontNode(ThreadNode *p){
    //如果左子树不为空,则下一个节点就是左子树的最右下节点
    if(p->lchild == 0) return LastNode(p->lchild);
    //如果为空,直接返回线索前驱
    else{
        return p->lchild;
    }
}

不含头结点的中序线索二叉树的中序遍历

//不含头结点的中序线索二叉树的中序遍历
void InOrder(ThreadNode *T){
    for(ThreadNode *p=FirstNode(T); p!=NULL; p = NextNode(p))
    printf("%d\n",p->data);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值