最近在学习《数据结构与算法分析(C语言描述)》,上面讲到一个带平衡条件的二叉查找树,之前在一家公司笔试也遇到了类似的题,于是决定自己用C++模板实现一遍。
(声明文件)AVL.h :
#ifndef AVL_DEC_H
#define AVL_DEC_H
template T>
class AvlTree;
int Max(int a1, int a2)
{
return a1 > a2 ? a1 : a2;
}
//节点类模板
templateT >
class Node
{
public:
friend class AvlTree<T>;
Node(T x);
private:
T element;
Node<T> *left;
Node<T> *right;
int height;
};
//AVL树
template T>
class AvlTree
{
public:
AvlTree();
~AvlTree();
void append(T x);
static int Height(Node<T>* tree);
void print();
void clear();
private:
void FreeTree(Node<T>* r);
Node<T>* append(T x, Node<T>* r);
void Add2Array(Node<T>* r, T** a, int* b, int n);
Node<T>* SingleRotationWithLeft(Node<T>*);
Node<T>* SingleRotationWithRight(Node<T>*);
Node<T>* DoubleRotationWithLeft(Node<T>*);
Node<T>* DoubleRotationWithRight(Node<T>*);
private:
Node<T>* root;
};
#include "AVL_def.h"
#endif // !AVL_DEC_H
(实现文件)AVL_def.h :
#ifndef AVL_DEF_H
#define AVL_DEF_H
template<typename T>
Node::Node(T x)
{
element = x;
left = nullptr;
right = nullptr;
height = 0;
}
template<typename T>
AvlTree::AvlTree()
{
root = nullptr;
}
template<typename T>
inline AvlTree::~AvlTree()
{
clear();
}
template<typename T>
void AvlTree::append(T x)
{
//调用另一个重载函数
root = append(x, root);
}
template <typename T>
Node* AvlTree::append(T x, Node* r)
{
if (r == nullptr)
{
r = new Node(x);
}
else if (x < r->element)
{
//要插入的数比当前节点数小,向左递归
r->left = append(x, r->left);
//如果插入操作导致当前节点不平衡
if (Height(r->left) - Height(r->right) == 2)
{
//在左儿子的左子树插入
if (x < r->left->element)
r = SingleRotationWithLeft(r);//进行一次从左向右的单旋转
//在左儿子的右子树插入
else
r = DoubleRotationWithLeft(r);//进行一次从左向右的双旋转
}
}
else if (x > r->element)
{
//要插入的数比当前节点数大,向右递归
r->right = append(x, r->right);
//如果插入操作导致当前节点不平衡
if (Height(r->right) - Height(r->left) == 2)
{
//在右儿子的右子树插入
if (x > r->right->element)
r = SingleRotationWithRight(r);//进行一次从左向右的单旋转
//在右儿子的左子树插入
else
r = DoubleRotationWithRight(r);//进行一次从左向右的双旋转
}
}
r->height = Max(Height(r->left), Height(r->right)) + 1;
return r;
}
//计算树的深度
template<typename T>
int AvlTree::Height(Node * r)
{
if (r == nullptr)
return -1;
else
return r->height;
}
//清除元素
template<typename T>
void AvlTree::clear()
{
FreeTree(root);
root = nullptr;
}
template<typename T>
void AvlTree::FreeTree(Node* r)
{
if (r == nullptr)
return;
if (r->left == nullptr && r->right == nullptr)
delete r;
else
{
FreeTree(r->left);
FreeTree(r->right);
delete r;
}
}
template<typename T>
Node* AvlTree::SingleRotationWithLeft(Node* r)
{
Node* k1;
k1 = r->left;
r->left = k1->right;
k1->right = r;
r->height = Max(Height(r->left),
Height(r->right)) + 1;
k1->height = Max(Height(k1->left), r->height) + 1;
return k1;
}
template<typename T>
Node* AvlTree::SingleRotationWithRight(Node* r)
{
Node* k1;
k1 = r->right;
r->right = k1->left;
k1->left = r;
r->height = Max(Height(r->left),
Height(r->right)) + 1;
k1->height = Max(Height(k1->right), r->height) + 1;
return k1;
}
template<typename T>
Node* AvlTree::DoubleRotationWithLeft(Node* r)
{
r->left = SingleRotationWithRight(r->left);
return SingleRotationWithLeft(r);
}
template<typename T>
Node* AvlTree::DoubleRotationWithRight(Node* r)
{
r->right = SingleRotationWithLeft(r->right);
return SingleRotationWithRight(r);
}
//将树的所有元素输出到一个二维数组,安全性由调用例程负责
template<typename T>
void AvlTree::Add2Array(Node* r, T** a, int* b, int n)
{
if (r == nullptr)
return;
a[n][b[n]++] = r->element;
Add2Array(r->left, a, b, n + 1);
Add2Array(r->right, a, b, n + 1);
}
#endif // !AVL_DEF_H
(测试)main.cpp :
#include
#include "AVL.h"
using namespace std;
//打印元素
template<typename T>
inline void AvlTree::print()
{
int n = Height(root) + 1;
T** a = new T*[n];
int *b = new int[n];
for (int i = 0; i < n; ++i)
{
a[i] = new T[pow(2, i)];
b[i] = 0;
}
Add2Array(root, a, b, 0);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n - i - 1; ++j)
cout << " ";
for (int j = 0; j < b[i]; ++j)
{
cout << a[i][j] << " ";
}
cout << endl;
}
for (int i = 0; i < n; ++i)
delete[] a[i];
delete[] a;
delete[] b;
}
int main()
{
int a[] = { 1,2,3,4,8,7,12,9,32,45,13,24,17 };
AvlTree<int> avl;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
avl.append(a[i]);
avl.print();
system("pause");
return 0;
}