《数据结构与算法分析(c描述)》——二叉搜索树实现

实现二叉搜索树的插入、删除、查找、遍历(递归、非递归)

遍历

遍历实现可分递归、非递归两种版本。这里重点谈非递归实现。

不额外使用栈的非递归遍历又称为 Morris 遍历。

Morris 遍历,使用无堆栈,O(1) 空间进行二叉树遍历。它的原理很简单,利用所有叶子结点的右指针,指向其后继结点,组成一个环,在第二次遍历到这个结点时,由于其左子树已经遍历完了,则访问该结点。

算法伪代码:

while 没有结束
    if 当前节点(cur)没有左后代
        打印该节点
        访问右后代
    else
        找到当前节点(cur)左后代最右节点(temp)
        if temp 的右后代为空                   // 第一次访问 temp
            让其指向当前节点(cur)
            当前节点(cur)转向左后代
        if temp 的右后代点指向当前节点(cur)     // 第二次访问 temp 其左子树已经访问完
            让其指向空
            打印 temp 节点
            当前节点(cur)转向右后代

流程图:

下图为每一步迭代的结果(从左至右,从上到下),cur代表当前节点,深色节点表示该节点已输出。

这里写图片描述

代码实现:

void inorderMorrisTraversal(TreeNode *root) {
    TreeNode *cur = root, *prev = NULL;
    while (cur != NULL)
    {
        if (cur->left == NULL)          
        {
            printf("%d ", cur->val);
            cur = cur->right;
        }
        else
        {
            // find predecessor
            prev = cur->left;
            while (prev->right != NULL && prev->right != cur)
                prev = prev->right;

            if (prev->right == NULL)   
            {
                prev->right = cur;
                cur = cur->left;
            }
            else                       
            {
                prev->right = NULL;
                printf("%d ", cur->val);
                cur = cur->right;
            }
        }
    }
}

查找 find

非递归实现,寻找 val 出现的位置,没有找到则放回 val 的父节点

        treeNode * findPos(int val) {
            treeNode *ptr = m_root;
            while (ptr != NULL) {
                if (val < ptr->m_ival) {
                    if (ptr->left != NULL)
                        ptr = ptr->left;
                    else 
                        return ptr;
                }
                else if (val > ptr->m_ival) {
                    if (ptr->right != NULL)
                        ptr = ptr->right;
                    else 
                        return ptr;
                }
                else // 树中找到 val 直接返回
                    return ptr;
            }
            return ptr;
        }

插入 insert

插入的实现类似与查找,其递归实现非常简单,在此我们可以直接调用 findPos 完成非递归的实现。

        void insert(int val) {
            if (m_root == NULL) {
                m_root = new treeNode(val);
                return;
            }
            treeNode * trav = findPos(val);
            if (val < trav->m_ival)
                trav->left = new treeNode(val);
            else if (val > trav->m_ival)
                trav->right = new treeNode(val);
            // 如果 val == trav->m_ival, 就什么也不做
        }

删除 delete

比较复杂的是删除节点,需要分三种情况考虑。

  • 被删除节点为树叶,直接将其删除
  • 该节点有一个儿子,调整该节点的父节点指针绕过该节点后,再删除该节点
  • 该节点有两个儿子,右子树的最小值替换该节点,再删除右子树的最小值
        // 递归实现,返回删除节点之后的树
        treeNode *deleteRecursive(int val, treeNode *tree) {
            treeNode *minPos;
            if (tree == NULL)
                return NULL;
            if (val < tree->m_ival)
                tree->left = deleteRecursive(val, tree->left);
            else if(val > tree->m_ival)
                tree->right  = deleteRecursive(val, tree->right);
            else { // 已经找到值 val 
                // 两个孩子节点
                if (tree->left != NULL && tree->right != NULL) {
                    minPos = findMin(tree->right);
                    tree->m_ival = minPos->m_ival;
                    tree->right = deleteRecursive(minPos->m_ival, tree->right);
                }
                else {  // 一个孩子节点或没有孩子节点
                    if (tree->right != NULL)
                        tree = tree->right;
                    if (tree->left != NULL)
                        tree = tree->left;
                    else {
                        delete tree;
                        tree = NULL;
                    }
                }
            }
            return tree;
        }

整合

将所有代码整合起来,并加入测试代码。在 ubuntu 14.04 g++ 4.8.4 下编译测试通过。

完整代码如下:

#include<iostream>
using namespace std;

struct treeNode {
    int m_ival;
    treeNode *left;
    treeNode *right;
    treeNode(int val):  m_ival(val), left(NULL), right(NULL) {};
};

class SearchTree {
    public:
        SearchTree() { m_root = NULL; }
        // 非递归实现 insert
        void insert(int val) {
            if (m_root == NULL) {
                m_root = new treeNode(val);
                return;
            }
            treeNode * trav = findPos(val);
            if (val < trav->m_ival)
                trav->left = new treeNode(val);
            else if (val > trav->m_ival)
                trav->right = new treeNode(val);
            // 如果 val == trav->m_ival, 就什么也不做
        }

        string  preTravel() {
            string result;
            preTravelRecursive(m_root, result);
            return result;
        }

        void  preTravelRecursive(treeNode * root, string &result) {
            if (root != NULL) {
                result += to_string(root->m_ival);
                preTravelRecursive(root->left, result);
                preTravelRecursive(root->right, result);
            }
            else 
                result.push_back('#');
        }

        string inTravel() {
            string result;
            inTravelRecursive(m_root, result);
            return result;
        }

        void inTravelRecursive(treeNode *tree, string &result) {
            if (tree == NULL)
                result += '#';
            else {
                inTravelRecursive(tree->left, result);
                result += to_string(tree->m_ival);
                inTravelRecursive(tree->right, result);
            }
        }

        string inTravleMorris() {
            treeNode *cur = m_root;
            treeNode *twice = NULL;
            string result = "";
            while (cur != NULL) {
                if (cur->left == NULL) {
                    result += to_string(cur->m_ival);
                    cur = cur->right;
                }
                else {
                    twice = cur->left;
                    while (twice->right != NULL && twice->right != cur)
                        twice = twice->right;
                    if (twice->right == NULL) {
                        twice->right = cur;
                        cur = cur->left;
                    }
                    else {
                        twice->right = NULL;
                        result += to_string(cur->m_ival);
                        cur = cur->right;
                    }
                }
            }
            return result;
        }

        void deleteNode(int val) {
            deleteRecursive(val, m_root);
        }
        // 递归实现,返回删除节点之后的树
        treeNode *deleteRecursive(int val, treeNode *tree) {
            treeNode *minPos;
            if (tree == NULL)
                return NULL;
            if (val < tree->m_ival)
                tree->left = deleteRecursive(val, tree->left);
            else if(val > tree->m_ival)
                tree->right  = deleteRecursive(val, tree->right);
            else { // 已经找到值 val 
                // 两个孩子节点
                if (tree->left != NULL && tree->right != NULL) {
                    minPos = findMin(tree->right);
                    tree->m_ival = minPos->m_ival;
                    tree->right = deleteRecursive(minPos->m_ival, tree->right);
                }
                else {  // 一个孩子节点或没有孩子节点
                    if (tree->right != NULL)
                        tree = tree->right;
                    if (tree->left != NULL)
                        tree = tree->left;
                    else {
                        delete tree;
                        tree = NULL;
                    }
                }
            }
            return tree;
        }

    private:
        treeNode * m_root;
        // 寻找 val 应该出现的地点,没有找到则返回 val 的父结点
        treeNode * findPos(int val) {
            treeNode *ptr = m_root;
            while (ptr != NULL) {
                if (val < ptr->m_ival) {
                    if (ptr->left != NULL)
                        ptr = ptr->left;
                    else 
                        return ptr;
                }
                else if (val > ptr->m_ival) {
                    if (ptr->right != NULL)
                        ptr = ptr->right;
                    else 
                        return ptr;
                }
                else // 树中找到 val 直接返回
                    return ptr;
            }
            return ptr;
        }
        // 寻找最小值所在地点
        treeNode * findMin(treeNode *root) {
            if (root != NULL)
                while (root->left != NULL)
                    root = root->left;
            return root;
        }
};

int main() {
    SearchTree bst;

    bst.insert(5);
    bst.insert(3);
    bst.insert(14);
    bst.insert(2);
    bst.insert(4);
    bst.insert(9);
    bst.insert(15);
    bst.insert(7);
    bst.insert(8);
    cout << bst.preTravel() << endl;
    cout << bst.inTravel() << endl;
    cout << bst.inTravleMorris() << endl;
    bst.deleteNode(3);
    cout << bst.preTravel() << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值