搜索二叉树
二叉搜索樹:它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小于它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大于它的根結點的值; 它的左、右子樹也分別為二叉排序樹。
二叉搜索樹有個特點,最左的是最小的節點,最右的是最大的節點。
當我們把二叉搜索樹進行中序遍歷的時候,它是進行排序后的結果,所以我們也把二叉搜索樹叫做排序二叉樹。
接下來我們介紹二叉排序樹的所有的算法:
1.1搜索二叉樹的結構
首先我們來看它的結構,他的結構和二叉樹類似,所以會有一個左孩子節點的指針,一個右孩子節點的指針,還有一個被叫做鍵值的東西,我們通常來采用這個構建搜索二叉樹,然后還有一個叫做關鍵值,我們用它來保存數據。
template<typename K,typename V> struct SearchBinaryTreeNode {typedef SearchBinaryTreeNode<K,V> Node;SearchBinaryTreeNode(const K& key): _left(NULL), _right(NULL), _key(key){}V _value;Node* _left;Node* _right;K _key;};1.2構建搜索二叉樹
SearchBinaryTree(const K* arr, size_t size){assert(arr);for (size_t i = 0; i < size; i++){InsertP(arr[i]);}}把數組中的每一個元素作為節點,進行插入。
1.3搜索二叉樹的插入
搜索二叉樹關鍵的算法之一,在這里,我們的思路就是當你插入一個節點,必須是所指向的位置為空時才可以查入,所以我們來查找我們所需要插入的位置,如果為空樹,那么可以直接進行插入。
其他的用根節點的鍵值和key進行比較,如果key大于根節點鍵值,就說明在右子樹如果小,那么就說明在右子樹,如果相等,就說明已經出現了,不需要再次進行插入。最后如果我們所找到的位置為空那么這個時候我們就可以進行插入,插入的時候要看與父親節點的key進行比較,如果小插入右邊,如果大,插入左邊。
?
上面完成的是非遞歸的插入,另外,我們實現遞歸的插入,思路是一樣的。
遞歸的插入在最后只有找到為空的時候才能進行插入節點,否則就進行遞歸。
bool _InsertP(Node *&root, const K& key){if (root == NULL){root = new Node(key);return true;}if (root->_key > key){_InsertP(root->_left, key);}else if (root->_key < key){_InsertP(root->_right, key);}else{return false;}return true;}1.4搜索二叉樹的刪除
搜索二叉樹的刪除算法算是最難的了。在這里我們需要考慮幾種思路。
- 沒有這個節點
- 刪除根節點
- 刪除左子樹為空的節點
- 刪除右子樹為空的節點
- 刪除左右子書都不為空的節點
首先我們要做的是找到這個節點,然后找到這個節點的算法就類似與查找節點。
接下來我們要做的是分情況進行討論。
如果沒有這個節點,我們就不刪了,return。
接下來看它的孩子,當它孩子任意一個為空的時候,看他的孩子時要考慮刪除根節點的情況。刪除根節點,這個時候終點是改變root,另外的刪除其他節點,找到這個節點,然后看這個節點和父親節點的關系,進行調整就好了。
然后,進行討論兩個孩子都有的情況,首先我們就是利用交換的方式進行刪除,思路就是找到刪除節點的第一個右子樹節點的最左節點或者左子樹第一個節點的最右節點。簡單的說,就是把根變作左子樹最大的或者右子樹最小的。
綜合這個思路我們就可以完成刪除。
?
接下來介紹遞歸的刪除:
遞歸的刪除的思路和上面的是一樣的,重點是在于理解遞歸。
遞歸的時候進行的也先是查找,如果找不到返回,找到進行刪除。
這個時候我們也是一樣,看root節點的孩子進行分布操作,如果左為空,那么就給root右,右為空,就給左,在這里,其實這個root的含義相當于是parent的左指針或右指針。因為是遞歸,所以就是上一層函數左指針或者右指針。然后其他的和上面的思路是一樣的。
?
1.5搜索二叉樹的查找
搜索二叉樹的查找,這個算法其實上面我們在刪除已經進行過了,下面進行簡單的介紹一下,你要搜索的,那么就是和根的key比較,如果大于根的key,那么就找右樹,如果小于根的key,那么就找左樹。相等,就代表找到了。
bool Find(const K &key){if (_root == NULL)return false;Node *cur = _root;while (cur){if (key > cur->_key){cur = cur->_left;}else if (key < cur->_key){cur = cur->_right;}else{return true;}}return false;}下來是遞歸查找,思路上同,就不多說了。
bool _FindP(Node * root,const K& key){if (root == NULL){return false;}if (key < root->_key){return _FindP(root->_left, key);}else if (key>root->_key){return _FindP(root->_right, key);}else{return true;}return false;}1.5搜索二叉樹的MAX和MIN
另外的算法就是找最小和最大
這兩個算法就是查找算法的變形,一個是右子樹的最右節點,一個是左子樹的最左節點
代碼(全)
#pragma once#include<iostream> #include<cstdlib> #include<cassert> using namespace std;template<typename K,typename V> struct SearchBinaryTreeNode {typedef SearchBinaryTreeNode<K,V> Node;SearchBinaryTreeNode(const K& key): _left(NULL), _right(NULL), _key(key){}V _value;Node* _left;Node* _right;K _key;};template<typename K,typename V> class SearchBinaryTree { protected:typedef SearchBinaryTreeNode<K,V> Node;public:SearchBinaryTree(const K* arr, size_t size){assert(arr);for (size_t i = 0; i < size; i++){InsertP(arr[i]);}}~SearchBinaryTree(){_root=_DestorySBT(_root);}bool InsertP(const K& key){return _InsertP(_root, key);}bool Insert(const K& key){if (_root == NULL){_root = new Node(key);return true;}Node *cur = _root;Node *parent = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (curcur->_key>key){parent = cur;cur = cur->_left;}else{return false;}}Node *tmp = new Node(key);if (key > parent->_key){parent->_right = tmp;}else{parent->_left = tmp;}return true;}bool RemoveP(const K& key){return _RemoveP(_root, key);}bool Remove(const K& key){Node *cur = _root;Node *parent = NULL;Node *del = NULL;while (cur&&cur->_key!=key){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key>key){parent = cur;cur = cur->_left;}else{break;}}if (cur == NULL){return false; }if (cur->left == NULL){del = cur;if (parent == NULL){_root = cur->_right;}else{if (parent->_left == cur){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right==NULL){del = cur;if (parent == NULL){cur = cur->_left;}else{if (parent->_left == cur){parent->_left = cur->_left;}else{parent->_right = cur->_right;}}}else{Node *swapnode = cur->_right;while (swapnode->_left){parent = swapnode;swapnode = swapnode->_left;}del = swapnode;cur->_key = swapnode->_key;cur->_value = swapnode->_value;if (parent->_left == swapnode)parent->_left = swapnode->_right;elseparent->_right = swapnode->_right;}delete del;del = NULL;return true;}void Inorderprint(){_Inorderprint(_root);cout << endl;}bool Empty(){return _root == NULL;}bool Find(const K &key){if (_root == NULL)return false;Node *cur = _root;while (cur){if (key > cur->_key){cur = cur->_left;}else if (key < cur->_key){cur = cur->_right;}else{return true;}}return false;}bool FindP(const K &key){return _FindP(_root, key);}const K& Top(){return _root->_key;}const K& Minvalue(){assert(_root);Node* cur = _root;while (cur->_left){cur = cur->_left;}return cur->_value;}const K& Maxvalue(){assert(_root);Node *cur = _root;while (cur->_right){cur = cur->_right;}return cur->_value;} protected:Node* _DestorySBT(Node *root){if (root != NULL){root->_left = _DestorySBT(root->_left);root->_right = _DestorySBT(root->_right);delete root;root = NULL;}return root;}void _Inorderprint(Node *root){if (root == NULL)return;_Inorderprint(root->_left);cout << root->_key << " ";_Inorderprint(root->_right);}bool _InsertP(Node *&root, const K& key){if (root == NULL){root = new Node(key);return true;}if (root->_key > key){_InsertP(root->_left, key);}else if (root->_key < key){_InsertP(root->_right, key);}else{return false;}return true;}bool _RemoveP(Node *&root, const K& key){if (root == NULL){return false;}if (root->_key < key){_RemoveP(root->_right,key);}else if (root->_key > key){_RemoveP(root->_left,key);}else{Node* del = root;if (root->_left == NULL){root = root->_right;}else if (root->_right == NULL){root = root->_left;}else{Node* parent = root;Node *swapnode = root->_right;while (swapnode->_left){parent = swapnode;swapnode = swapnode->_left;}root->_key = swapnode->_key;root->_value = swapnode->_value;if (parent->_right == swapnode)parent->_right = swapnode->_right;elseparent->_left = swapnode->_right;del = swapnode;}delete del;return true;}return false;}bool _FindP(Node * root,const K& key){if (root == NULL){return false;}if (key < root->_key){return _FindP(root->_left, key);}else if (key>root->_key){return _FindP(root->_right, key);}else{return true;}return false;} protected:Node * _root; };?
總結
- 上一篇: 浅析AVL树
- 下一篇: Linux下的进程概论与编程二(进程控制