AVL平衡二叉树打印树模型测试

对于树模型,大家比较熟知的就是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平衡二叉树打印树模型测试》

《AVL平衡二叉树打印树模型测试》

《AVL平衡二叉树打印树模型测试》

《AVL平衡二叉树打印树模型测试》

《AVL平衡二叉树打印树模型测试》

《AVL平衡二叉树打印树模型测试》

《AVL平衡二叉树打印树模型测试》

《AVL平衡二叉树打印树模型测试》


可从上面的图中看出AVL树模型的变化,不管是插入还是删除元素,整个AVL树始终都保持平衡!

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