什麼是二叉查找樹
二叉查找樹(Binary Search Tree)又叫二叉排序樹(Binary Sort Tree),它是一種數據結構,支持多種動態集合操作,如 Search、Insert、Delete、Minimum 和 Maximum 等。
二叉查找樹要麼是一棵空樹,要麼是一棵具有如下性質的非空二叉樹:
若左子樹非空,則左子樹上的所有結點的關鍵字值均小於根結點的關鍵字值。
若右子樹非空,則右子樹上的所有結點的關鍵字值均大於根結點的關鍵字值。
左、右子樹本身也分別是一棵二叉查找樹(二叉排序樹)。
可以看出,二叉查找樹是一個遞歸的數據結構,且對二叉查找樹進行中序遍歷,可以得到一個遞增的有序序列。
二叉查找樹的C++模板實現文件(BSTree.h)
這裏因爲是模板類,所以二叉查找樹的類的相關實現放在頭文件中。
下面是一些二叉查找樹的相關方法實現。
/**
* C++ 語言: 二叉查找樹
*/
#ifndef _BINARY_SEARCH_TREE_HPP_
#define _BINARY_SEARCH_TREE_HPP_
#include <iomanip>
#include <iostream>
using namespace std;
template <class T>
class BSTNode{
public:
T key; // 關鍵字(鍵值)
BSTNode *left; // 左孩子
BSTNode *right; // 右孩子
BSTNode *parent;// 父結點
BSTNode(T value, BSTNode *p, BSTNode *l, BSTNode *r):
key(value),parent(p),left(l),right(r) {}
};
template <class T>
class BSTree {
private:
BSTNode<T> *mRoot; // 根結點
public:
BSTree();
~BSTree();
// 前序遍歷"二叉樹"
void preOrder();
// 中序遍歷"二叉樹"
void inOrder();
// 後序遍歷"二叉樹"
void postOrder();
// 層序遍歷"二叉樹"
void BFS_Tree();
// 深度
int deep();
// (遞歸實現)查找"二叉樹"中鍵值爲key的節點
BSTNode<T>* search(T key);
// (非遞歸實現)查找"二叉樹"中鍵值爲key的節點
BSTNode<T>* iterativeSearch(T key);
// 查找最小結點:返回最小結點的鍵值。
T minimum();
// 查找最大結點:返回最大結點的鍵值。
T maximum();
// 找結點(x)的後繼結點。即,查找"二叉樹中數據值大於該結點"的"最小結點"。
BSTNode<T>* successor(BSTNode<T> *x);
// 找結點(x)的前驅結點。即,查找"二叉樹中數據值小於該結點"的"最大結點"。
BSTNode<T>* predecessor(BSTNode<T> *x);
// 將結點(key爲節點鍵值)插入到二叉樹中
void insert(T key);
// 刪除結點(key爲節點鍵值)
void remove(T key);
// 銷燬二叉樹
void destroy();
// 打印二叉樹
void print();
private:
// 前序遍歷"二叉樹"
void preOrder(BSTNode<T>* tree) const;
// 中序遍歷"二叉樹"
void inOrder(BSTNode<T>* tree) const;
// 後序遍歷"二叉樹"
void postOrder(BSTNode<T>* tree) const;
// 層序遍歷"二叉樹"
void BFS_Tree(BSTNode<T>* tree) const;
//深度
int deep(BSTNode<T>* tree);
// (遞歸實現)查找"二叉樹x"中鍵值爲key的節點
BSTNode<T>* search(BSTNode<T>* x, T key) const;
// (非遞歸實現)查找"二叉樹x"中鍵值爲key的節點
BSTNode<T>* iterativeSearch(BSTNode<T>* x, T key) const;
// 查找最小結點:返回tree爲根結點的二叉樹的最小結點。
BSTNode<T>* minimum(BSTNode<T>* tree);
// 查找最大結點:返回tree爲根結點的二叉樹的最大結點。
BSTNode<T>* maximum(BSTNode<T>* tree);
// 將結點(z)插入到二叉樹(tree)中
void insert(BSTNode<T>* &tree, BSTNode<T>* z);
// 刪除二叉樹(tree)中的結點(z),並返回被刪除的結點
BSTNode<T>* remove(BSTNode<T>* &tree, BSTNode<T> *z);
// 銷燬二叉樹
void destroy(BSTNode<T>* &tree);
// 打印二叉樹
void print(BSTNode<T>* tree, T key, int direction);
};
/*
* 構造函數
*/
template <class T>
BSTree<T>::BSTree():mRoot(NULL)
{
}
/*
* 析構函數
*/
template <class T>
BSTree<T>::~BSTree()
{
destroy();
}
/*
* 前序遍歷"二叉樹"
*/
template <class T>
void BSTree<T>::preOrder(BSTNode<T>* tree) const
{
if(tree != NULL)
{
cout<< tree->key << " " ;
preOrder(tree->left);
preOrder(tree->right);
}
}
template <class T>
void BSTree<T>::preOrder()
{
preOrder(mRoot);
}
/*
* 中序遍歷"二叉樹"
*/
template <class T>
void BSTree<T>::inOrder(BSTNode<T>* tree) const
{
if(tree != NULL)
{
inOrder(tree->left);
cout<< tree->key << " " ;
inOrder(tree->right);
}
}
template <class T>
void BSTree<T>::inOrder()
{
inOrder(mRoot);
}
/*
* 後序遍歷"二叉樹"
*/
template <class T>
void BSTree<T>::postOrder(BSTNode<T>* tree) const
{
if(tree != NULL)
{
postOrder(tree->left);
postOrder(tree->right);
cout<< tree->key << " " ;
}
}
template <class T>
void BSTree<T>::postOrder()
{
postOrder(mRoot);
}
//層次遍歷
template <class T>
void BSTree<T>::BFS_Tree(BSTree * root) const
{
if(root == NULL)
return;
//藉助雙端隊列存儲遍歷的結點
deque<T> d;
d.push_back(root);
while(d.size())
{
BSTree temp = d.front();
cout << d.front()->data;
d.pop_front();
if(temp->Lchild)
d.push_back(temp->Lchild);
if(temp->Rchild)
d.push_back(temp->Rchild);
}
}
template <class T>
void BSTree<T>::BFS_Tree()
{
BFS_Tree(mRoot);
}
/*
* "二叉樹"深度
*/
template <class T>
int BSTree<T>::deep(BSTNode<T>* root) const
{
if(root == null)
{
return 0;
}
else
{
int lchilddeep = deep(root->left);//求左子樹的深度
int rchilddeep = deep(root->left);//求右子樹的深度
return lchilddeep > rchilddeep ? lchilddeep + 1 : rchilddeep + 1;//左子樹和右子樹深度較大的那個加一等於整個樹的深度
}
}
template <class T>
int BSTree<T>::deep()
{
deep(mRoot);
}
/*
* (遞歸實現)查找"二叉樹x"中鍵值爲key的節點
*/
template <class T>
BSTNode<T>* BSTree<T>::search(BSTNode<T>* x, T key) const
{
if (x==NULL || x->key==key)
return x;
if (key < x->key)
return search(x->left, key);
else
return search(x->right, key);
}
template <class T>
BSTNode<T>* BSTree<T>::search(T key)
{
search(mRoot, key);
}
/*
* (非遞歸實現)查找"二叉樹x"中鍵值爲key的節點
*/
template <class T>
BSTNode<T>* BSTree<T>::iterativeSearch(BSTNode<T>* x, T key) const
{
while ((x!=NULL) && (x->key!=key))
{
if (key < x->key)
x = x->left;
else
x = x->right;
}
return x;
}
template <class T>
BSTNode<T>* BSTree<T>::iterativeSearch(T key)
{
iterativeSearch(mRoot, key);
}
/*
* 查找最小結點:返回tree爲根結點的二叉樹的最小結點。
*/
template <class T>
BSTNode<T>* BSTree<T>::minimum(BSTNode<T>* tree)
{
if (tree == NULL)
return NULL;
while(tree->left != NULL)
tree = tree->left;
return tree;
}
template <class T>
T BSTree<T>::minimum()
{
BSTNode<T> *p = minimum(mRoot);
if (p != NULL)
return p->key;
return (T)NULL;
}
/*
* 查找最大結點:返回tree爲根結點的二叉樹的最大結點。
*/
template <class T>
BSTNode<T>* BSTree<T>::maximum(BSTNode<T>* tree)
{
if (tree == NULL)
return NULL;
while(tree->right != NULL)
tree = tree->right;
return tree;
}
template <class T>
T BSTree<T>::maximum()
{
BSTNode<T> *p = maximum(mRoot);
if (p != NULL)
return p->key;
return (T)NULL;
}
/*
* 找結點(x)的後繼結點。即,查找"二叉樹中數據值大於該結點"的"最小結點"。
*/
template <class T>
BSTNode<T>* BSTree<T>::successor(BSTNode<T> *x)
{
// 如果x存在右孩子,則"x的後繼結點"爲 "以其右孩子爲根的子樹的最小結點"。
if (x->right != NULL)
return minimum(x->right);
// 如果x沒有右孩子。則x有以下兩種可能:
// (01) x是"一個左孩子",則"x的後繼結點"爲 "它的父結點"。
// (02) x是"一個右孩子",則查找"x的最低的父結點,並且該父結點要具有左孩子",找到的這個"最低的父結點"就是"x的後繼結點"。
BSTNode<T>* y = x->parent;
while ((y!=NULL) && (x==y->right))
{
x = y;
y = y->parent;
}
return y;
}
/*
* 找結點(x)的前驅結點。即,查找"二叉樹中數據值小於該結點"的"最大結點"。
*/
template <class T>
BSTNode<T>* BSTree<T>::predecessor(BSTNode<T> *x)
{
// 如果x存在左孩子,則"x的前驅結點"爲 "以其左孩子爲根的子樹的最大結點"。
if (x->left != NULL)
return maximum(x->left);
// 如果x沒有左孩子。則x有以下兩種可能:
// (01) x是"一個右孩子",則"x的前驅結點"爲 "它的父結點"。
// (01) x是"一個左孩子",則查找"x的最低的父結點,並且該父結點要具有右孩子",找到的這個"最低的父結點"就是"x的前驅結點"。
BSTNode<T>* y = x->parent;
while ((y!=NULL) && (x==y->left))
{
x = y;
y = y->parent;
}
return y;
}
/*
* 將結點插入到二叉樹中
*
* 參數說明:
* tree 二叉樹的根結點
* z 插入的結點
*/
template <class T>
void BSTree<T>::insert(BSTNode<T>* &tree, BSTNode<T>* z)
{
BSTNode<T> *y = NULL;
BSTNode<T> *x = tree;
// 查找z的插入位置
while (x != NULL)
{
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y==NULL)
tree = z;
else if (z->key < y->key)
y->left = z;
else
y->right = z;
}
/*
* 將結點(key爲節點鍵值)插入到二叉樹中
*
* 參數說明:
* tree 二叉樹的根結點
* key 插入結點的鍵值
*/
template <class T>
void BSTree<T>::insert(T key)
{
BSTNode<T> *z=NULL;
// 如果新建結點失敗,則返回。
if ((z=new BSTNode<T>(key,NULL,NULL,NULL)) == NULL)
return ;
insert(mRoot, z);
}
/*
* 刪除結點(z),並返回被刪除的結點
*
* 參數說明:
* tree 二叉樹的根結點
* z 刪除的結點
*/
template <class T>
BSTNode<T>* BSTree<T>::remove(BSTNode<T>* &tree, BSTNode<T> *z)
{
BSTNode<T> *x=NULL;
BSTNode<T> *y=NULL;
if ((z->left == NULL) || (z->right == NULL) )
y = z;
else
y = successor(z);
if (y->left != NULL)
x = y->left;
else
x = y->right;
if (x != NULL)
x->parent = y->parent;
if (y->parent == NULL)
tree = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
if (y != z)
z->key = y->key;
return y;
}
/*
* 刪除結點(z),並返回被刪除的結點
*
* 參數說明:
* tree 二叉樹的根結點
* z 刪除的結點
*/
template <class T>
void BSTree<T>::remove(T key)
{
BSTNode<T> *z, *node;
if ((z = search(mRoot, key)) != NULL)
if ( (node = remove(mRoot, z)) != NULL)
delete node;
}
/*
* 銷燬二叉樹
*/
template <class T>
void BSTree<T>::destroy(BSTNode<T>* &tree)
{
if (tree==NULL)
return ;
if (tree->left != NULL)
return destroy(tree->left);
if (tree->right != NULL)
return destroy(tree->right);
delete tree;
tree=NULL;
}
template <class T>
void BSTree<T>::destroy()
{
destroy(mRoot);
}
/*
* 打印"二叉查找樹"
*
* key -- 節點的鍵值
* direction -- 0,表示該節點是根節點;
* -1,表示該節點是它的父結點的左孩子;
* 1,表示該節點是它的父結點的右孩子。
*/
template <class T>
void BSTree<T>::print(BSTNode<T>* tree, T key, int direction)
{
if(tree != NULL)
{
if(direction==0) // tree是根節點
cout << setw(2) << tree->key << " is root" << endl;
else // tree是分支節點
cout << setw(2) << tree->key << " is " << setw(2) << key << "'s " << setw(12) << (direction==1?"right child" : "left child") << endl;
print(tree->left, tree->key, -1);
print(tree->right,tree->key, 1);
}
}
template <class T>
void BSTree<T>::print()
{
if (mRoot != NULL)
print(mRoot, mRoot->key, 0);
}
#endif
判斷一棵二叉樹是否爲BSTree
限定了子樹中節點值的範圍,從而每個節點只需訪問一次。節點值的初始範圍可限定爲INT_MIN以及INT_MAX。
//判斷是否爲BST
bool isBST(Node* node)
{
return(isBSTUtil(node, INT_MIN, INT_MAX));
}
//如果是一顆二叉查找樹,且值範圍在[min,max],則返回true
bool isBSTUtil(Node * node , int min , int max )
{
//空樹也是BST
if ( node == NULL)
return true;
//如果節點值違反了最大/最小約束條件,則不是BST
if ( node->key < min || node->key > max)
return false;
//遞歸檢查子樹
return isBSTUtil( node->left, min, node->key) &&
isBSTUtil( node->right, node->key, max);
}
方法二:
1) 對樹進行中序遍歷,將結果保存在temp數組中。
3) 檢測temp數組中元素是否爲升序排列。如果是,則這棵樹爲BST.
時間複雜度: O(n)
該方法還可以進一步的優化,我們可以避免使用這個額外的數組。在中序遍歷時,可以保存前驅節點,如果當前節點小於前驅節點,則這棵樹不是BST.
//判斷是否爲BST
bool isBST(Node* root)
{
static Node *prev = NULL;
// 中序遍歷這棵樹,並保存前驅節點至prev中
if (root)
{
if (!isBST(root->left))
return false;
// 檢測節點值的合法性
if (prev != NULL && root->key <= prev->key)
return false;
prev = root;
//右子樹
return isBST(root->right);
}
return true;
}