數據結構13—二叉搜索樹,堆
二叉樹
二叉樹的定義
-
Binode的模版——遞歸定義法
template <typename T> struct BinNode { BinNodePosi(T) parent,lc,rc; //父節點及左、右孩子 int height; int size(); T data; // 構造函數 BinNode() : BinNodePosi(T) insertAsLC ( T const& ); //作為當前節點的左孩子插入新節點 BinNodePosi(T) insertAsRC ( T const& ); //作為當前節點的右孩子插入新節點 BinNodePosi(T) succ(); //取當前節點的直接后繼 template <typename VST> void travLevel ( VST& ); //子樹層次遍歷 template <typename VST> void travPre ( VST& ); //子樹先序遍歷 template <typename VST> void travIn ( VST& ); //子樹中序遍歷 template <typename VST> void travPost ( VST& ); //子樹后序遍歷 };
-
Binode接口實現
template <typename T> BinNodePosi(T)BinNode<T>::insertAsLC(T const& e) {return lc=new BinNode(e,this);} template <typename T> BinNodePosi(T)BinNode<T>::insertAsRC(T const& e) {return rc=new BinNode(e,this);} template <typename T> int BinNode<T>::size(){ int s=1; if(lc) s += lc->size(); if(rc) s +=rc->size(); return s; }
-
BinTree模版
template<typename T> class BinTree{ protected: int _size; BinNodePosi(T) _root; virtual int updateHeight(BinNodePosi(T)x); void updateHeightAbove(BinNodePosi(T)x); public: int size()const; bool empty()const{return !_root;} BinNodePosi(T) root()const {return _root;} /*...子樹接入刪除和分離接口...*/ /*...遍歷接口...*/ }
二叉搜索樹
二叉搜索樹search
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
//這樣函數定義的確會只返回二叉樹的內容,而不能返回節點的地址
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root==NULL) return NULL;
if(root->val==val)return root;
else if(root->val<val) return searchBST(root->right,val);
else return searchBST(root->left,val);
}
};
測試用例舉例:
[4,2,7,1,3]
2
二叉搜索樹的插入
遞歸
此遞歸代碼和老師講的稍微有所不同,需要返回的是整個樹,也就是返回root節點。通過這個代碼我深刻體會了老師所講*&對於進行指針操作的函數的重要作用。
比如我在這個代碼中定義了insertBSThelp函數進行主要迭代,那么怎么從這個函數中取出經過插入后的root指針呢?因此將此函數的入口參數設置為*&,因此這個函數就有操作外部指針的能力,經過這個函數操作的root指針再在insertIntoBST中return時就是經過插入的指針了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
insertBSThelp(root,val);
return root;
}
void insertBSThelp(TreeNode*& root, int val){
if(root==NULL)
{root= new TreeNode;
root->val=val;
return;
}
if(root->val==val) return;
if(root->val<val) {insertBSThelp(root->right,val);}
else { insertBSThelp(root->left,val);}
}
};
測試例例子:
[2,1,3,null,4]
5
測試結果
利用search
這個例子格外加強了我對*&的理解。在我看來*&比較像對指針的操作權限,放在函數的參數上是指函數具有對參數傳入指針的操作權限,而函數定義成為*&就可以讓外部有權利改變函數傳出的指針。
在這個例子中,依舊最終返回的應該是整個樹的root,因此三個函數分別起到不同的作用。
search找到外部指針root對應的樹中的對應節點的指針,傳出給insertBShelp,可以看到search函數用*&的傳入參數使其有權利對外部root進行修改,而函數定義*&又使得傳出的位置有權利修改search內部指針,就使得search外部傳出位置有權利修改外部的root的對應指針。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
insertBSThelp(root,val);
return root;
}
void insertBSThelp(TreeNode*root, int val){
TreeNode *&t=search(root,val);
if(t==NULL)
t=new TreeNode;
t->val=val;
}
TreeNode*& search(TreeNode*&root,double val){
if(root==NULL)return root;
if(root!=NULL&&root->val==val)
return root;
if(root->val>val)
return search(root->left,val);
else return search(root->right,val);
}
};
刪除
以刪除頂端為例。
- 有孩子中的一個把孩子掛上去
- 找右子樹的最左,把它的右孩掛上去。
過於混亂,不展示代碼了。
堆與優先級隊列
堆的作用是取前幾。
堆是完全二叉樹結構,因此使用數組存儲。
其大小關系是局部有序的,兄弟間無關系。
-
插入
只看被破壞位置到根節點路徑有無被破壞,到不破壞就停
-
刪除
- 頂部:把頂部和最后一個交換,頂部向下篩;比較當前三角形,如果有不是頂端的最小值就交換,等到三角形穩定就停。
- 中間;向上篩和向下篩都要。所以這個順序是?
-
建堆