二叉树的遍历

摘要:本文讲解了如何使用C++实现了二叉树的创建,添加节点,删除节点,使用递归和非递归方法分别进行前中后遍历,进行层遍历

关键字 :二叉树遍历


二叉树的结构体

typedef struct node
{
    int key, visited = 0;
    struct node *lChild, *rChild;
}Node, *BST;

这里key是存储节点的值,visited用来辅助判断节点是否被访问,在递归后序遍历时用到。


二叉树的建立

// 建立BST  
void createBST(Node * &T, int a[], int n)
{
    T = NULL;
    int i;
    for(i = 0; i < n; i++)
    {
        BSTInsert(T, a[i]);
    }
}

T是根节点,a[]存储节点的值,n是节点的个数
其中BSTInsert(T, a[i])函数的实现如下:

// 在给定的BST中插入结点,其数据域为element, 使之称为新的BST  
bool BSTInsert(Node * &p, int element)
{
    if(NULL == p) // 空树  
    {
        p = new Node;
        //p = (BST *)malloc(sizeof(BST));
        p->key = element;
        p->lChild = p->rChild = NULL;
        return true;
    }

    if(element == p->key) // BST中不能有相等的值  
        return false;

    if(element < p->key)  // 递归  
        return BSTInsert(p->lChild, element);

    return BSTInsert(p->rChild, element); // 递归  
}

二叉树的递归遍历

前序遍历

// 先序遍历  
void preOrderTraverse(BST T)
{
    BST p = T;
    if(p)
    {
        cout << p->key << " ";
        preOrderTraverse(p->lChild);
        preOrderTraverse(p->rChild);
    }
}

中序遍历

// 中序遍历  
void midOrderTraverse(BST T)
{
    if(T)
    {
        midOrderTraverse(T->lChild);
        cout << T->key << " ";
        midOrderTraverse(T->rChild);
    }
}

后序遍历

// 后序遍历  
void backOrderTraverse(BST T)
{
    if(T)
    {
        backOrderTraverse(T->lChild);
        backOrderTraverse(T->rChild);
        cout << T->key << " ";
    }
}

删除节点

//删除二叉树中与key值相等的节点
bool DeleteBST(BST & T, int key)
{
    /* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素节点 */
    /* 并返回TRUE;否则返回FALSE */
    if(!T)
        return false;   /* 不存在关键字等于key的数据元素 */
    else
    {
        if(key == T->key)
            Delete(T);
        else if(key < T->key)
            return DeleteBST(T->lChild, key);
        else
            return DeleteBST(T->rChild, key);
    }
}

DeleteBST()的作用是寻找节点值和key值相等的节点,Delete(T)才是真正删除节点的函数。代码如下:

int Delete(BST & p)
{
    /* 从二叉排序树中删除节点p, 并重接它的左或右子树 */
    BST q, s;
    if(!p->lChild && !p->rChild) /* p为叶子节点 */
        p = 0;
    else if(!p->lChild) /* 左子树为空,重接右子树 */
    {
        q = p;
        p = p->rChild;
        free(q);
    }
    else if(!p->rChild) /* 右子树为空,重接左子树 */
    {
        q = p;
        p = p->lChild;
        free(q);
    }
    else                        /* 左右子树均不为空 */
    {
        q = p;
        s = p->lChild;
        while(s->rChild)     /* 转左,然后向右走到尽头*/
        {
            q = s;
            s = s->rChild;
        }
        p->key = s->key;
        if(q != p)               /* 判断是否执行上述while循环 */
            q->rChild = s->lChild;    /* 执行上述while循环,重接右子树 */
        else
            q->lChild = s->lChild;    /* 未执行上述while循环,重接左子树 */
        free(s);
    }
    return true;
}

删除节点要遵循以下规则:
(1)删除节点为叶节点,直接删除;否则,执行步骤(2)
(2)当删除节点的右子树为空时,直接把左子树的根节点作为删除节点的左孩子;否则,执行步骤(3);
(3)当删除节点的左子树为空时,直接把右子树的根节点作为删除节点的右孩子;否则,执行步骤(4);
(4)当左子树和右子树都不为空时,设删除节点为p节点,先寻找p节点的左孩子,设为s节点,若s存在右孩子,执行步骤a;否则,执行步骤b;

a.以s节点为起始点,一直寻找s的最右端孩子,设为s节点,s节点的父节点设为q节点。此时把s的左子树作为q节点的右子树,s节点直接替代p节点;

b.p节点的右子树作为s节点的右子树,并且用s节点替换p节点。

步骤图解如下:
1.树的原图
这里写图片描述

2.执行规则(1)
删除叶子节点7,则直接删除
这里写图片描述

3.执行规则(2)
删除值为5的节点,由于该节点右子树为空,只需把节点5的左子树作为父节点6的左子树,然后删除节点5。
这里写图片描述

4.执行规则(3)
删除值为11的节点,由于该节点左子树为空,只需把节点11的右子树作为父节点10的右子树,然后删除节点11。
这里写图片描述

5.执行规则(4)a条例
删除值为10的节点,由于节点10的第一个左孩子6存在右子树,故寻找节点6的最右端孩子节点,为9,把节点9的左子树作为父节点6的右子树,并且以节点9替换要删除节点10,然后删除节点10。
这里写图片描述

6.执行规则(4)b条例
删除值为13的节点,由于节点13的第一个左孩子12不存在右子树,故把13的右子树作为12的右子树,以节点12替代节点13,删除节点13。
这里写图片描述


二叉树的非递归遍历

前序遍历

void preSearch(BST T)
{
    stack<BST> s;
    BST p = T;
    while(p)
    {
        while(p)
        {
            cout << p->key << " ";
            s.push(p);
            p = p->lChild;
        }
        while(!s.empty() && !p)
        {
            p = s.top();
            s.pop();
            p = p->rChild;
        }
    }
}

中序遍历

void midSearch(BST T)
{
    BST p = T;
    stack<BST> s;
    while(p)
    {
        while(p)
        {
            s.push(p);
            p = p->lChild;
        }
        while(!s.empty() && !p)
        {
            p = s.top();
            cout << p->key << " ";
            s.pop();
            p = p->rChild;
        }
        //cout << p->key << " ";
    }
}

后序遍历

void backSearch(BST T)
{
    BST cur;                      
    BST pre = NULL;   
    s.push(T);
    while(!s.empty())
    {
        cur = s.top();
        if((cur->lChild == NULL&&cur->rChild == NULL) ||
            (pre != NULL && (pre == cur->lChild || pre == cur->rChild)))
        {
            cout << cur->key << " ";  //如果当前结点没有孩子结点或者孩子节点都已被访问过 
            s.pop();
            pre = cur;
        }
        else
        {
            if(cur->rChild != NULL)
                s.push(cur->rChild);
            if(cur->lChild != NULL)
                s.push(cur->lChild);
        }
    }
}

层序遍历

void levelOrderTraverse(BST T)
{
    BST p = T;
    if(p)
    {
        de.push_back(p);
    }
    while(!de.empty())
    {
        p = de.front();
        if(p->lChild)
        {
            de.push_back(p->lChild);
        }
        if(p->rChild)
        {
            de.push_back(p->rChild);
        }
        p = de.front();
        cout << p->key << " ";
        de.pop_front();
    }
}

源代码

#include <iostream>  
#include <deque>
#include <stack>
using namespace std;

// BST的结点  
typedef struct node
{
    int key, visited = 0;
    struct node *lChild, *rChild;
}Node, *BST;

deque<BST> de;
stack<BST> s;

// 在给定的BST中插入结点,其数据域为element, 使之称为新的BST  
bool BSTInsert(Node * &p, int element)
{
    if(NULL == p) // 空树  
    {
        p = new Node;
        //p = (BST *)malloc(sizeof(BST));
        p->key = element;
        p->lChild = p->rChild = NULL;
        return true;
    }

    if(element == p->key) // BST中不能有相等的值  
        return false;

    if(element < p->key)  // 递归  
        return BSTInsert(p->lChild, element);

    return BSTInsert(p->rChild, element); // 递归  
}

// 建立BST  
void createBST(Node * &T, int a[], int n)
{
    T = NULL;
    int i;
    for(i = 0; i < n; i++)
    {
        BSTInsert(T, a[i]);
    }
}


#pragma region 递归

// 先序遍历  
void preOrderTraverse(BST T)
{
    BST p = T;
    if(p)
    {
        cout << p->key << " ";
        preOrderTraverse(p->lChild);
        preOrderTraverse(p->rChild);
    }
}

// 中序遍历  
void midOrderTraverse(BST T)
{
    if(T)
    {
        midOrderTraverse(T->lChild);
        cout << T->key << " ";
        midOrderTraverse(T->rChild);
    }
}

// 后序遍历  
void backOrderTraverse(BST T)
{
    if(T)
    {
        backOrderTraverse(T->lChild);
        backOrderTraverse(T->rChild);
        cout << T->key << " ";
    }
}

int Delete(BST & p)
{
    /* 从二叉排序树中删除节点p, 并重接它的左或右子树 */
    BST q, s;
    if(!p->lChild && !p->rChild) /* p为叶子节点 */
        p = 0;
    else if(!p->lChild) /* 左子树为空,重接右子树 */
    {
        q = p;
        p = p->rChild;
        free(q);
    }
    else if(!p->rChild) /* 右子树为空,重接左子树 */
    {
        q = p;
        p = p->lChild;
        free(q);
    }
    else                        /* 左右子树均不为空 */
    {
        q = p;
        s = p->lChild;
        while(s->rChild)     /* 转左,然后向右走到尽头*/
        {
            q = s;
            s = s->rChild;
        }
        p->key = s->key;
        if(q != p)               /* 判断是否执行上述while循环 */
            q->rChild = s->lChild;    /* 执行上述while循环,重接右子树 */
        else
            q->lChild = s->lChild;    /* 未执行上述while循环,重接左子树 */
        free(s);
    }
    return true;
}

bool DeleteBST(BST & T, int key)
{
    /* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素节点 */
    /* 并返回TRUE;否则返回FALSE */
    if(!T)
        return false;   /* 不存在关键字等于key的数据元素 */
    else
    {
        if(key == T->key)
            Delete(T);
        else if(key < T->key)
            return DeleteBST(T->lChild, key);
        else
            return DeleteBST(T->rChild, key);
    }
}


#pragma endregion


#pragma region 非递归

void levelOrderTraverse(BST T)
{
    BST p = T;
    if(p)
    {
        de.push_back(p);
    }
    while(!de.empty())
    {
        p = de.front();
        if(p->lChild)
        {
            de.push_back(p->lChild);
        }
        if(p->rChild)
        {
            de.push_back(p->rChild);
        }
        p = de.front();
        cout << p->key << " ";
        de.pop_front();
    }
}

void preSearch(BST T)
{
    stack<BST> s;
    BST p = T;
    while(p)
    {
        while(p)
        {
            cout << p->key << " ";
            s.push(p);
            p = p->lChild;
        }
        while(!s.empty() && !p)
        {
            p = s.top();
            s.pop();
            p = p->rChild;
        }
    }
}

void midSearch(BST T)
{
    BST p = T;
    stack<BST> s;
    while(p)
    {
        while(p)
        {
            s.push(p);
            p = p->lChild;
        }
        while(!s.empty() && !p)
        {
            p = s.top();
            cout << p->key << " ";
            s.pop();
            p = p->rChild;
        }
        //cout << p->key << " ";
    }
}

void backSearch(BST T)
{
    BST cur;                      
    BST pre = NULL;   
    s.push(T);
    while(!s.empty())
    {
        cur = s.top();
        if((cur->lChild == NULL&&cur->rChild == NULL) ||
            (pre != NULL && (pre == cur->lChild || pre == cur->rChild)))
        {
            cout << cur->key << " ";  //如果当前结点没有孩子结点或者孩子节点都已被访问过 
            s.pop();
            pre = cur;
        }
        else
        {
            if(cur->rChild != NULL)
                s.push(cur->rChild);
            if(cur->lChild != NULL)
                s.push(cur->lChild);
        }
    }
}

#pragma endregion

int main(void)
{
    int a[11] = { 10,6,11,5,9,13,4,8,12,14,7};
    int n = 11;
    BST T;

    // 并非所有的a[]都能构造出BST,所以,最好对createBST的返回值进行判断  
    createBST(T, a, n);
    cout << "前序遍历:" << endl;
    preOrderTraverse(T);
    cout << endl;
    preSearch(T);
    cout << endl;

    cout << "中序遍历:" << endl;
    midOrderTraverse(T);
    cout << endl;
    midSearch(T);
    cout << endl;

    cout << "后序遍历:" << endl;
    backOrderTraverse(T);
    cout << endl;
    backSearch(T);
    cout << endl;

    //cout << DeleteBST(T,2) << endl;
    cout << "层序遍历:" << endl;
    levelOrderTraverse(T);

    cout << "删除2之后" << endl;
    DeleteBST(T, 2);
    levelOrderTraverse(T);

    cout << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值