1. 程式人生 > 實用技巧 >C++二叉搜尋樹

C++二叉搜尋樹

//BST.h
#pragma once
template <typename T> class BST;
template <typename T> class BSTNode {
public:
    friend class BST<T>;
    BSTNode() {
        lChild = rChild = parent = nullptr;
        data = nullptr;
    }
    BSTNode(T value) {
        lChild = rChild = parent = nullptr;
        data = value;
    }
private:
    BSTNode<T>* lChild, * rChild, * parent;
    T data;
};

template<typename T> class BST {
public:
    BST() { }

    //插入操作
    void insert(BSTNode<T>* node);

    //二叉查詢樹的中序遍歷,就相當於排序了
    void inSort(BSTNode<T>* node);

    //按節點刪除
    void deleteNode(BSTNode<T>* node);

    //按數值刪除
    void deleteNode(const T& t);

    BSTNode<T>* search(T key);
    BSTNode<T>* root = nullptr;

private:
    int count;
};

template<typename T>
void BST<T>::insert(BSTNode<T>* node)
{
    BSTNode<T>* curr, * temp = nullptr;
    curr = root;
    while (nullptr != curr) //遍歷二叉樹,找到應該插入的父節點
    {
        temp = curr;
        if (node->data > curr->data)
        {
            curr = curr->rChild;
        }
        else {
            curr = curr->lChild;
        }
    }
    node->parent = temp;//temp 程式碼當前最後遍歷的node,設定node->parent為該節點
    if (temp == nullptr)
    {
        root = node;
        count++;
    }
    else {
        if (node->data < temp->data)
        {
            temp->lChild = node;
            count++;
        }
        else {
            temp->rChild = node;
            count++;
        }
    }
}

template<typename T>
void BST<T>::inSort(BSTNode<T>* node)
{
    if (node != nullptr)
    {
        inSort(node->lChild);
        std::cout << node->data << ",";
        inSort(node->rChild);
    }
}

template<typename T>
inline void BST<T>::deleteNode(BSTNode<T>* node)
{
    BSTNode<T>* p = node->parent;//獲取node的父節點,這裡很重要
    if (node->lChild == nullptr && node->rChild == nullptr) //葉子節點直接刪除
    {
        if (node == node->parent->lChild)
        {
            node->parent->lChild = nullptr;
        }
        else {
            node->parent->rChild = nullptr;
        }
        delete node;
        count--;
    }
    else if (node->rChild != nullptr && node->lChild == nullptr) {//存在右孩子
        if (p == nullptr)//說明節點為根節點
        {
            root = node->rChild;
            count--;
        }
        else {
            node->rChild->parent = p;
            if (p->lChild == node) //判斷是父節點的左孩子還是右孩子
            {
                p->lChild = node->rChild;
            }
            else {
                p->rChild = node->rChild;
            }
            delete node;
            count--;
        }
    }
    else if (node->lChild != nullptr && node->rChild == nullptr)//存在左孩子
    {
        if (p == nullptr)
        {
            root = root->lChild;
            count--;
        }
        else {
            node->lChild->parent = p;
            if (p->lChild == node)
            {
                p->lChild = node->lChild;
            }
            else {
                p->rChild = node->lChild;
            }
            delete node;
            count--;
        }
    }
    else {
        BSTNode<T>* left, * curp = nullptr;
        left = node->rChild; //本方案是找右側最小值,替換node節點,其他節點保持不動即可
        while (left != nullptr)
        {
            curp = left;
            left = left->lChild;
        }

        if (curp->rChild != nullptr)
        {
            if (curp->lChild == curp)
            {
                curp->parent->lChild = curp->rChild;
            }
            else {
                curp->parent->rChild = curp->rChild;
            }
        }
        else {
            if (curp->parent->lChild == curp)
            {
                curp->parent->lChild = nullptr;
            }
            else {
                curp->parent->rChild = nullptr;
            }
            //curp->parent->lChild = nullptr;
        }
        //替curp 替換 node
        curp->parent = p;
        curp->lChild = node->lChild;
        curp->rChild = node->rChild;

        if (p->lChild == node)//判斷node 是p 的左孩子還是右孩
        {
            p->lChild = curp;
        }
        else {
            p->rChild = curp;
        }
        delete node;
        count--;
    }
}

template<typename T>
inline void BST<T>::deleteNode(const T& k)
{
    BSTNode<T>* node = search(k);
    if (node != nullptr)
    {
        deleteNode(node);
    }
}


template<typename T>
inline BSTNode<T>* BST<T>::search(T k)
{
    BSTNode<T>* node = root;
    while (node != nullptr)
    {
        if (k < node->data)
        {
            node = node->lChild;
        }
        else if (k > node->data)
        {
            node = node->rChild;
        }
        else {
            break;
        }
    }
    return node;
}

//BSTree.h
//BST.cpp
#include "BST.h"
//main.cpp
//https://www.cnblogs.com/clc2008/p/10193550.html
//#include "pch.h"
#include <iostream>
#include "BST.h"
using namespace std;

int main()
{
    // 樹結構示意
    //     30
    //    /  \
    //  15   25
    // /  \
    //9    18
    //   /   \
    //  16   25
    //      /  \
    //    20    26  
    BST<int> sbt;
    sbt.insert(new BSTNode<int>(30));
    sbt.insert(new BSTNode<int>(15));
    sbt.insert(new BSTNode<int>(9));
    sbt.insert(new BSTNode<int>(18));
    sbt.insert(new BSTNode<int>(16));
    sbt.insert(new BSTNode<int>(25));
    sbt.insert(new BSTNode<int>(20));
    sbt.insert(new BSTNode<int>(26));
    sbt.insert(new BSTNode<int>(35));

    cout << "搜尋樹排序後:";
    sbt.inSort(sbt.root);

    sbt.deleteNode(18);

    cout << endl << "刪除18 後排序:";

    sbt.inSort(sbt.root);
}