zoukankan      html  css  js  c++  java
  • 数据结构学习-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

  • 相关阅读:
    select&pselect/poll&ppoll/epoll
    软件常见基础问题总结
    FIFO、LRU、OPT这三种置换算法的缺页次数
    Django配置静态文件(CSSjs)及Django调用JS、CSS、图片等静态文件
    Django基础
    Django开发网站(四)
    Django开发网站(二)
    ubuntu1304下安装boa服务器
    Django开发网站(一)
    C语言中的七种排序算法
  • 原文地址:https://www.cnblogs.com/cyrio/p/10118132.html
Copyright © 2011-2022 走看看