搜索树---排序二叉树和平衡二叉树的C++实现

1. 理解:

1.1 排序二叉树

  首先需要介绍的是数据结构,这里使用了模板来适应不用的数据类型:

  template <typename ElementType>

  class BSTreeNode{

  
public:

  
ElementType element;/*二叉树中存放的数据*/

  
BSTreeNode<ElementType> *parent;/*节点的父亲节点*/

  
BSTreeNode<ElementType> *lchild,*rchild;/*节点的左右孩子*/

  };

  这个是节点的数据结构,较为常见。对数据和操作进行封装,得到了下面的数据结构:

  template <typename ElementType>

  class BSTree {

  
public:

  …;

  
protected:

  
BSTreeNode<ElementType> *rootNode;/*数据节点的根节点*/

  
ElementType deletedNodeElement;/*实际删除节点的数据*/

  …;

  private:

  …;

  };

  其次介绍其操作:

  搜索树是为动态查找服务的,所谓动态查找就是在查找的过程当中可以动态增加整个树的内容。所以,基本的操作包括了查找,增加和删除,以及为调试用的遍历操作,如下代码所示:

  virtual BSTreeNode<ElementType> *Insert(ElementType element);

  virtual BSTreeNode<ElementType> *Delete(ElementType element);

  virtual BSTreeNode<ElementType> *Search(ElementType element);

  插入操作和删除操作返回的数据表示插入和实际删除节点的父亲节点,该节点信息可以被后面的平衡二叉树利用。插入操作非常简单,如果当前节点数据大于插入节点的数据则插入到当前节点的左子树中,否则插入到右子树中。注意的是删除中的“实际删除节点”,因为在删除过程中,我们采取的策略时,如果需要删除的节点有左子树,则我们会拿左子树中的最大孩子的数据来替换删除节点的数据,然后删除该最大孩子,而这个最大孩子就是我们“实际删除”的节点。

  查找操作查找指定数据的节点,给类型必须执行“==”运算符。若查找到执行数据,则返回第一个包含该数据的节点的指针;否则返回空指针。该函数对所有的排序二叉树都是适用的,因此下面的平衡二叉树不需要重新实现,只需要修改返回值类型。

  其他遍历操作更为普通,不做介绍。

1.2 平衡二叉树

  还是先介绍数据结构:

  节点数据类型和树的结构采用了继承的方式,这比较符合他们之间的关系。节点数据成员多了一个成员,就是平衡因子,所谓平衡因子就是节点的左子树的高度减去右子树的高度。

  template <typename ElementType>

  class AVLTreeNode : public BSTreeNode<ElementType>{

  
public:

  
int bf;

  };

  树的封装类没有添加什么数据成员,只是对不同的操作进行了重写:

  template <typename ElementType>

  class AVLTree : public BSTree<ElementType> {

  …;

  };

  下面是这篇文章的重点,就是插入和删除操作,以及随之带来的平衡化操作,主要的还是参考网上大神的博客,这里只是记录下我的理解:

  插入时,先按照排序二叉树的插入算法进行插入,新插入的节点一定是叶子节点,所以不必考虑该新节点的平衡化问题,从其父亲节点开始考虑。如果插入在父亲节点的左边,则父亲节点平衡因子加上1, 否则减去1,表示插入在右边。这里一定有人会问,插入一个新节点,它的父亲节点的平衡因子不一定会改变吧?这里的答案是,当父亲节点的平衡因子变为0时,就不会向上继续调整树的结构了。意思就是说,当插入节点不改变以父节点为根的子树时,就不会向上继续调整。

  删除的思路和插入类似:返回的是“实际删除”节点的父亲节点,如果删除的节点的数据大于父亲节点的数据,父亲节点平衡因子加1,否则减去1(等于包括在内,这个对理解很有帮助)。当父亲节点的深度值不为0时,就不会继续向上调整了。原因是,父亲节点深度值不为0, 表示是从0变到了非0, 那么则表示该子树的深度没有变化,因此不需要向上调整。

      平衡华操作和书中介绍的经典是一样的,就是分为四种:LL,LR,RL, RR。
  然后是平衡因子的调整,我记录下大神的想法,就是在旋转时进行调整,调整的依据是拿一个的子树的高度作为比较的依据,该子树就是图中标记可能为NULL的子树。

《搜索树---排序二叉树和平衡二叉树的C++实现》 (大神说是涉及三个节点:第三个节点就是那么NULL的节点,就是可能为NULL的节点)   

  对于左旋——p 的右子树从t 变成了t 的左子树,显然p 的右子树高度至少减1 。t 的bf 代表了原来的t 左右子树的高度差,如果t->bf<0 ,则p 的右子树的高度还要减少|t->bf| 。t 的左子树在原来的左子树上面又多了一个p ,显然左子树高度至少加1 。在p 的平衡因子修改完之后,如果p->bf>0 那么t 的左子树高度还要增加p->bf 。

  综合起来就是++(p->bf) -= t->bf < 0 ? t->bf : 0; ++(t->bf) += p->bf > 0 ? p->bf : 0;

  对于右旋同理–(p->bf) -= t->bf > 0 ? t->bf : 0; –(t->bf) += p->bf < 0 ? p->bf : 0;

  差不多就是这些,还有点语言上需要注意的地方,开始没有理解c_root的用法,后来才知道这些是为了引用考虑的,因为这里传的是一个引用,传引用的目的就是能够改变传进去的值。还有就是在模板类的继承中,如果使用父类的数据成员不能直接使用,而要加上一个this->来引用(还有一种通过using 声明的方式)。

2. 代码:

//BSTree.h
#ifndef _BSTREE_H
#define _BSTREE_H
template <typename ElementType>
class BSTreeNode{
		public:
				ElementType element;
				BSTreeNode<ElementType> *parent;
				BSTreeNode<ElementType> *lchild,*rchild;
};
template <typename ElementType>
class BSTree {
		public:
				BSTree();
				virtual ~BSTree();
				virtual BSTreeNode<ElementType> *Insert(ElementType element);
				virtual BSTreeNode<ElementType> *Delete(ElementType element);
				virtual BSTreeNode<ElementType> *Search(ElementType element);
				virtual void InOrderTraverse(void);
				virtual void PreOrderTraverse(void);
		protected:
				virtual BSTreeNode<ElementType> *_newNodeImpl(void);
				BSTreeNode<ElementType> *rootNode;
				ElementType deletedNodeElement;
		private:
				void _clear(BSTreeNode<ElementType> *root);
				BSTreeNode<ElementType>* _insert(BSTreeNode<ElementType> *parent, BSTreeNode<ElementType> **root, ElementType element);
				BSTreeNode<ElementType>* _search(BSTreeNode<ElementType> *root, ElementType element);
				void _inOrderTraverse(BSTreeNode<ElementType> *root);
				void _preOrderTraverse(BSTreeNode<ElementType> *root);
};
#include "BSTree.cpp"
#endif
//BSTree.cpp
#include "BSTree.h"
#include <iostream>
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
BSTree<ElementType>::BSTree()
{
	rootNode = 0;
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
BSTree<ElementType>::~BSTree()
{
	_clear(rootNode);
	rootNode = 0;
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
void BSTree<ElementType>::_clear(BSTreeNode<ElementType> *root)
{
	if(root == NULL) return;
	_clear(root->lchild);
	_clear(root->rchild);
	delete root;
}
//------------------------------------------------------------------------------------------------------------------------------------------
/*
 * return parent node of the inserted item
 */
template <typename ElementType>
BSTreeNode<ElementType> *BSTree<ElementType>::Insert(ElementType element)
{
	return _insert(NULL, &rootNode, element);
}
//------------------------------------------------------------------------------------------------------------------------------------------
/*
 * return the parent node of the turely deleted node
 * return NULL means not find the node to find
 */
template <typename ElementType>
BSTreeNode<ElementType> *BSTree<ElementType>::Delete(ElementType element)
{
	BSTreeNode<ElementType> *p = rootNode, *q, *parent;

	while(p && p->element != element){
		if(p->element < element) p = p->rchild;
		else p = p->lchild;
	}
	if(p == NULL) return NULL;/*can not find*/
	if(p->lchild == NULL){
		if(p->parent == NULL){/*p is the root node*/
			rootNode = p->rchild;
			rootNode->parent = NULL;
		}
		else if(p->parent->lchild == p){
			p->parent->lchild = p->rchild;
			if(p->rchild) p->rchild->parent = p->parent;
		}else{
			p->parent->rchild = p->rchild;
			if(p->rchild) p->rchild->parent = p->parent;
		}
		deletedNodeElement = element;
		parent =  p->parent;
		delete p;
		return parent;
	}else{
		q = p->lchild;
		while(q->rchild) q = q->rchild;

		if(q == p->lchild){
			p->lchild = p->lchild->lchild;
			if(p->lchild) p->lchild->parent = p;
			parent = p;
		}else{
			q->parent->rchild = q->lchild;
			if(q->lchild) q->lchild->parent = q->parent;
			parent = q->parent;
		}
		p->element = q->element;
		deletedNodeElement = q->element;
		delete q;
		return parent;
	}
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
BSTreeNode<ElementType> *BSTree<ElementType>::Search(ElementType element)
{
	return _search(rootNode, element);
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
void BSTree<ElementType>::InOrderTraverse(void)
{
	_inOrderTraverse(rootNode);
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
void BSTree<ElementType>::PreOrderTraverse(void)
{
	_preOrderTraverse(rootNode);
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
BSTreeNode<ElementType>* BSTree<ElementType>::_insert(BSTreeNode<ElementType> *parent,BSTreeNode<ElementType> **root, ElementType element)
{
	if(*root == 0){
		BSTreeNode<ElementType> *pElement = _newNodeImpl();
		pElement->element = element;
		pElement->parent = parent;
		(*root) = pElement;
		return parent;
	}else if(element < (*root)->element) return _insert(*root, &((*root)->lchild),element);
	else return _insert(*root, &((*root)->rchild),element);
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
BSTreeNode<ElementType>* BSTree<ElementType>::_search(BSTreeNode<ElementType> *root, ElementType element)
{
	if(root==0) return 0;
	else if(root->element == element) return root;
	else if(element < root->element) return _search(root->lchild, element);
	else return _search(root->rchild, element);
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
void BSTree<ElementType>::_inOrderTraverse(BSTreeNode<ElementType> *root)
{
	if(root == 0) return;
	_inOrderTraverse(root->lchild);
	std::cout << root->element << std::endl;
	_inOrderTraverse(root->rchild);
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
void BSTree<ElementType>::_preOrderTraverse(BSTreeNode<ElementType> *root)
{
	if(root == 0) return;
	std::cout << root->element << std::endl;
	_preOrderTraverse(root->lchild);
	_preOrderTraverse(root->rchild);
}
//------------------------------------------------------------------------------------------------------------------------------------------
template <typename ElementType>
BSTreeNode<ElementType> *BSTree<ElementType>::_newNodeImpl(void)
{
	BSTreeNode<ElementType> *pNode = new  BSTreeNode<ElementType>();
	pNode->parent = pNode->lchild = pNode->rchild = NULL;
	return pNode;
}

//AVLTree.h
#ifndef _AVLTREE_H
#define _AVLTREE_H
#include "BSTree.h"

template <typename ElementType>
class AVLTreeNode : public BSTreeNode<ElementType>{
		public:
				int bf;
};
 
template <typename ElementType>
class AVLTree : public BSTree<ElementType> {
		public:
				AVLTree();
				virtual ~AVLTree();
				virtual AVLTreeNode<ElementType> *Insert(ElementType element);
				virtual AVLTreeNode<ElementType> *Delete(ElementType element);
				virtual AVLTreeNode<ElementType> *Search(ElementType element);
		protected:
				AVLTreeNode<ElementType> *_newNodeImpl(void);
};

#include "AVLTree.cpp"
#endif

//AVLTree.cpp
#include "AVLTree.h"
//---------------------------------------------------------------------------------
template <typename ElementType>
void _leftBalance(AVLTreeNode<ElementType>* &p)
{
	AVLTreeNode<ElementType> *pRightChild = (AVLTreeNode<ElementType> *)p->rchild;
	if(pRightChild->bf == 1){
		_rightRotate(pRightChild);
		p->rchild = (BSTreeNode<ElementType> *)pRightChild;
	}
	_leftRotate(p);
}
//---------------------------------------------------------------------------------
template <typename ElementType>
void _rightBalance(AVLTreeNode<ElementType>* &p)
{
	AVLTreeNode<ElementType> *pLeftChild = (AVLTreeNode<ElementType> *)p->lchild;
	if(pLeftChild->bf == -1){
		_leftRotate(pLeftChild);
		p->lchild = (BSTreeNode<ElementType> *)pLeftChild;
	}
	_rightRotate(p);
}
//---------------------------------------------------------------------------------
template <typename ElementType>
void _leftRotate(AVLTreeNode<ElementType>* &p)
{
	AVLTreeNode<ElementType> *t = (AVLTreeNode<ElementType>*)p->rchild;
	t->parent = p->parent;
	p->parent = t;
	p->rchild = t->lchild;
	if(t->lchild) t->lchild->parent = p;
	t->lchild = p;
	++(p->bf) -= t->bf < 0 ? t->bf : 0;
	++(t->bf) += p->bf > 0 ? p->bf : 0;
	p = t;
}
//---------------------------------------------------------------------------------
template <typename ElementType>
void _rightRotate(AVLTreeNode<ElementType>* &p)
{
	AVLTreeNode<ElementType> *t = (AVLTreeNode<ElementType>*)p->lchild;
	t->parent = p->parent;
	p->parent = t;
	p->lchild = t->rchild;
	if(t->rchild) t->rchild->parent = p;
	t->rchild = p;
	--(p->bf) -= t->bf > 0 ? t->bf : 0;
	--(t->bf) += p->bf < 0 ? p->bf : 0;
	p = t;
}
//---------------------------------------------------------------------------------
template <typename ElementType>
AVLTree<ElementType>::AVLTree():
	BSTree<ElementType>()
{
}
//---------------------------------------------------------------------------------
template <typename ElementType>
AVLTree<ElementType>::~AVLTree()
{
}
//---------------------------------------------------------------------------------
#define  c_p pParentNode->parent 
#define  c_root (c_p?((c_p->lchild == pParentNode)?c_p->lchild:c_p->rchild):this->rootNode)
template <typename ElementType>
AVLTreeNode<ElementType> *AVLTree<ElementType>::Insert(ElementType element)
{
	AVLTreeNode<ElementType> *pParentNode = (AVLTreeNode<ElementType>*)BSTree<ElementType>::Insert(element);
	const ElementType *pElement = &element;

	if(pParentNode == NULL) return NULL;
	while(pParentNode){
		pParentNode->bf += (pParentNode->element > *pElement) ? 1:-1;
		if(pParentNode->bf == -2) _leftBalance((AVLTreeNode<ElementType> *&)c_root);
		else if(pParentNode->bf == 2) _rightBalance((AVLTreeNode<ElementType> *&)c_root);
		if(pParentNode->bf == 0) break;/*insert and rotate end*/
		pElement = &(pParentNode->element);
		pParentNode = (AVLTreeNode<ElementType>*)pParentNode->parent;
	}
	return pParentNode;
}
//---------------------------------------------------------------------------------
template <typename ElementType>
AVLTreeNode<ElementType> *AVLTree<ElementType>::Delete(ElementType element)
{
	AVLTreeNode<ElementType> *pParentNode = (AVLTreeNode<ElementType>*)BSTree<ElementType>::Delete(element);
	const ElementType *pElement = &this->deletedNodeElement;

	while(pParentNode){
		pParentNode->bf += (pParentNode->element < *pElement) ? 1 : -1;
		if(pParentNode->bf == -2) _leftBalance((AVLTreeNode<ElementType> *&)c_root);
		else if(pParentNode->bf == 2) _rightBalance((AVLTreeNode<ElementType> *&)c_root);
		if(pParentNode->bf) break;
		pElement = &(pParentNode->element);
		pParentNode = (AVLTreeNode<ElementType>*)pParentNode->parent;
	}
	return pParentNode;
}
//---------------------------------------------------------------------------------
template <typename ElementType>
AVLTreeNode<ElementType> *AVLTree<ElementType>::Search(ElementType element)
{
	return (AVLTreeNode<ElementType>*)BSTree<ElementType>::Search(element);
}
//---------------------------------------------------------------------------------
template <typename ElementType>
AVLTreeNode<ElementType> *AVLTree<ElementType>::_newNodeImpl(void)
{
	AVLTreeNode<ElementType> *pNode = new AVLTreeNode<ElementType>();
	pNode->bf = 0;
	pNode->parent = pNode->lchild = pNode->rchild = NULL;
	return pNode;
}

//测试:main.cpp
#include "AVLTree.h"
#include <string>
#include <iostream>

int main()
{
	AVLTree<int> itree;

	std::cout << "Insert 0 9 4 6 -4 -2 -1\n";
	itree.Insert(0);
	itree.Insert(9);
	itree.Insert(4);
	itree.Insert(6);
	itree.Insert(-4);
	itree.Insert(-2);
	itree.Insert(-1);
	
	std::cout << "InOrder traverse:\n";
	itree.InOrderTraverse();
	std::cout << "PreOrder traverse:\n";
	itree.PreOrderTraverse();

	std::cout << "Deleted 9:\n";
	itree.Delete(9);
	std::cout << "InOrder:\n";
	itree.InOrderTraverse();
	std::cout << "PreOrder:\n";
	itree.PreOrderTraverse();

	std::cout << "Deleted 4:\n";
	itree.Delete(4);
	std::cout << "InOrder:\n";
	itree.InOrderTraverse();
	std::cout << "PreOrder:\n";
	itree.PreOrderTraverse();

	std::cout << "Deleted 0:\n";
	itree.Delete(0);
	std::cout << "InOrder:\n";
	itree.InOrderTraverse();
	std::cout << "PreOrder:\n";
	itree.PreOrderTraverse();

	std::cout << "Deleted -2:\n";
	itree.Delete(-2);
	std::cout << "InOrder:\n";
	itree.InOrderTraverse();
	std::cout << "PreOrder:\n";
	itree.PreOrderTraverse();

	std::cout << "Deleted 6:\n";
	itree.Delete(6);
	std::cout << "InOrder:\n";
	itree.InOrderTraverse();
	std::cout << "PreOrder:\n";
	itree.PreOrderTraverse();
//-----------------------------------------------------------------------------------------
	AVLTree<std::string> strTree;

	std::cout << "Inserted 5 string: rensehngqiang shibojun lijin wangzaibing zhaogang\n";
	strTree.Insert("renshengqiang");
	strTree.Insert("shibojun");
	strTree.Insert("lijin");
	strTree.Insert("wangzaibing");
	strTree.Insert("zhaogang");

	std::cout << "InOrder traverse:\n";
	strTree.InOrderTraverse();
	std::cout << "PreOrder traverse:\n";
	strTree.PreOrderTraverse();

	std::cout << "Look for lijin:\n";
	AVLTreeNode<std::string> *pNode = strTree.Search("lijin");
	if(pNode != 0) std::cout << pNode->element << std::endl;

	std::cout << "Look for huangliangyu\n";
	pNode = strTree.Search("huangliangyu");
	if(pNode != 0) std::cout << pNode->element << std::endl;

	return 0;
}

3. 参考:

主要参考:http://blog.csdn.net/timercrack/article/details/1924767

原始大神:http://blog.csdn.net/happycock/article/details/20874

偷懒者下载地址:https://github.com/renshengqiang/Algorithm/tree/master/SearchTree

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/rsqiang/article/details/8657346
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞