数据结构--二叉查找树 Binary Search Tree
生活随笔
收集整理的這篇文章主要介紹了
数据结构--二叉查找树 Binary Search Tree
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
文章目錄
- 1.二叉查找樹概念
- 2.二叉查找樹操作
- 2.1 查找
- 2.2 插入
- 2.3 刪除
- 2.4 其他
- 3. 支持重復(fù)數(shù)據(jù)的二叉查找樹
- 4 有散列表了,還需要二叉查找樹?
- 5 代碼實(shí)現(xiàn)
1.二叉查找樹概念
二叉查找樹要求,在樹中的任意一個(gè)節(jié)點(diǎn),其左子樹中的每個(gè)節(jié)點(diǎn)的值,都要小于這個(gè)節(jié)點(diǎn)的值,而右子樹節(jié)點(diǎn)的值都大于這個(gè)節(jié)點(diǎn)的值。
2.二叉查找樹操作
2.1 查找
2.2 插入
2.3 刪除
2.4 其他
- 支持快速地查找最大節(jié)點(diǎn)和最小節(jié)點(diǎn)、前驅(qū)節(jié)點(diǎn)和后繼節(jié)點(diǎn)。
- 中序遍歷二又查找樹,可以輸出有序的數(shù)據(jù)序列,時(shí)間復(fù)雜度是 O(n) ,非常高效。因此,二叉查找樹也叫作二叉排序樹。
3. 支持重復(fù)數(shù)據(jù)的二叉查找樹
- 通過鏈表和支持動(dòng)態(tài)擴(kuò)容的數(shù)組等數(shù)據(jù)結(jié)構(gòu),把值相同的數(shù)據(jù)都存儲(chǔ)在同一個(gè)節(jié)點(diǎn)上。
- 每個(gè)節(jié)點(diǎn)仍然只存儲(chǔ)一個(gè)數(shù)據(jù)。在查找插入位置的過程中,如果碰到一個(gè)節(jié)點(diǎn)的值,與要插入數(shù)據(jù)的值相同,我們就將這個(gè)要插入的數(shù)據(jù)放到這個(gè)節(jié)點(diǎn)的右子樹,也就是說,把這個(gè)新插入的數(shù)據(jù)當(dāng)作大于這個(gè)節(jié)點(diǎn)的值來處理。
- 在二叉查找樹中,查找、插入、刪除等很多操作的時(shí)間復(fù)雜度都跟樹的高度成正比。兩個(gè)極端情況的時(shí)間復(fù)雜度分別是 O(n) 和 O(logn) ,分別對(duì)應(yīng)二叉樹退化成鏈表的情況和完全二叉樹。
- 為了避免時(shí)間復(fù)雜度的退化,針對(duì)二又查找樹,我們又設(shè)計(jì)了一種更加復(fù)雜的樹,平衡二叉查找樹,時(shí)間復(fù)雜度可以做到穩(wěn)定的 O(logn)
4 有散列表了,還需要二叉查找樹?
- 散列表時(shí)間復(fù)雜度可以做到常量級(jí)的O(1), 而二叉查找樹在比較平衡的情況下, 時(shí)間復(fù)雜度才是 O(logn), 相對(duì)散列表,好像并沒有什么優(yōu)勢(shì),那我們?yōu)槭裁催€要用二叉查找樹呢?
幾個(gè)原因: - 第一, 散列表中的數(shù)據(jù)是無序存儲(chǔ)的, 如果要輸出有序的數(shù)據(jù),需要先進(jìn)行排序.而對(duì)于二叉查找樹來說,我們只需要中序遍歷,就可以在O(n)的時(shí)間復(fù)雜度內(nèi),輸出有序的數(shù)據(jù)序列.
- 第二, 散列表擴(kuò)容耗時(shí)很多,而且當(dāng)遇到散列沖突時(shí),性能不穩(wěn)定,盡管二叉查找樹的性能不穩(wěn)定,但是在工程中,我們最常用的平衡二叉查找樹的性能非常穩(wěn)定,時(shí)間復(fù)雜度穩(wěn)定在O(logn).
- 第三, 盡管散列表的查找等操作的時(shí)間復(fù)雜度是常量級(jí)的,但因?yàn)楣_突的存在,這個(gè)常量不一定比 logn 小,所以實(shí)際的查找速度可能不一定比 O(logn) 快. 加上哈希函數(shù)的耗時(shí),也不一定就比平衡二又查找樹的效率高.
- 第四, 散列表的構(gòu)造比二又查找樹要復(fù)雜,需要考慮的東西很多. 比如散列函數(shù)的設(shè)計(jì)、沖突解決辦法、擴(kuò)容、縮容等.平衡二又查找樹只需要考慮平衡性這一個(gè)問題,而且這個(gè)問題的解決方案比較成熟、固定.
- 最后,為了避免過多的散列沖突,散列表裝載因子不能太大,特別是基于開放尋址法解決沖突的散列表,不然會(huì)浪費(fèi)一定的存儲(chǔ)空間.
- 綜合這幾點(diǎn), 平衡二又查找樹在某些方面還是優(yōu)于散列表的, 所以,這兩者的存在并不沖突. 我們?cè)趯?shí)際的開發(fā)過程中,需要結(jié)合具體的需求來選擇使用哪一個(gè).
5 代碼實(shí)現(xiàn)
/*** @description: 二叉查找樹* @author: michael ming* @date: 2019/5/16 23:48* @modified by: */ #include <iostream> #include <random> #include <time.h> using namespace std; template <class T> class BSTNode { public:T data;BSTNode<T> *left, *right;BSTNode():left(NULL), right(NULL){}BSTNode(const T& d, BSTNode<T> *l = NULL, BSTNode<T> *r = NULL){data = d; left = l; right = r;} }; template <class T> class BST { private:BSTNode<T>* root;int nodeLen; public:BST():root(NULL){}~BST(){clear(root);root = NULL;}void clear(BSTNode<T>* nodeP){if(nodeP == NULL)return;if (nodeP == NULL)return;clear(nodeP->left);clear(nodeP->right);delete nodeP;}BSTNode<T>* get_root() const { return root; }bool isEmpty() const { return root == NULL; }T* search(const T& d) const{return search(d, root);}T* search(const T& d, BSTNode<T>* p) const{while(p != NULL){if(d == p->data)return &(p->data);else if(d < p->data)p = p->left;elsep = p->right;}return 0;}T* get_max_data(){if(root == NULL)return NULL;BSTNode<T>* temp = root;while(temp->right != NULL)temp = temp->right;return &temp->data;}T* get_min_data(){if(root == NULL)return NULL;BSTNode<T>* temp = root;while(temp->left != NULL)temp = temp->left;return &temp->data;}void insert(const T& d){BSTNode<T> *p = root, *prev = NULL;while(p != NULL){prev = p;if(d < p->data)p = p->left;elsep = p->right;}if(root == NULL)root = new BSTNode<T>(d);else if(d < prev->data)prev->left = new BSTNode<T>(d);elseprev->right = new BSTNode<T>(d);}void del(T d){if(root == NULL)return;BSTNode<T> *p = root, *pfather = NULL;while(p != NULL && p->data != d){pfather = p;if(d > p->data)p = p->right;elsep = p->left;}if(p == NULL) //沒找到dreturn;if(p->left != NULL && p->right != NULL)//要?jiǎng)h除的節(jié)點(diǎn)有2個(gè)子節(jié)點(diǎn){BSTNode<T> *minP = p->right, *minPFather = p;//找到右子樹最小的跟要?jiǎng)h的交換while(minP->left != NULL) //右子樹最小的肯定在左節(jié)點(diǎn){minPFather = minP;minP = minP->left;}p->data = minP->data; //把右子樹最小的數(shù)付給要?jiǎng)h除的節(jié)點(diǎn)datap = minP; //minP付給p,刪除ppfather = minPFather;}//要?jiǎng)h除的是葉節(jié)點(diǎn)或者只有1個(gè)節(jié)點(diǎn)BSTNode<T>* child;if(p->left != NULL)child = p->left;else if(p->right != NULL)child = p->right;elsechild = NULL;if(pfather == NULL)//p是根節(jié)點(diǎn)root = child;else if(p == pfather->left)pfather->left = child;elsepfather->right = child;delete p;p = NULL;}int get_height(BSTNode<T>* nodep) //遞歸法, 求左右子樹高度,較大的+1{if(nodep == NULL)return 0;int leftheight = get_height(nodep->left);int rightheight = get_height(nodep->right);return max(leftheight, rightheight) + 1;}void inOrderPrint(BSTNode<T>* nodep) //二叉查找樹用中序打印,是有序的{if (nodep == NULL)return;inOrderPrint(nodep->left);cout << nodep->data << " ";inOrderPrint(nodep->right);} };int main() {BST<int> intBST;srand(time(0));for(int i = 0; i < 6; ++i){intBST.insert(rand());}intBST.insert(7);if(intBST.search(7))cout << *(intBST.search(7)) << endl;cout << "BST height: " << intBST.get_height(intBST.get_root()) << endl;intBST.inOrderPrint(intBST.get_root());cout << "max : " << *(intBST.get_max_data()) << ", min : " << *(intBST.get_min_data()) << endl;intBST.del(7);intBST.inOrderPrint(intBST.get_root());return 0; }總結(jié)
以上是生活随笔為你收集整理的数据结构--二叉查找树 Binary Search Tree的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode 559. N叉树的最大
- 下一篇: 动态规划应用--搜索引擎拼写纠错