说来惭愧,数据结构学了10年了,直到今天才弄明白这个平衡二叉树的代码实现(之前只是知道原理,现在也可以自己造轮子用C++实现了)。
平衡二叉树其实就是二叉树,它是二叉树的一种特殊结构,主要是为了提高查找效率
假如有1023个节点,那么最多只需要10次就能找到目标节点。
转换成平衡二叉树的左旋和右旋的实现,其实就是为了使树平衡,将这棵树做最少的改动。并且前提条件是插入节点之前,这颗树是平衡的,所以只有4种情况会导致树的不平衡
1)依次插入3,2,1 需要右旋
2)依次插入1,2,3 需要左旋
3)依次插入1,3,2 需要先右旋再左旋
4)依次插入3,1,2 需要先左旋再右旋
以上4种情况都会导致根节点的不平衡,经过旋转以后,最终都会得到一颗以2为根节点的平衡的二叉树
#include <iostream>
using namespace std;
//树上的节点 我们只用一个value来存值 可以自行扩展存储其他数据
class TreeNode {
public:
int _value;
int _balance; //平衡因子 0表示左右平衡 左边深度减右边的深度
TreeNode *_lc;
TreeNode *_rc;
TreeNode()
{
_value = 0;
_lc = NULL;
_rc = NULL;
}
};
//平衡二叉树
class AVLTree {
public:
//每棵树都有一个根节点
TreeNode * _root;
//向一个树中插入一个元素
TreeNode* insertValue(TreeNode * &node,int value)
{
if (node == NULL)
{
//如果节点为空,直接创建一个节点
node = new TreeNode();
node->_value = value;
node->_balance = 0;
}
//如果当前插入的值比根节点大
else if (value > node->_value )
{
//如果有右子树 , 往右子树里面插入
node->_rc = insertValue(node->_rc, value);
if(getTreeDepth(node->_rc)-getTreeDepth(node->_lc)==2)//插入后失衡
{
if( value > node->_rc->_value )
{
// N NR
// \ / \
// NR => N NRR
// \
// NRR
node = LeftRotate(node);
}
else
{
// N N NRL
// \ \ / \
// NR => NRL => N NR
// / \
// NRL
node = RightLeftRotate(node);
}
}
}
//如果有左子树 , 往左子树里面插入
else
{
node->_lc = insertValue(node->_lc, value);
if(getTreeDepth(node->_lc)-getTreeDepth(node->_rc)==2)//插入后失衡
{
if( value > node->_lc->_value )
{
// N N NLR
// / / / \
// NL => NLR => NL N
// \ /
// NLR NL
node=LeftRightRotate(node);//左右的旋转
}
else
{
// N NL
// / / \
// NL => NLL N
// /
// NLL
node=RightRotate(node);//右旋
}
}
}
//更新节点的高度
_root->_balance = getTreeDepth(_root->_lc ) - getTreeDepth(_root->_rc );
return node;
}
//右旋一棵二叉树
TreeNode * RightRotate(TreeNode *&node)
{
int balanceFactor = getTreeDepth(node->_lc) - getTreeDepth(node->_rc);
if (balanceFactor != 2)
{
cout << "不符合右旋条件" << endl;
return node;
}
//旋转前 二叉树是平衡的
// N NL
// / / \
// NL => NLL N
// /
// NLL
// N NL
// / \ / \
// NL NR => NLL N
// / \ \ / \
// NLL NLR NLLR NLR NR
// \
// NLLR
TreeNode *NL = node->_lc;
node->_lc = NL->_rc;
NL->_rc = node;
return NL;
}
//左旋一棵二叉树
TreeNode * LeftRotate(TreeNode *&node)
{
int balanceFactor = getTreeDepth(node->_lc) - getTreeDepth(node->_rc);
if (balanceFactor != -2)
{
cout << "不符合左旋条件" << endl;
return node;
}
// N NR
// \ / \
// NR => N NRR
// \
// NRR
// N NR
// / \ / \
// NL NR => N NRR
// / \ / \ \
// NRL NRR NL NRL NRRR
// \
// NRRR
TreeNode *NR = node->_rc;
node->_rc = NR->_lc;
NR->_lc = node;
return NR;
}
//先右旋再左旋
TreeNode * RightLeftRotate(TreeNode *&node)
{
// N N NRL
// \ \ / \
// NR => NRL => N NR
// / \
// NRL NR
RightRotate(node->_rc);
return LeftRotate(node);
}
//先右旋再左旋
TreeNode * LeftRightRotate(TreeNode *&node)
{
// N N NLR
// / / / \
// NL => NLR => NL N
// \ /
// NLR NL
LeftRotate(node->_lc);
return RightRotate(node);
}
//获取二叉树的深度(左右子树的最大深度+1)
int getTreeDepth(TreeNode * root)
{
if (root == NULL)
{
return 0;
}
int leftTreeDepth = getTreeDepth(root->_lc);
int rightTreeDepth = getTreeDepth(root->_rc);
return leftTreeDepth > rightTreeDepth ? leftTreeDepth + 1 : rightTreeDepth + 1;
}
//获取最大节点(一直向右边找节点)
TreeNode * getMaxNode(TreeNode * root)
{
if (root!= NULL )
{
if (root->_rc != NULL)
{
return getMaxNode(root->_rc);
}
else
{
return root;
}
}
else
{
return NULL;
}
}
//获取最小节点(一直向左边找节点)
TreeNode * getMinNode(TreeNode * root)
{
if (root!= NULL )
{
if (root->_lc != NULL)
{
return getMinNode(root->_lc);
}
else
{
return root;
}
}
else
{
return NULL;
}
}
//中序遍历
void printTreeMid(TreeNode * root)
{
if (root!= NULL) {
printTreeMid(root->_lc);
std::cout << root->_value << "," ;
printTreeMid(root->_rc);
}
}
//前序遍历
void printTreeFront(TreeNode * root)
{
if (root != NULL) {
std::cout << root->_value << "," ;
printTreeFront(root->_lc);
printTreeFront(root->_rc);
}
}
//后序遍历
void printTreeBack(TreeNode * root)
{
if (root != NULL) {
printTreeBack(root->_lc);
printTreeBack(root->_rc);
std::cout << root->_value << "," ;
}
}
};
void testFun(TreeNode * node)
{
}
int main()
{
// 创建一个平衡二叉树
AVLTree * avlTree = new AVLTree();
for (int i = 1 ; i < 1024 ; i++)
{
avlTree->insertValue(avlTree->_root, i);
}
cout << "树的深度为 :" << avlTree->getTreeDepth(avlTree->_root) <<endl;
avlTree->printTreeFront(avlTree->_root);
cout<<endl;
}
运行:
树的深度为 :10
可以看到树的深度为10,如果按照上一节的插入操作不做平衡处理的话,这棵树的深度达到最坏的情况1023,也就会导致1023这个节点在查找的时候会找1023次才能找到
特殊的:当平衡二叉树是一颗满二叉树的时候,根节点刚好是最中间的那个值