对于树模型,大家比较熟知的就是AVL树和红黑树。前者利用树的高度来严格的保证左右子树的高度差不超过1,而后者则利用着色和一系列规则确保树的平衡:左右子树高度差不超过2。本篇文章主要讨论AVL树,并打印出树的结构模型,以便观察树在插入和删除元素后树的变化。
一、代码
1、AvlTree.h
<span style="font-family:Microsoft YaHei;">#ifndef __AVL_TREE__
#define __AVL_TREE__
#include "printTree.h"
#include<iomanip>
template <typename Type>
class AvlTree{
public:
struct AvlNode{
Type element;
AvlNode *left;
AvlNode *right;
int height;
AvlNode( const Type& dt, AvlNode *lt, AvlNode *rt, int h = 0 ) : element(dt), left(lt), right(rt), height(h){}
};
private:
AvlNode *root;
int size;
friend class PrintTree<Type, AvlNode, AvlTree>;
PrintTree<Type, AvlNode, AvlTree> ptta;
int height( AvlNode *t ){
return ( t == NULL ) ? -1 : t -> height;
}
int max( int x, int y ){
return x > y ? x : y;
}
void right_rotate( AvlNode* &t ){
AvlNode *k = t -> left;
t -> left = k -> right;
k -> right = t;
t -> height = max( height( t -> left ), height( t -> right ) ) + 1;
k -> height = max( height( k -> left ), t -> height ) + 1;
t = k;
}
void left_rotate( AvlNode* &t ){
AvlNode *k = t -> right;
t -> right = k -> left;
k -> left = t;
t -> height = max( height( t -> left ), height( t -> right ) ) + 1;
k -> height = max( t -> height, height( t -> right ) ) + 1;
t = k;
}
void doubleWithLeftFirst( AvlNode* &t ){
left_rotate( t -> left );
right_rotate( t );
}
void doubleWithRightFirst( AvlNode* &t ){
right_rotate( t -> right );
left_rotate( t );
}
void insert( const Type& x, AvlNode* &t ){ //将新的元素插入二叉树,如果该元素值在二叉树中出现了,则什么也不做
if( t == NULL ){
t = new AvlNode( x, NULL, NULL );
++size;
}
else if( x < t -> element ){
insert( x, t -> left );
if( height( t -> left ) - height( t -> right ) == 2 )
if( x < t -> left -> element )
right_rotate( t );
else
doubleWithLeftFirst( t );
}
else if( t -> element < x ){
insert( x, t -> right );
if( height( t -> right ) - height( t -> left ) == 2 )
if( t -> right -> element < x )
left_rotate( t );
else
doubleWithRightFirst( t );
}
else
; //do nothing
t -> height = max ( height( t -> left ), height( t -> right ) ) + 1;
}
void remove( const Type& x, AvlNode* &t ){ //将指定元素从指定节点中移除,如果有的话
if( t == NULL )
return;
if( x < t -> element ){
remove( x, t -> left );
if( height( t -> right ) - height( t -> left ) == 2 )
if( height( t -> right -> left ) < height( t -> right -> right ) )
left_rotate( t );
else
doubleWithRightFirst( t );
}
else if( t -> element < x ){
remove( x, t -> right );
if( height( t -> left ) - height( t -> right ) == 2 )
if( height( t -> left -> right ) < height( t -> left -> left ) )
right_rotate( t );
else
doubleWithLeftFirst( t );
}
else if( t->left != NULL && t->right != NULL ){
t -> element = findMin( t -> right ) -> element;
remove( t -> element, t -> right );
if( height( t -> left ) - height( t -> right ) == 2 )
if( height( t -> left -> right ) < height( t -> left -> left ) )
right_rotate( t );
else
doubleWithLeftFirst( t );
}
else{
AvlNode *old = t;
t = ( t -> left != NULL ) ? t -> left : t -> right;
delete old;
--size;
return;
}
t -> height = max( height( t -> left ), height(t -> right ) ) + 1;
}
bool search( const Type& x, AvlNode *t ) const { //在指定的节点中搜索指定的元素,如果有的话
if( t == NULL )
return false;
else if( x < t -> element )
return search( x, t -> left );
else if( t -> element < x )
return search( x, t -> right );
else
return true;
}
void clear( AvlNode* &t ){ //删除二叉树
if( t != NULL ){
clear( t -> left );
clear( t -> right );
delete t;
}
t = NULL;
}
void print( AvlNode* &t ) const { //对二叉树进行中序遍历,也即由小到大输出
if( t == NULL )
return;
print( t -> left );
std::cout << std::setw(5) << t -> element;
print( t -> right );
}
AvlNode* clone( AvlNode *t ) const { //复制二叉树
if( t == NULL )
return NULL;
return new AvlNode( t -> element, clone( t -> left ), clone( t -> right ) );
}
void initial(){ //默认二叉树数据初始化
root = NULL;
size = 0;
}
bool initial( const Type& e ){ //带指定参数的初始化
root = new AvlNode( e, NULL, NULL );
if( root == NULL )
return false;
size = 1;
return true;
}
public:
AvlTree(){ //默认构造函数
initial();
}
AvlTree( Type& e ){ //带指定参数的构造函数
if( !initial(e) )
std::cout << "根节点构造失败!" << std::endl;
}
AvlTree(const AvlTree& rhs){ //复制构造函数
*this = rhs;
}
const AvlTree& operator=(const AvlTree& rhs){ //复制操作符
if( this != &rhs ){
clear();
root = clone( rhs.root );
}
return *this;
}
~AvlTree(){ //析构函数
clear( root );
}
AvlNode* findMin( AvlNode *t ){ //寻找二叉树中最小数据的节点
if( t != NULL )
while( t -> left != NULL )
t = t -> left;
return t;
}
AvlNode* findMax( AvlNode *t ){ //寻找二叉树中最大数据的节点
if( t != NULL )
while( t -> right != NULL )
t = t -> right;
return t;
}
Type findMin(){ //寻找二叉树中最小的数据
AvlNode *p = findMin( root );
if( p == NULL )
return -1;
return p -> element;
}
Type findMax(){ //寻找二叉树中最大的数据
AvlNode *p = findMax( root );
if( p == NULL )
return -1;
return p -> element;
}
bool search( const Type& x ) const { //搜索指定的元素是否在二叉树中
return search( x, root );
}
bool isEmpty() const { //判断二叉树是否为空
return size == 0;
}
int Size(){ //返回二叉树节点的数目
return size;
}
void insert( const Type& e ){ //将元素插入二叉树中
insert( e, root );
}
void remove( const Type& e ){ //将元素从二叉树中移除,如果有的话
remove( e, root );
}
void Traverse(){ //对整个二叉树进行由小到大的输出
print( root );
}
void print_tree(){
ptta.print_tree( *this );
}
};
#endif</span>
2、printTree.h
<span style="font-family:Microsoft YaHei;">#include<string>
#include<vector>
#include<sstream>
/*
1、专门用于打印二叉树的泛型类,使用此类需申明该类为友元、并且在使用类中定义该类的一个实例;
2、需要提供三个类型参数,第一个为结点元素的类型,第二个为结点的类型,第三个为使用类的类型;
3、最后,在调用唯一的外部接口时,需传递使用类的当前实例作为唯一的参数!
*/
template<typename Type, typename bten, typename ClassType>
class PrintTree{
int height, width;
std::vector<std::string> vs;
bten *root;
int max(int x, int y){
return x > y ? x : y;
}
int get_height(bten* &t){
if( !t )
return 0;
if( t -> left == NULL && t -> right == NULL )
return 1;
int ht = max( get_height( t -> left ), get_height( t -> right) ) + 1;
return ht;
}
std::string transform(Type n){
std::string st;
std::ostringstream oss;
oss << n;
st = oss.str();
return st;
}
void create_string(std::string& s, int cur_height){
int i, frontw = 1, behindw = 1, pows = height - cur_height;
frontw <<= pows;
--frontw;
behindw <<= (pows + 1);
behindw -= (frontw + 1);
std::string tmp;
for(i = 0; i < width; ++i)
tmp += " ";
for(i = 0; i < frontw; ++i)
s = tmp + s;
for(i = 0; i < behindw; ++i)
s += tmp;
}
void set_string(Type value, int cur_height){
std::string s;
if( value != -1 ){
s = transform( value );
int dis = width - s.size();
if( dis < 0 ){
std::cout << "控制宽度:" << width << '\t' << "字符串为:" << s << '\t' </span>
<span style="font-family:Microsoft YaHei;"><span style="white-space:pre"> </span><< "字符串长度为:" << s.size() << std::endl;
return;
}
for(int i = 0; i < dis; ++i)
s = " " + s;
}
else{
s = "";
for(int i = 0; i < width; ++i)
s = " " + s;
}
create_string( s, cur_height );
vs[cur_height] += s;
s.clear();
}
void push_value_map( bten* &t, int front_height ){
int frh = get_cur_height( t );
if( !t && height > front_height ){
int pows = height - front_height, level;
for( level = 0; level < pows; ++level ){
int count = ( !level ) ? 1 : ( 1 << level );
for(int i = 0; i < count; ++i)
set_string( ( Type ) -1, front_height + level + 1 );
}
}
else if( t ){
set_string( t -> element, frh );
push_value_map( t -> left, frh );
push_value_map( t -> right, frh );
}
else
return;
}
int get_height(){
return get_height( root );
}
int get_cur_height( bten* &t ){
if( !t )
return 0;
int ht = 0;
bten *temp = root;
while( true ){
if( !temp )
break;
if( t -> element < temp -> element ){
temp = temp -> left;
++ht;
}
else if(temp -> element < t -> element ){
temp = temp -> right;
++ht;
}
else
break;
}
return ht;
}
public:
void print_tree( ClassType &t ){ //打印二叉树的外部函数接口
root = t.root;
height = get_height( root );
--height;
std::vector<std::string> vs_tmp( height + 1 );
vs = vs_tmp;
std::string tm = transform( t.findMax() );
width = tm.size();
push_value_map( root, 0 );
for(int i = 0; i < vs.size(); ++i)
std::cout << vs[i] << std::endl;
vs.clear();
}
};</span>
3、testAvlTree.cpp
<span style="font-family:Microsoft YaHei;">#include<iostream>
#include "AvlTree.h"
using namespace std;
int main(){
AvlTree<int> avlt;
int x;
cout<< "首次使用请先初始化根的值:";
cin >> x;
avlt.insert( x );
cout << endl;
while( 1 ){
cout << " 二叉平衡树操作菜单" << endl;
cout << "----------------------------------------------------------------------------------------\n";
cout << "1---insert( &e ) 2---findMin() 3---findMax() 4---search( &e ) 5---empty()\n";
cout << "6---remove( &e ) 7---size() 8---print_tree() 0---Quit\n";
cout << "----------------------------------------------------------------------------------------\n";
cout << "请选择:";
cin >> x;
if(x <= 0 || x > 8)
break;
switch(x){
case 1:
cout<<"请输入要插入的值:";
cin >> x;
avlt.insert( x );
cout<<"插入后为:"<<endl;
avlt.Traverse();
cout << endl;
break;
case 2:
cout << "当前二叉树中最小的值为:" << avlt.findMin() << endl;
break;
case 3:
cout << "当前二叉树中最大的值为:" << avlt.findMax() << endl;
break;
case 4:
cout << "请输入待搜索的元素:";
cin >> x;
if( avlt.search( x ) )
cout << "当前元素在二叉树中!" << endl;
else
cout << "当前元素不在二叉树中!" << endl;
break;
case 5:
if( !avlt.isEmpty() )
cout << "当前二叉树不为空!" << endl;
else
cout << "当前二叉树为空!" << endl;
break;
case 6:
cout << "当前二叉树元素为:" << endl;
avlt.Traverse();
cout << endl;
cout << "请输入要删除的元素:";
cin >> x;
avlt.remove( x );
cout << "删除后二叉树元素为:" << endl;
avlt.Traverse();
cout << endl;
break;
case 7:
cout <<"当前二叉树节点数为:" << avlt.Size() << endl;
break;
case 8:
avlt.print_tree();
break;
default:
break;
}
}
return 0;
}</span>
二、测试图示
可从上面的图中看出AVL树模型的变化,不管是插入还是删除元素,整个AVL树始终都保持平衡!