1. 程式人生 > >資料結構學習-BST二叉查詢樹

資料結構學習-BST二叉查詢樹

二叉查詢樹(Binary Search Tree)

是一種樹形的儲存資料的結構

如圖所示,它具有的特點是:

1、具有一個根節點

2、每個節點可能有0、1、2個分支

3、對於某個節點,他的左分支小於自身,自身小於右分支

接下來我們用c++來實現BST的封裝

首先我們編寫每個節點的類結構,分析可以知道我們每一個節點需要儲存一個數據(data),左分支(left指向一個節點),右分支(right指向另一個節點)

因此我們建立

bstNode.h

#ifndef TEST1_BSTNODE_H
#define TEST1_BSTNODE_H
template <typename T> //
這裡使用模板類,以放入多種型別的資料,值得一提的是模板類不能講宣告和實現放在兩個檔案中 class bstNode{ public: T data; bstNode* left; bstNode* right; bstNode(){ //預設建構函式 data = 0; left = nullptr; right = nullptr; } bstNode(T val){ //賦值建構函式 data = val; left = nullptr; right
= nullptr; } }; #endif //TEST1_BSTNODE_H

 

接下來我們建立封裝了各種方法的樹形結構類:

myBST.h

 

這個標頭檔案的設計思路如下:

 

1、先包含bstNode* root作為根節點,在通過根節點的左右指標延伸出整棵樹;

 

2、封裝了一些會用到的方法:搜尋指定值(Search)、找出一顆子樹中的最小值(treeMin)、插入指定值(Insert)、刪除指定值(Delete)、判斷是否是葉子結點(isLeaf)、判斷是否有兩個孩子(isNodeWithTwoChild)、

 

三種遍歷方式(前序PreorderTraversal、中序InorderTraversal、後序Postodertraversal)、刪除所有節點(DeleteAllNodes)、廣度搜索進行周遊(BFTraversal)、橫著畫圖(Graph)、返回根節點(getRoot)、判斷樹空(isEmpty)

 

預設建構函式、vector為引數的建構函式、陣列和長度為引數的建構函式、解構函式。

 

注意在這裡為了防止公有方法直接呼叫私有資料,採用了建立以"__"開頭的私有方法,讓公有方法先來呼叫該私有方法,再讓私有方法來呼叫私有資料,以確保其安全性。

 

#ifndef TEST1_MYBST_H
#define TEST1_MYBST_H

#include <iomanip>
#include "bstNode.h"
#include <vector>
#include <deque>
#include <iostream>
using namespace std;

template <typename T>
class myBST{
private:
    bstNode<T> * root = nullptr;
    bstNode<T> * __search(bstNode<T> * root , const T &key){
        if (nullptr == root)
            return nullptr;
        if (key == root->data)
            return root;
        else if (key < root->data)
            return __search(root->left, key);
        else
            return __search(root->right, key);
    } //查詢關鍵字是否存在
    bstNode<T> * __treeMin(bstNode<T> * root , bstNode<T> * &parent){
        bstNode<T> * curr = root;
        while(curr->left!= nullptr){
            parent = curr;
            curr = curr->left;
        }
        return  curr;
    } //返回最小節點(一路向左)
    bool __Insert(const T &key){
        bstNode<T> * temp = new bstNode<T>(key);
        bstNode<T> * parent = nullptr;
        if(isEmpty()){
            root=temp;
            return true;
        }
        else{
            bstNode<T> * curr;
            curr = root;
            while(curr){
                parent = curr;
                if(temp->data>curr->data) curr=curr->right;
                else curr = curr->left;
            }
            if(temp->data<parent->data){
                parent->left=temp;
                return true;
            }
            else {
                parent->right = temp;
                return true;
            }
        }
        return false;
    } //插入指定值
    bool __Delete(const T &key){
        bool found = false;//儲存有沒有找到key的變數
        if(isEmpty()){
            cerr<<"BST為空"<<endl;
            return false;
        }
        bstNode<T> * curr = root;
        bstNode<T> * parrent = nullptr;
        while(curr!= nullptr) {
            if (key == curr->data) {
                found = true;
                break;
            } else {
                parrent = curr;
                if (key < curr->data) curr = curr->left;
                else curr = curr->right;
            }
        }
        if(!found){
            cerr<<"未找到key!"<<endl;
            return false;
        }
        if (parrent == nullptr){//刪除根節點
            root = nullptr;
            delete(curr);
            return true;
        }
        /*
         刪除的節點有三種可能:
         1、葉子結點
         2、一個孩子的節點
         3、兩個孩子的節點
         */
        if (__isLeaf(curr)){ //刪除的點是葉子結點
            if(parrent->left==curr) parrent->left= nullptr;
            else parrent->right= nullptr;
            delete(curr);
            return true;
        }
        else if(__isNodeWithTwoChild(curr)){ //是兩個孩子的節點
            //以當前右子樹中的最小值取代他
            bstNode<T> * parrent = curr;
            bstNode<T> * tmp = __treeMin(curr->right,parrent);
            curr->data = tmp->data;
            if(parrent->right==tmp)
                parrent->right== nullptr;
            else parrent->left== nullptr;
            delete(tmp);
            return true;
        }
        else{ //只有一個孩子的節點
            if(curr->left!= nullptr){
                if(curr->left == curr){
                    parrent->left=curr->left;
                    delete(curr);
                    return true;
                }
                else{
                    parrent->right=curr->right;
                    delete(curr);
                    return true;
                }
            }
            if(curr->right!= nullptr){
                if(curr->left == curr){
                    parrent->left=curr->left;
                    delete(curr);
                    return true;
                }
                else{
                    parrent->right=curr->right;
                    delete(curr);
                    return true;
                }
            }
        }
        return false;
    } //刪除指定值
    bool __isLeaf(bstNode<T> * const & root){
        if(root->left== nullptr && root->right== nullptr) return true;
        else return false;
    }//判斷是否是葉子節點
    bool __isNodeWithTwoChild(bstNode<T> * const & root){
        if(root->left!= nullptr && root->right!= nullptr) return true;
        else return false;
    }//判斷是否有兩個孩子
    void __InorderTraversal(bstNode<T> *root,std::vector<int>&result){
        if(nullptr == root) return;
        __InorderTraversal(root->left,result);
        cout<<root->data<<" ";
        result.push_back(root->data);
        __InorderTraversal(root->right,result);
    }//中序遍歷
    void __PreorderTraversal(bstNode<T> *root,std::vector<int>&result){
        if(nullptr == root) return;
        cout<<root->data<<" ";
        result.push_back(root->data);
        __InorderTraversal(root->left,result);
        __InorderTraversal(root->right,result);
    }//前序遍歷
    void __PostorderTraversal(bstNode<T> *root,std::vector<int>&result){
        if(nullptr == root) return;
        __InorderTraversal(root->left,result);
        __InorderTraversal(root->right,result);
        cout<<root->data<<" ";
        result.push_back(root->data);
    }//後序遍歷
    void __DeleteAllNodes(bstNode<T> *root){
        if (root == nullptr) return;
        __DeleteAllNodes(root->left);
        __DeleteAllNodes(root->right);
        __Delete(root->data);
    }//刪除所有節點
    void __BFTraversal(vector<T>&result) {
        deque<bstNode<T> *> TQueue;
        bstNode<T> *pointer = root;
        if (pointer != nullptr) {
            TQueue.push_back(pointer);
        }
        while (!TQueue.empty()) {
            pointer = TQueue.front();
            TQueue.pop_front();
            cout << pointer->data << " ";
            result.push_back(pointer->data);
            if (pointer->left != nullptr) TQueue.push_back(pointer->left);
            if (pointer->right != nullptr) TQueue.push_back(pointer->right);
        }
    } //廣度搜索來進行周遊
    void __Graph(int indent,bstNode<T>* root){
        if(root != 0){
            __Graph(indent + 8, root->right);
            cout<<setw(indent)<<" "<<root->data<<endl;
            __Graph(indent + 8, root->left);
        }
    } //橫著畫圖的內部介面
    bstNode<T> * __GetRoot(){
        return root;
    } //返回根節點的內部介面
public:
    myBST(){
        root = nullptr;
    } //預設構造
    myBST(vector<T> arr){
        root = nullptr;
        for(int i =0;i<(int)arr.size();i++){
            __Insert(arr[i]);
        }
    }
    myBST(T * arr,int len){
        root = nullptr;
        for(int i =0;i<len;i++){
            __Insert(*(arr+i));
        }
    }
    ~myBST(){
        bstNode<T> * curr = root;
        __DeleteAllNodes(curr);
    }//析構
    bool isEmpty() const{
        return root == nullptr;
    }//判斷樹空
    bool search(const T &key){
        bstNode<T> * temp = __search(root, key);
        return (temp == nullptr) ? false : true;
    }//查詢關鍵字是否存在的對外介面
    bool Insert(const T &key){
        return __Insert(key);
    }//插入節點的外部介面
    bool Delete(const T &key){
        return __Delete(key);
    }//刪除節點的外部介面
    void InorderTraversal(vector<T>&result){
        __InorderTraversal(root, result);
    }//中序遍歷的外部介面
    void PreorderTraversal(vector<T>&result){
        __PreorderTraversal(root, result);
    }//前序遍歷的外部介面
    void PostorderTraversal(vector<T>&result){
        __PostorderTraversal(root, result);
    }//後序遍歷的外部介面
    void BFTraversal(vector<T>&result){
        return __BFTraversal(result);
    } //廣度搜索外部介面
    void Graph(int indent,bstNode<T>* root){
        return __Graph(indent,root);
    } //橫著畫圖的外部介面
    bstNode<T> * GetRoot(){
        return __GetRoot();
    } //返回根節點的外部介面
};

#endif //TEST1_MYBST_H

 

最後來進行測試:

main.cpp

#include <iostream>
#include <vector>
#include "myBST.h"
#include "bstNode.h"
using namespace std;
int main() {
    vector<int> in = {23,11,56,5,20,30,89,77,45,50};
    myBST<int> bst(in);
    bst.Delete(5);
    bst.Insert(4);
    bool found = bst.search(4);
    if(!found)
        cout<<"not found!"<<endl;
    else
        cout<<"found!"<<endl;
    vector<int> result;
    cout<<"InorderTravelsal:  ";
    bst.InorderTraversal(result);
    cout<<endl<<"PreorderTravelsal:  ";
    bst.PreorderTraversal(result);
    cout<<endl<<"PostorderTraversal:  ";
    bst.PostorderTraversal(result);
    cout<<endl<<"BFTraversal:  ";
    bst.BFTraversal(result);
    cout<<endl<<"Graph:"<<endl;
    bstNode<int>* pointer = bst.GetRoot();
    bst.Graph(0,pointer);
    return 0;
}

得到圖示結果:

參考:https://blog.csdn.net/zhangxiao93/article/details/51444972