当前位置:   article > 正文

二叉查找树(BST)及二叉树的遍历_bs二叉查找树

bs二叉查找树

一、二叉查找树(BST)

1、二叉查找树的特征

  二叉查找树(BST)也称为二叉搜索树或二叉排序树。二叉查找树的节点包含键值key。二叉查找树或者是一棵空树,否则要求:

1. 若它的左子树不为空,那么左子树上所有节点的key都小于根节点的key。

2. 若它的右子树不为空,那么右子树上所有节点的key都大于根节点的key。

3. 它的左右子树也分别为二叉排序树。
这里写图片描述

2、二叉查找树的建立、查找、插入和删除

(1)递归建立二叉查找树

btree creat_tree(btree root, int val)
{
    if (root == nullptr)//如果为空的二叉树,便将新的节点设定为根节点
    {
        root = new Binary_tree;
        root->data = val;
        root->left = nullptr;
        root->right = nullptr;
    }
    else if (root->data < val)//如果新值比节点值大,递归地建立右子树
        root->right = creat_tree(root->right, val);
    else if (root->data > val)//如果新值比节点值小,递归地建立左子树
        root->left = creat_tree(root->left, val);
    else
        exit(-1);
    return root;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

(2)查找节点

btree search_tree(btree ptr, int val)
{
    while(1)
    {
        if(ptr == nullptr)//没找到就返回NULL
            return nullptr;
        if(ptr->data == val)//节点值等于查找值
            return ptr;
        else if(ptr->data > val)//查找值比节点值小,向左子树搜索
            ptr = ptr->left;
        else
            ptr = ptr->right;//查找值比节点值大,向右子树搜索
    }   
}

//查找值最小的节点
btree findmin_tree(btree root)
{
    if (root == nullptr)//首先判断是否为空树
        return nullptr;
    if (root->left == nullptr)
        return root;
    else
        return findmin_tree(root->left);//使用递归判断
}

//查找值最大的节点
btree findmax_tree(btree root)
{
    if (root != nullptr)//首先判断是否为空树
        while (root->right != nullptr)//通过循环判断
            root = root->right;
    return root;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

(3)插入节点

这里写图片描述

btree insert_tree(btree root, int val)
{
    if (search_tree(root, val) == nullptr)
    {
        if (root == nullptr)
            creat_tree(root, val);//如果树为空,则创建树
        else if (val < root->data)
            //递归插入到左子树
            root->left = insert_tree(root->left, val);
        else if (val > root->data)
            //递归插入到右子树
            root->right = insert_tree(root->right, val);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(4)删除节点

这里写图片描述

btree remove_tree(btree root, int val)
{
    btree bt = search_tree(root, val);
    if (bt != nullptr)
    {
        if (val < root->data)//只有左子树
            root->left = remove_tree(root->left, val);
        else if (val > root->data)//只有右子树
            root->right = remove_tree(root->right, val);
        //左右子树都有
        else if (root->left != nullptr && root->right != nullptr)
        {
            //把右子树的最小值复制到当前节点
            root->data = findmin_tree(root->right)->data;
            //把最小值节点删除
            root->right = remove_tree(root->right, root->data);
        }
        else
        {
            //只有左子树或者右子树
            root = (root->left != nullptr)? root->left : root->right;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

二、二叉树的遍历

  遍历二叉树,就是以某种方式逐个“访问”二叉树的每一个节点。“访问”是指对节点的进行某种操作,例如输出节点的值。根据访问树根的顺序,我们有三种方式遍历二叉树:

1. 前序遍历:树根->左子树->右子树

2. 中序遍历:左子树->树根->右子树

3. 后序遍历:左子树->右子树->树根

1、前序遍历

  先访问根节点,再遍历左子树,最后遍历右子树;并且在遍历左右子树时,仍需先访问根节点,然后遍历左子树,最后遍历右子树。
  例如下图中二叉树前序遍历节点访问顺序为ABDGHCEIF:
这里写图片描述

2、中序遍历

  先遍历左子树、然后访问根节点,最后遍历右子树;并且在遍历左右子树的时候。仍然是先遍历左子树,然后访问根节点,最后遍历右子树。
  例如前图中二叉树中序遍历节点访问顺序为GDHBAEICF:
这里写图片描述

3、后序遍历

  先遍历左子树,然后遍历右子树,最后访问根节点;同样,在遍历左右子树的时候同样要先遍历左子树,然后遍历右子树,最后访问根节点。前图后序遍历结果如下。
  例如前图中二叉树后序遍历节点访问顺序为GHDBIEFCA:
这里写图片描述

4、确定唯一的二叉树

  在二叉树的三种遍历方式中,如果有中序与前序的遍历结果或者中序与后序的遍历结果,即可从这些结果中得到唯一的二叉树。

  确定唯一二叉树的方式:

1. 首先根据前序遍历的首元素或者后序遍历的尾元素,在中序遍历确定根节点。

2. 随后根据该根节点在中序遍历中确定左右子树。

三、前序、中序、后序遍历的递归和非递归实现

1、递归实现

void inorder(btree ptr)//中序(输出根节点次序)遍历(递归实现)
{
    if (ptr != nullptr)
    {
        inorder(ptr->left);
        cout << ptr->data << " ";
        inorder(ptr->right);
    }
}

void preorder(btree ptr)//前序遍历(递归实现)
{
    if (ptr != nullptr)
    {
        cout << ptr->data << " ";
        preorder(ptr->left);
        preorder(ptr->right);
    }
}

void postorder(btree ptr)//后序遍历(递归实现)
{
    if (ptr != nullptr)
    {
        postorder(ptr->left);
        postorder(ptr->right);
        cout << ptr->data << " ";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

2、非递归实现(使用栈)

//非递归中序遍历(左节点->根节点->右节点)思想:即用栈实现  
// 因为中序遍历二叉树的特点,所以在当前节点cur不为空或栈不为空的条件下(在该条件下的原因:该条件说明  
// 未遍历完二叉树),开始执行循环体,进行遍历:  
//(1)从当前节点cur开始,以cur为循环条件,当cur不为空时,将cur入栈,然后以cur=cur->_left跟进,直至  
//     将该二叉树的最左节点入栈后,入栈操作结束  
//(2)取栈顶节点:先保存该节点(用top保存该节点的原因:还要考虑该节点的右孩子)并输出该节点的值,  
//     然后执行栈的pop操作。  
//(3)继续以top->_right为cur值,转(1)操作.  

void inorder2(btree ptr)//中序遍历的非递归实现
{
    stack<btree> st;
    while (ptr != nullptr || !st.empty())
    {
        while (ptr != nullptr)
        {
            st.push(ptr);
            ptr = ptr -> left;
        }
        btree tp = st.top();
        cout << tp -> data << " ";
        st.pop();
        ptr = tp -> right;
    }
}

//非递归先序遍历(根节点->左节点->右节点)思想:即用栈实现  
//遍历二叉树的前提条件是:该二叉树不为空。在满足该条件的情况下,进行以下步骤:  
//1.先将二叉树的根节点push进栈。  
//2.在该栈不为空的条件下,执行一个循环(先用top保存栈顶元素,再对栈进行pop操作,因为栈具有后进先出的特点  
//  ,所以先对top->_right进行判断是否入栈,再对top->_left进行判断是否入栈)。  
//3.当栈为空时,先序遍历该二叉树结束。

void preorder2(btree ptr)//前序遍历的非递归实现
{
    stack<btree> st;
    if (ptr != nullptr)
    {
        st.push(ptr);
    }
    while (!st.empty())
    {       
        btree tp = st.top();
        st.pop();
        cout << tp -> data << " ";
        if (tp->right != nullptr)
            st.push(tp->right);
        if (tp->left != nullptr)
            st.push(tp->left);
    }
}

//非递归后序遍历(左节点->右节点->根节点)思想:即用栈实现  
//(1)在当前节点cur不为空或栈不为空的条件下(在该条件下的原因:该条件说明未遍历完二叉树)。  
//(2)从当前节点cur开始,以cur为循环条件,当cur不为空时,将cur入栈,然后以cur=cur->_left跟进,直至  
//     将该二叉树的最左节点入栈后,入栈操作结束。取栈顶节点top:先保存该节点(用top保存该节点的原因:  
//     还要考虑该节点的右孩子),  
//(3)若top->_right==NULL || lastVisited == top->_right,则输出top->_value,执行栈的pop操作,并执行lastVisited = top(  
//    用lastVisited保存最近一个所输出的节点,待到下一次同样的操作时,若lastVisited == top->_right,则  
//    说明top的右节点已经访问过了,可以访问top了,否则会陷在cur = top->_right这步操作里);  
//(4)若条件(3)不满足,则继续以top->_right为cur值,转(1)操作.  
void postorder2(btree ptr)//后序遍历的非递归实现
{
    stack<btree> st;
    btree lastVisited  = nullptr;
    while (ptr != nullptr || !st.empty())
    {
        while (ptr != nullptr)
        {
            st.push(ptr);
            ptr = ptr -> left;
        }
        btree tp = st.top();
        if (tp->right == nullptr || lastVisited == tp->right)
        {   
            st.pop();
            cout << tp -> data << " ";
            lastVisited = tp;
        }
        else 
            ptr = tp->right;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

参考:https://blog.csdn.net/xiaotan2011929/article/details/61427919
http://www.cnblogs.com/QG-whz/p/5168620.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/274977
推荐阅读
相关标签
  

闽ICP备14008679号