在数据结构中,有一个奇葩的东西,说它奇葩,那是由于它重要,这就是树。而在树中,二叉树又是当中的贵族。二叉树的一个重要应用是它们在查找中的应用,因而就有了二叉查找树。 使二叉树成为一颗二叉查找树,须要知足如下两点:面试
如下是对于二叉查找树的基本操做定义类,而后慢慢分析是如何实现它们的。算法
template<class T>数据结构
class BinarySearchTree{public:// 构造函数,初始化root值BinarySearchTree() : root(NULL){}// 析构函数,默认实现~BinarySearchTree() {}// 查找最小值,并返回最小值const T &findMin() const;// 查找最大值,并返回最大值const T &findMax() const;// 判断二叉树中是否包含指定值的元素bool contains(const T &x) const;// 判断二叉查找树是否为空bool isEmpty() const { return root ? false : true; }// 打印二叉查找树的值void printTree() const;// 向二叉查找树中插入指定值void insert(const T &x);// 删除二叉查找树中指定的值void remove(const T &x);// 清空整个二叉查找树void makeEmpty() const;private:// 指向根节点BinaryNode<T> *root;void insert(const T &x, BinaryNode<T> *&t) const;void remove(const T &x, BinaryNode<T> *&t) const;BinaryNode<T> *findMin(BinaryNode<T> *t) const;BinaryNode<T> *findMax(BinaryNode<T> *t) const;bool contains(const T &x, BinaryNode<T> *t) const;void printTree(BinaryNode<T> *t) const;void makeEmpty(BinaryNode<T> *&t) const;};
根据二叉查找树的性质:函数
咱们能够从root
节点开始:学习
NULL
为止,这样就能够找到最小值了;NULL
为止,这样就能够找到最大值了。以下图所示:spa
在程序中实现时,有两种方法:code
对于finMin
的实现,我这里使用递归的方式,代码参考以下:blog
BinaryNode<T> *BinarySearchTree<T>::findMin(BinaryNode<T> *t) const递归
{if (t == NULL){return NULL;}else if (t->left == NULL){return t;}else{return findMin(t->left);}}
在findMin()
的内部调用findMin(BinaryNode<T> *t)
,这样就防止了客户端知道了root
根节点的信息。上面使用递归的方式实现了查找最小值,下面使用循环的方式来实现findMax
。内存
template<class T>
BinaryNode<T> *BinarySearchTree<T>::findMax(BinaryNode<T> *t) const{if (t == NULL){return NULL;}while (t->right){t = t->right;}return t;}
在不少面试的场合下,面试官通常都是让写出非递归的版本;而在对树进行的各类操做,不少时候都是使用的递归实现的,因此,在平时学习时,在理解递归版本的前提下,须要关心一下对应的非递归版本。
contains
用来判断二叉查找树是否包含指定的元素。代码实现以下:
template<class T>
bool BinarySearchTree<T>::contains(const T &x, BinaryNode<T> *t) const{if (t == NULL){return false;}else if (x > t->element){return contains(x, t->right);}else if (x < t->element){return contains(x, t->left);}else{return true;}}
算法规则以下:
insert
函数用来向儿茶查找树中插入新的元素,算法处理以下:
代码实现以下:
template<class T>
void BinarySearchTree<T>::insert(const T &x, BinaryNode<T> *&t) const{if (t == NULL){t = new BinaryNode<T>(x, NULL, NULL);}else if (x < t->element){insert(x, t->left);}else if (x > t->element){insert(x, t->right);}}
remove
函数用来删除二叉查找树中指定的元素值,这个处理起来比较麻烦。在删除子节点时,须要分如下几种状况进行考虑(结合下图进行说明): 以下图所示:
对于状况1,直接删除对应的节点便可;实现起来时比较简单的;
对于状况2,直接删除对应的节点,而后用其子节点占据删除掉的位置;
对于状况3,是比较复杂的。首先在须要被删除节点的右子树中找到最小值节点,而后使用该最小值替换须要删除节点的值,而后在右子树中删除该最小值节点。
假如如今须要删除包含值23的节点,步骤以下图所示:
代码实现以下:
template<class T>
void BinarySearchTree<T>::remove(const T &x, BinaryNode<T> *&t) const{if (t == NULL){return;}if (x < t->element){remove(x, t->left);}else if (x > t->element){remove(x, t->right);}else if (t->left != NULL && t->right != NULL){// 拥有两个子节点t->element = findMin(t->right)->element;remove(t->element, t->right);}else if (t->left == NULL && t->right == NULL){// 没有子节点,直接干掉delete t;t = NULL;}else if (t->left == NULL || t->right == NULL){// 拥有一个子节点BinaryNode *pTemp = t;t = (t->left != NULL) ? t->left : t->right;delete pTemp;}}
makeEmpty
函数用来释放整个二叉查找树占用的内存空间,同理,也是使用的递归的方式来实现的。具体代码请下载文中最后提供的源码。
这篇文章对数据结构中很是重要的二叉查找树进行了详细的总结,虽然二叉查找树很是重要,可是理解起来仍是很是容易的,主要是须要掌握对递归的理解。若是对递归有很是扎实的理解,那么对于树的一些操做,那都是很是好把握的,而理解二叉查找树又是后续的AVL平衡树和红黑树的基础,但愿这篇文章对你们有帮助。