【数据结构】AVL树的实现与应用(AVL树非递归版)

一、实验目的

         1. 掌握二叉树的链式存储结构。
         2. 掌握二叉树的各种遍历算法。
         3. 掌握二叉查找树节点查找、修改非关键字部分的算法实现。
         4. 掌握平衡二叉查找树节点插入、删除的算法实现。

二. 实验要求、内容

       1. 基于二叉链式存储结构实现平衡二叉查找树的典型操作(构造、拷贝构造、析构、赋值运算符重载、节点个数、树高、增加节点、删除节点、查找一个节点、判空、修改某个节点非关键字部分的数据、先根遍历、后根遍历、中根遍历、按层次遍历),测试和调试程序。
       2. 使用平衡二叉查找树完成树排序算法,测试和调试程序。
       3. 按要求撰写实验报告、录制程序运行以及讲解程序的视频。 报告中要包含算法性能的讨论以及根据实现效率在问题的多种解决方案中进行比较、选择的说明。

三.实验设备

          计算机、Windows 操作系统、C++语言集成开发环境。

四.实验原理(或程序框图)及步骤

          具体流程图及原理可点击此链接。https://download.csdn.net/download/qq_47504614/20923278

五、程序源代码

          AVL树用非递归实现,此处给出部分核心代码,完整代码可点击下方链接下载。https://download.csdn.net/download/qq_47504614/20923278

AVL.h 文件

enum State_code {
	success, fail, range, underflow, overflow, fatal, not_present,
	duplicate_error, entry_inserted, entry_found, internal_error
};
enum Balance_factor { left_higher, equal_height, right_higher };
template <class Record> struct AVL_node {
	// data members:
	Record data;   //节点数据
	AVL_node<Record>* left;    //左孩子
	AVL_node<Record>* right;   //右孩子
	Balance_factor balance;    //平衡因子
	//4 个方法
	// constructors:
	AVL_node();    //无参构造
	AVL_node(const Record& x);      //有参构造
	void set_balance(Balance_factor b);      //建立平衡因子
	Balance_factor get_balance() const;      //获取平衡因子
};

template <class Record> 
class AVL_tree 
{
public:
	//17+2 方法数
	AVL_tree();
	bool empty() const;// 判空
	void preorder(void (*visit)(Record&));// 先根遍历
	void inorder(void (*visit)(Record&));// 中根遍历
	void postorder(void (*visit)(Record&));// 后根遍历
	void level_traverse(void (*visit)(Record&));// 按层次遍历
	int size() const;// 树中节点总数
	int height() const;// 树高
	int width() const;// 树宽
	void clear();// 置空
	AVL_tree(const AVL_tree<Record>& original);// 构造
	AVL_tree& operator =(const AVL_tree<Record>& original);// 拷贝构造
	~AVL_tree();// 析构
	State_code insert(const Record& new_data);// 插入新节点,数据为new_data
	State_code remove(const Record& old_data);// 找到数据为old_data 的节点删除
	State_code retrieve(Record& target) const;// 查找关键字为target 的节点带回
	State_code replace(Record& target);// 查找关键字为target 的节点,修改非关键字部分
	// 用于验证树形结构
	void print_tree(void (*f)(int indentation, AVL_node<Record>*&));
	void prenode(int indentation, AVL_node<Record>* root, void (*f)(int indentation,
		AVL_node<Record>*&));
	void tree_sort(AVL_tree<Record>&, List<AVL_node<Record>*> &, void (*visit)(Record&));
private:
	AVL_node<Record>* root;	
};

增加函数: 

template <class Record>State_code AVL_tree<Record>::insert(const Record& new_data)// 插入新节点,数据为new_data
{
	bool taller = true;   //是否需要平衡树
	AVL_node<Record>* p = root;
	AVL_node<Record>* parent = NULL; // 记录前驱结点,方便连接和调整平衡因子
	Stack<AVL_node<Record>*> st; //用栈记录插入的路径,方便调整栈中结点的平衡因子;

	 // 找插入位置,记录路径信息
	while (p != NULL) {
		if (new_data == p->data)
		{ //要插入的数据和AVL树中的数字相同,则返回失败!
			return fail;
		}

		parent = p;
		st.push(parent); //找过的入栈
		if (new_data < p->data)
		{
			p = p->left;
		}
		else if (new_data > p->data)
		{
			p = p->right;
		}
	}

	p = new AVL_node<Record>(new_data);
	p->set_balance(equal_height);

	if (parent == NULL)
	{
		root = p;    //判断是不是第一个结点,进行root的连接;
		root->set_balance(equal_height);
		return success;
	}

	//此时通过父节点的数据判断插入的是左还是右
	if (new_data < parent->data)
	{ 
		parent->left = p;
	}
	else
	{
		parent->right = p;
	}
	
/// 以上完成插入工作

	while (!st.empty())
	{  //栈不空,出栈顶元素
		st.top(parent);
		st.pop();

		//插入的是父节点的左孩子
		if (p == parent->left)
		{  
			//得到父节点的平衡因子,如果父节点等高,插入之后左高1,不需要平衡树
			if (parent->get_balance() == equal_height)
			{
				parent->set_balance(left_higher);
				taller = false;
			}
			//如果父节点左高,插入之后左高2,需要平衡树
			else if (parent->get_balance() == left_higher)
			{
				parent->set_balance(left_higher);
				taller = true;
			}
			//如果父节点右高,插入之后等高,不需要平衡树
			else if (parent->get_balance() == right_higher)
			{
				parent->set_balance(equal_height);
				taller = false;
			}
		}
		//插入的是父节点的右孩子
		else if (p == parent->right)
		{
			//如果父节点等高,插入之后右高1,不需要平衡树
			if (parent->get_balance() == equal_height)
			{
				parent->set_balance(right_higher);
				taller = false;
			}
			//如果父节点左高,插入之后等高,不需要平衡树
			else if (parent->get_balance() == left_higher)
			{
				parent->set_balance(equal_height);
				taller = false;
			}
			//如果父节点右高,插入之后右高2,需要平衡树
			else if (parent->get_balance() == right_higher)
			{
				parent->set_balance(right_higher);
				taller = true;
			}
		}

		//以下判断栈中的平衡因子,看是否需要进行旋转调整
		if (parent->get_balance() == equal_height)
		{  //等高,直接跳出循环
			break;
		}
		//如果taller=false,且父节点右高或左高,代表当前父节点右高1或左高1
		if ((!taller)&& ((parent->get_balance() == right_higher) || (parent->get_balance() == left_higher)))
		{
			p = parent;  //此时在向上走,判断平衡因子;
		}
		//如果taller为真,此时父节点左高2或右高2,需要平衡
		else if (taller)
		{
			if (parent->get_balance() == left_higher)  //左高2
			{
				//LL型,右旋父节点
				if ((p->get_balance() == left_higher) && (p == parent->left)) 
				{
					AVL_node<Record>* subR = parent;
					parent = parent->left;
					subR->left = parent->right;
					parent->right = subR;
					parent->set_balance(equal_height);
					subR->set_balance(equal_height);
				}
				//LR型,先左旋父节点的左孩子,再右旋父节点
				else if ((p->get_balance() == right_higher) && (p == parent->left))
				{

					AVL_node<Record>* subR = parent;
					AVL_node<Record>* subL = parent->left;
					parent = subL->right;

					subL->right = parent->left;
					parent->left = subL;
					if ((parent->get_balance() == left_higher) || (parent->get_balance() == equal_height))
					{
						subL->set_balance(equal_height);
					}
					else
					{
						subL->set_balance(left_higher);
					}

					subR->left = parent->right;
					parent->right = subR;
					if (parent->get_balance() == left_higher)
					{
						subR->set_balance(right_higher);
					}
					else
					{
						subR->set_balance(equal_height);
					}

					parent->set_balance(equal_height);

				}
			}
			//右高2
			else if(parent->get_balance() == right_higher) 
			{
				//RR型,左旋父节点
				if ((p->get_balance() == right_higher) && (p == parent->right))
				{
					AVL_node<Record>* subL = parent;
					parent = subL->right;
					subL->right = parent->left;
					parent->left = subL;
					subL->set_balance(equal_height);
					parent->set_balance(equal_height);
				}
				//RL型,先右旋父节点的右孩子,再左旋父节点
				else if ((p->get_balance() == left_higher) && (p == parent->right))
				{
					
					AVL_node<Record>* subL = parent;
					AVL_node<Record>* subR = parent->right;
					parent = subR->left;

					subR->left = parent->right;
					parent->right = subR;
					if ((parent->get_balance() == right_higher) || (parent->get_balance() == equal_height))
					{
						subR->set_balance(equal_height);
					}
					else
					{
						subR->set_balance(right_higher);
					}

					subL->right = parent->left;
					parent->left = subL;
					if (parent->get_balance() == right_higher)
					{
						subL->set_balance(left_higher);
					}
					else
					{
						subL->set_balance(equal_height);
					}
					parent->set_balance(equal_height);

				}
			}
			break;
		}
		
	}
	if (st.empty())
	{  //通过旋转函数,此时parent指向根节点;
		root = parent;  //此时调到栈底了,旋转后将更改root的指向
	}
	else
	{
		AVL_node<Record>* tmp;
		st.top(tmp);  //当前的栈顶结点
		if (parent->data < tmp->data)
		{
			tmp->left = parent;
		}
		else
		{
			tmp->right = parent;
		}
	}
	return success;
}

六、实验结果

          测试数据:16、3、7、11、9、26、18、14、15(依次插入)

输出树形结构:

( 11 : ->  R ) ===> 7 18
 ( 7 : ->  E ) ===> 3 9
  ( 3 : ->  E ) ===>
  ( 9 : ->  E ) ===>
 ( 18 : ->  L ) ===> 15 26
  ( 15 : ->  E ) ===> 14 16
   ( 14 : ->  E ) ===>
   ( 16 : ->  E ) ===>
  ( 26 : ->  E ) ===>

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_47504614

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值