資料結構學習-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