"《算法导论》之‘树’":AVL树
本文关于AVL树的介绍引自博文AVL树(二)之 C++的实现,与二叉查找树相同的部分则不作介绍直接引用;代码实现是在本文的基础上自己实现且继承自上一篇博文二叉查找树。
1.AVL树的介绍
AVL树是高度平衡的而二叉树。它的特点是:AVL树中任何节点的两个子树的高度最大差别为1。

上面的两张图片,左边的是AVL树,它的任何节点的两个子树的高度差别都<=1;而右边的不是AVL树,因为7的两颗子树的高度相差为2(以2为根节点的树的高度是3,而以8为根节点的树的高度是1)。
2.节点的旋转
如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。这种失去平衡的可以概括为4种姿态:LL(左左),LR(左右),RR(右右)和RL(右左)。下面给出它们的示意图:

上图中的4棵树都是"失去平衡的AVL树",从左往右的情况依次是:LL、LR、RL、RR。除了上面的情况之外,还有其它的失去平衡的AVL树,如下图:

上面的两张图都是为了便于理解,而列举的关于"失去平衡的AVL树"的例子。总的来说,AVL树失去平衡时的情况一定是LL、LR、RL、RR这4种之一,它们都由各自的定义:
(1) LL:LeftLeft,也称为"左左"。插入或删除一个节点后,根节点的左子树的左子树还有非空子节点,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。
例如,在上面LL情况中,由于"根节点(8)的左子树(4)的左子树(2)还有非空子节点",而"根节点(8)的右子树(12)没有子节点";导致"根节点(8)的左子树(4)高度"比"根节点(8)的右子树(12)"高2。
(2) LR:LeftRight,也称为"左右"。插入或删除一个节点后,根节点的左子树的右子树还有非空子节点,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。
例如,在上面LR情况中,由于"根节点(8)的左子树(4)的左子树(6)还有非空子节点",而"根节点(8)的右子树(12)没有子节点";导致"根节点(8)的左子树(4)高度"比"根节点(8)的右子树(12)"高2。
(3) RL:RightLeft,称为"右左"。插入或删除一个节点后,根节点的右子树的左子树还有非空子节点,导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
例如,在上面RL情况中,由于"根节点(8)的右子树(12)的左子树(10)还有非空子节点",而"根节点(8)的左子树(4)没有子节点";导致"根节点(8)的右子树(12)高度"比"根节点(8)的左子树(4)"高2。
(4) RR:RightRight,称为"右右"。插入或删除一个节点后,根节点的右子树的右子树还有非空子节点,导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
例如,在上面RR情况中,由于"根节点(8)的右子树(12)的右子树(14)还有非空子节点",而"根节点(8)的左子树(4)没有子节点";导致"根节点(8)的右子树(12)高度"比"根节点(8)的左子树(4)"高2。
前面说过,如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。AVL失去平衡之后,可以通过旋转使其恢复平衡,下面分别介绍"LL(左左),LR(左右),RR(右右)和RL(右左)"这4种情况对应的旋转方法。
2.1 LL的旋转
LL失去平衡的情况,可以通过一次旋转让AVL树恢复平衡。如下图:

图中左边是旋转之前的树,右边是旋转之后的树。从中可以发现,旋转之后的树又变成了AVL树,而且该旋转只需要一次即可完成。
对于LL旋转,你可以这样理解为:LL旋转是围绕"失去平衡的AVL根节点"进行的,也就是节点k2;而且由于是LL情况,即左左情况,就用手抓着"左孩子,即k1"使劲摇。将k1变成根节点,k2变成k1的右子树,"k1的右子树"变成"k2的左子树"。
代码如下:
// LL:左左对应的情况(左单旋转)。
template<class T>
Node<T> * AVLTree<T>::leftLeftRotation(Node<T>* k2)
{
NodePointer k1 = NULL, k2ParentPtr = NULL; k1 = k2->left;
if (k2 != root)
{
k2ParentPtr = k2->parent;
if (k2ParentPtr->left == k2)
{
k2ParentPtr->left = k1;
}
else
{
k2ParentPtr->right = k1;
}
k1->parent = k2ParentPtr;
}
else
{
k1->parent = NULL;
} k2->left = k1->right;
k1->right = k2;
k2->parent = k1; if (k2->left != NULL)
{
NodePointer tmpK2Left = k2->left;
tmpK2Left->parent = k2;
} return k1;
}
leftLeftRotation
2.2 RR的旋转
理解了LL之后,RR就相当容易理解了。RR是与LL对称的情况!RR恢复平衡的旋转方法如下:

图中左边是旋转之前的树,右边是旋转之后的树。RR旋转也只需要一次即可完成。
代码如下:
// RR:右右对应的情况(右单旋转)。
template<class T>
Node<T> * AVLTree<T>::rightRightRotation(Node<T>* k1)
{
NodePointer k2 = NULL, k1ParentPtr = NULL; k2 = k1->right;
if (k1 != root)
{
k1ParentPtr = k1->parent;
if (k1ParentPtr->left == k1)
{
k1ParentPtr->left = k2;
}
else
{
k1ParentPtr->right = k2;
}
k2->parent = k1ParentPtr;
}
else
{
k2->parent = NULL;
} k1->right = k2->left;
k2->left = k1;
k1->parent = k2; if (k1->right != NULL)
{
NodePointer tmpK1Right = k1->right;
tmpK1Right->parent = k1;
} return k2;
}
rightRightRotation
2.3 LR的旋转
LR失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡。如下图:

第一次旋转是围绕"k1"进行的"RR旋转",第二次是围绕"k3"进行的"LL旋转"。
代码如下:
// LR:左右对应的情况(左双旋转)。
template<class T>
Node<T> * AVLTree<T>::leftRightRotation(Node<T>* k3)
{
k3->left = rightRightRotation(k3->left); return leftLeftRotation(k3);
}
leftRightRotation
2.4 RL的旋转
RL是与LR的对称情况!RL恢复平衡的旋转方法如下:

第一次旋转是围绕"k3"进行的"LL旋转",第二次是围绕"k1"进行的"RR旋转"。
代码如下:
// RL:右左对应的情况(右双旋转)。
template<class T>
Node<T> * AVLTree<T>::rightLeftRotation(Node<T>* k1)
{
k1->right = leftLeftRotation(k1->right); return rightRightRotation(k1);
}
rightLeftRotation
3.代码实现
这里定义的AVL树的类如下:
#include "BSTree.hpp" template<class T>
class AVLTree : public BSTree<T>
{
public:
AVLTree();
virtual ~AVLTree();
virtual bool addNode(T k, T val); // 覆盖BSTree中的addNode函数
virtual bool delNode(T k); // 覆盖BSTree中的delNode函数 private:
Node<T> * findImbalanceNode(NodePointer ptr);
// LL:左左对应的情况(左单旋转)。
Node<T> * leftLeftRotation(NodePointer k2);
// RR:右右对应的情况(右单旋转)。
Node<T> * rightRightRotation(NodePointer k1);
// LR:左右对应的情况(左双旋转)。
Node<T> * leftRightRotation(NodePointer k3);
// RL:右左对应的情况(右双旋转)。
Node<T> * rightLeftRotation(NodePointer k1); };
实现程序为:
#ifndef AVLTREE_H
#define AVLTREE_H #include "BSTree.hpp" template<class T>
class AVLTree : public BSTree<T>
{
public:
AVLTree();
virtual ~AVLTree();
virtual bool addNode(T k, T val); // 覆盖BSTree中的addNode函数
virtual bool delNode(T k); // 覆盖BSTree中的delNode函数 private:
Node<T> * findImbalanceNode(NodePointer ptr);
// LL:左左对应的情况(左单旋转)。
Node<T> * leftLeftRotation(NodePointer k2);
// RR:右右对应的情况(右单旋转)。
Node<T> * rightRightRotation(NodePointer k1);
// LR:左右对应的情况(左双旋转)。
Node<T> * leftRightRotation(NodePointer k3);
// RL:右左对应的情况(右双旋转)。
Node<T> * rightLeftRotation(NodePointer k1); }; template<class T>
AVLTree<T>::AVLTree()
{
root = NULL;
} template<class T>
AVLTree<T>::~AVLTree()
{
destroy();
root = NULL;
} template<class T>
bool AVLTree<T>::addNode(T k, T val)
{
bool isSuccess = BSTree<T>::addNode(k, val);
if (isSuccess)
{
NodePointer ptr = searchNode(k);
if (ptr != root)
{
NodePointer preParent = ptr->parent;
if (preParent != root)
{
NodePointer prePreParent = preParent->parent;
if (prePreParent == root)
{
if (getHeight(prePreParent->left) - getHeight(prePreParent->right) == )
{
if (ptr == preParent->left)
{
root = leftLeftRotation(prePreParent);
}
else
{
root = leftRightRotation(prePreParent);
}
}
else if (getHeight(prePreParent->right) - getHeight(prePreParent->left) == )
{
if (ptr == preParent->left)
{
root = rightLeftRotation(prePreParent);
}
else
{
root = rightRightRotation(prePreParent);
}
}
}
else
{
NodePointer prePrePreParent = prePreParent->parent;
if (getHeight(prePreParent->left) - getHeight(prePreParent->right) == )
{
if (prePreParent == prePrePreParent->left)
{
if (ptr == preParent->left)
{
prePrePreParent->left = leftLeftRotation(prePreParent);
}
else
{
prePrePreParent->left = leftRightRotation(prePreParent);
}
}
else
{
if (ptr == preParent->left)
{
prePrePreParent->right = leftLeftRotation(prePreParent);
}
else
{
prePrePreParent->right = leftRightRotation(prePreParent);
}
}
}
else if (getHeight(prePreParent->right) - getHeight(prePreParent->left) == )
{
if (prePreParent == prePrePreParent->left)
{
if (ptr == preParent->left)
{
prePrePreParent->left = rightLeftRotation(prePreParent);
}
else
{
prePrePreParent->left = rightRightRotation(prePreParent);
}
}
else
{
if (ptr == preParent->left)
{
prePrePreParent->right = rightLeftRotation(prePreParent);
}
else
{
prePrePreParent->right = rightRightRotation(prePreParent);
}
}
}
}
}
}
} return isSuccess;
} template<class T>
bool AVLTree<T>::delNode(T k)
{
bool isSuccess = true;
NodePointer ptr = searchNode(k);
NodePointer preParent = NULL;
if (ptr != NULL)
{
if (ptr == root)
{
BSTree<T>::delNode(k);
// only left left exist
if (getHeight(root->left) - getHeight(root->right) == )
{
root = leftLeftRotation(root);
}
}
else
{
NodePointer lNode = NULL, rNode = NULL;
preParent = ptr->parent;
if (preParent == root)
{
BSTree<T>::delNode(k);
lNode = root->left;
rNode = root->right;
if (getHeight(preParent->left) - getHeight(preParent->right) == )
{
if (getHeight(lNode->left) >= getHeight(lNode->right))
{
root = leftLeftRotation(preParent);
}
else
{
root = leftRightRotation(preParent);
}
}
else if (getHeight(preParent->right) - getHeight(preParent->left) == )
{
if (getHeight(rNode->right) >= getHeight(rNode->left))
{
root = rightRightRotation(preParent);
}
else
{
root = rightLeftRotation(preParent);
}
}
}
else
{
NodePointer prePreParent = NULL;
NodePointer lNode = NULL, rNode = NULL;
BSTree<T>::delNode(k);
// 这里需要递归查找不平衡点,以防止高层结点不平衡而低层结点平衡的情况
NodePointer tmpPtr = findImbalanceNode(preParent);
if (tmpPtr != NULL)
{
if (tmpPtr == root)
{
lNode = tmpPtr->left;
rNode = tmpPtr->right;
if (getHeight(tmpPtr->left) - getHeight(tmpPtr->right) == )
{
if (getHeight(lNode->left) >= getHeight(lNode->right))
{
root = leftLeftRotation(tmpPtr);
}
else
{
root = leftRightRotation(tmpPtr);
}
}
else if (getHeight(tmpPtr->right) - getHeight(tmpPtr->left) == )
{
if (getHeight(rNode->right) >= getHeight(rNode->left))
{
root = rightRightRotation(tmpPtr);
}
else
{
root = rightLeftRotation(tmpPtr);
}
}
}
else
{
prePreParent = tmpPtr->parent;
lNode = tmpPtr->left;
rNode = tmpPtr->right;
if (getHeight(tmpPtr->left) - getHeight(tmpPtr->right) == )
{
if (tmpPtr == prePreParent->left)
{
if (getHeight(lNode->left) >= getHeight(lNode->right))
{
prePreParent->left = leftLeftRotation(tmpPtr);
}
else
{
prePreParent->left = leftRightRotation(tmpPtr);
}
}
else
{
if (getHeight(lNode->left) >= getHeight(lNode->right))
{
prePreParent->right = leftLeftRotation(tmpPtr);
}
else
{
prePreParent->right = leftRightRotation(tmpPtr);
}
}
}
else if (getHeight(tmpPtr->right) - getHeight(tmpPtr->left) == )
{
if (tmpPtr == prePreParent->left)
{
if (getHeight(rNode->right) >= getHeight(rNode->left))
{
prePreParent->left = rightRightRotation(tmpPtr);
}
else
{
prePreParent->left = rightLeftRotation(tmpPtr);
}
}
else
{
if (getHeight(rNode->right) >= getHeight(rNode->left))
{
prePreParent->right = rightRightRotation(tmpPtr);
}
else
{
prePreParent->right = rightLeftRotation(tmpPtr);
}
}
}
}
}
}
}
}
else
{
isSuccess = false;
} return isSuccess;
} template<class T>
Node<T> * AVLTree<T>::findImbalanceNode(NodePointer ptr)
{
unsigned int lHeight = getHeight(ptr->left), rHeight = getHeight(ptr->right);
if (ptr == NULL)
{
return NULL;
}
else
{
if (lHeight - rHeight == || rHeight - lHeight == )
{
return ptr;
}
else
{
findImbalanceNode(ptr->parent);
}
}
} // LL:左左对应的情况(左单旋转)。
template<class T>
Node<T> * AVLTree<T>::leftLeftRotation(Node<T>* k2)
{
NodePointer k1 = NULL, k2ParentPtr = NULL; k1 = k2->left;
if (k2 != root)
{
k2ParentPtr = k2->parent;
if (k2ParentPtr->left == k2)
{
k2ParentPtr->left = k1;
}
else
{
k2ParentPtr->right = k1;
}
k1->parent = k2ParentPtr;
}
else
{
k1->parent = NULL;
} k2->left = k1->right;
k1->right = k2;
k2->parent = k1; if (k2->left != NULL)
{
NodePointer tmpK2Left = k2->left;
tmpK2Left->parent = k2;
} return k1;
} // RR:右右对应的情况(右单旋转)。
template<class T>
Node<T> * AVLTree<T>::rightRightRotation(Node<T>* k1)
{
NodePointer k2 = NULL, k1ParentPtr = NULL; k2 = k1->right;
if (k1 != root)
{
k1ParentPtr = k1->parent;
if (k1ParentPtr->left == k1)
{
k1ParentPtr->left = k2;
}
else
{
k1ParentPtr->right = k2;
}
k2->parent = k1ParentPtr;
}
else
{
k2->parent = NULL;
} k1->right = k2->left;
k2->left = k1;
k1->parent = k2; if (k1->right != NULL)
{
NodePointer tmpK1Right = k1->right;
tmpK1Right->parent = k1;
} return k2;
} // LR:左右对应的情况(左双旋转)。
template<class T>
Node<T> * AVLTree<T>::leftRightRotation(Node<T>* k3)
{
k3->left = rightRightRotation(k3->left); return leftLeftRotation(k3);
} // RL:右左对应的情况(右双旋转)。
template<class T>
Node<T> * AVLTree<T>::rightLeftRotation(Node<T>* k1)
{
k1->right = leftLeftRotation(k1->right); return rightRightRotation(k1);
} #endif
AVLTree.hpp
Boost单元测试程序为:
#include "stdafx.h"
#include "../AVLTree/AVLTree.hpp" struct AVLTree_Fixture
{
public:
AVLTree_Fixture()
{
testAVLTree = new AVLTree<int>();
}
~AVLTree_Fixture()
{
delete testAVLTree;
} AVLTree<int> * testAVLTree; }; BOOST_FIXTURE_TEST_SUITE(AVLTree_Test_Suite, AVLTree_Fixture) BOOST_AUTO_TEST_CASE( AVLTree_addNode_Test )
{
// add node next next to root and cause "left left/right" imbalance
// left left
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
testAVLTree->destroy();
// left right
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
testAVLTree->destroy();
// add node next next to root and cause "right left/right" imbalance
// right left
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
testAVLTree->destroy();
// right right
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
testAVLTree->destroy(); // add node not next next to root and cause "left left/right" imbalance
// left left
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
testAVLTree->destroy(); // left right
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
testAVLTree->destroy(); // add node next next to root and cause "right left/right" imbalance
// right left
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
testAVLTree->destroy(); // right right
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
BOOST_REQUIRE(testAVLTree->addNode(, ) == true);
testAVLTree->destroy(); } BOOST_AUTO_TEST_CASE(AVLTree_delNode_Test)
{
// delete root and cause "right right" imbalance --------------------------------
// actually, only "right right" imbalance will be caused at such condition ------
int key1[] = { , , , };
int value1[] = { , , , };
unsigned len1 = sizeof(key1) / sizeof(int);
testAVLTree->creatTree(key1, value1, len1);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // delete right node of 'root' and cause "left left/right" imbalance ----------------
// left left
int key31[] = { , , , , , , };
int value31[] = { , , , , , , };
unsigned len31 = sizeof(key31) / sizeof(int);
testAVLTree->creatTree(key31, value31, len31);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // left right
int key32[] = { , , , , , , };
int value32[] = { , , , , , , };
unsigned len32 = sizeof(key32) / sizeof(int);
testAVLTree->creatTree(key32, value32, len32);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // delete left node of 'root' and cause "right left/right" imbalance -------------------
// right left
int key21[] = { , , , , , , };
int value21[] = { , , , , , , };
unsigned len21 = sizeof(key21) / sizeof(int);
testAVLTree->creatTree(key21, value21, len21);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy();
// right right
int key22[] = { , , , , , , };
int value22[] = { , , , , , , };
unsigned len22 = sizeof(key22) / sizeof(int);
testAVLTree->creatTree(key22, value22, len22);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // delete node and cause "left left/right" imbalance -------------------
// left left -- imbalanced node is at root
int key41[] = { , , , , , , };
int value41[] = { , , , , , , };
unsigned len41 = sizeof(key41) / sizeof(int);
testAVLTree->creatTree(key41, value41, len41);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // left right -- imbalanced node is at root
int key42[] = { , , , , , , };
int value42[] = { , , , , , , };
unsigned len42 = sizeof(key42) / sizeof(int);
testAVLTree->creatTree(key42, value42, len42);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // left left -- imbalanced node is not at root
int key43[] = { , , , , , , , };
int value43[] = { , , , , , , , };
unsigned len43 = sizeof(key43) / sizeof(int);
testAVLTree->creatTree(key43, value43, len43);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // left right -- imbalanced node is not at root
int key44[] = { , , , , , , , };
int value44[] = { , , , , , , , };
unsigned len44 = sizeof(key44) / sizeof(int);
testAVLTree->creatTree(key44, value44, len44);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // delete node and cause "right left/right" imbalance -------------------
// right left -- imbalanced node is at root
int key51[] = { , , , , , , };
int value51[] = { , , , , , , };
unsigned len51 = sizeof(key51) / sizeof(int);
testAVLTree->creatTree(key51, value51, len51);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // right right -- imbalanced node is at root
int key52[] = { , , , , , , };
int value52[] = { , , , , , , };
unsigned len52 = sizeof(key52) / sizeof(int);
testAVLTree->creatTree(key52, value52, len52);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // right left -- imbalanced node is not at root
int key53[] = { , , , , , , , , };
int value53[] = { , , , , , , , , };
unsigned len53 = sizeof(key53) / sizeof(int);
testAVLTree->creatTree(key53, value53, len53);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); // right right -- imbalanced node is not at root
int key54[] = { , , , , , , , , };
int value54[] = { , , , , , , , , };
unsigned len54 = sizeof(key54) / sizeof(int);
testAVLTree->creatTree(key54, value54, len54);
BOOST_REQUIRE(testAVLTree->delNode() == true);
testAVLTree->destroy(); } //BOOST_AUTO_TEST_CASE(AVLTree_CopyConstructor_Test)
//{
// // leave blank
//}
//
//BOOST_AUTO_TEST_CASE(AVLTree_EqualOperator_Test)
//{
// // leave blank
//} BOOST_AUTO_TEST_SUITE_END()
AVTreeUnitTest
本篇博文的代码均托管到Github.
"《算法导论》之‘树’":AVL树的更多相关文章
- 算法导论:Trie字典树
1. 概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie一词来自retrieve,发音为/tr ...
- 树·AVL树/平衡二叉树
1.AVL树 带有平衡条件的二叉查找树,所以它必须满足条件: 1 是一棵二叉查找树 2 满足平衡条件 1.1 平衡条件: 1)严格的平衡条件:每个节点都必须有相同高度的左子树和右子树(过于严格而不被使 ...
- 04-树4. Root of AVL Tree-平衡查找树AVL树的实现
对于一棵普通的二叉查找树而言,在进行多次的插入或删除后,容易让树失去平衡,导致树的深度不是O(logN),而接近O(N),这样将大大减少对树的查找效率.一种解决办法就是要有一个称为平衡的附加的结构条件 ...
- 算法导论笔记:18B树
磁盘作为辅存,它的容量要比内存大得多,但是速度也要慢许多,下面就是磁盘的的结构图: 磁盘驱动器由一个或多个盘片组成,它们以固定的速度绕着主轴旋转,数据存储于盘片的表面,磁盘驱动器通过磁臂末尾的磁头来读 ...
- 基于visual Studio2013解决算法导论之051区间树
题目 区间树 解决代码及点评 #include <stdio.h> #include <string.h> #include <iostream> #def ...
- 树 -- AVL树
前言 通过之前对二叉查找树的讨论,我们知道在给定节点数目的情况下,二叉树的高度越低,查找所用时间也就越短. 在讨论红黑树的时候,我们说过红黑树并非完全"平衡"的二叉树,只是近似&q ...
- 红黑树/B+树/AVL树
RB Tree 红黑树 :http://blog.csdn.net/very_2/article/details/5722682 Nginx的RBTree实现 :http://blog.csdn ...
- 数据结构--树--AVL树
详情查看:http://www.cnblogs.com/skywang12345/p/3577360.html
- 红黑树和AVL树的实现与比较-----算法导论
一.问题描述 实现3种树中的两种:红黑树,AVL树,Treap树 二.算法原理 (1)红黑树 红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是red或black.红黑树满足以 ...
- 06-看图理解数据结构与算法系列(AVL树)
AVL树 AVL树,也称平衡二叉搜索树,AVL是其发明者姓名简写.AVL树属于树的一种,而且它也是一棵二叉搜索树,不同的是他通过一定机制能保证二叉搜索树的平衡,平衡的二叉搜索树的查询效率更高. AVL ...
随机推荐
- Redis中的关系查询
本文对Redis如何保存关系型数据,以及如何对其匹配.范围.模糊查询进行举例讲解,其中模糊查询功能基于最新的2.8.9以后版本. 1 关系型数据的存储 以Staff对象为例,在关系型数据库或类似Gri ...
- Redis 学习笔记1:CentOS 6.7下安装Redis
在linux环境搭建Redis环境,首先从官网(http://redis.io/)下载Redis 版本,本人使用的3.21版本. 1. 将redis 解压到 /usr/local目录下. [root ...
- Android使用HttpClient以Post、Get请求服务器发送数据的方式(普通和json)
讲这个之前,我们先来说说get和post两种请求的区别吧!!! 1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.jsp?name=te ...
- Struts 2 之资源国际化
首先在struts.properties文件中加入以下内容: struts.custom.i18n.resources=messageResource 或在struts.xml中加入 <con ...
- UE4 C++与蓝图交互
一.C++调用蓝图的函数 本来应该有一个很好的示例,但一下却忘了适用于哪些地方,只有简单写一个步骤了. 1.新建一个C++类继承Actor,名称随意,我这里继承了一个SplineMesh,一样de,并 ...
- Java开发各层对象含义 PO,VO,DAO,BO,POJO
java的几种对象(PO,VO,DAO,BO,POJO)解释 一.PO:persistant object 持久对象,可以看成是与数据库中的表相映射的java对象.最简单的PO就是对应数据库中 ...
- UNIX网络编程——SOCKET API和TCP STATE的对应关系_三次握手_四次挥手及TCP延迟确认
在socket系统调用中,如何完成三次握手和四次挥手: SOCK_DGRAM即UDP中的connect操作知识在内核中注册对方机器的IP和PORT信息,并没有建立连接的过程,即没有发包,close也不 ...
- SDL2源代码分析8:视频显示总结
===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...
- StarUML中InteractionOperation的画法
StarUML画InteractionOperation的方法:http://stackoverflow.com/questions/16152278/using-alt-in-sequence-di ...
- pig的一些实例(我常用的语法)
在pig中, dump和store会分别完成两个MR,不会一起进行 1:加载名用正则表达式: LOAD'/user/wizad/data/wizad/raw/2014-0{6,7-0,7-1,7-2, ...