C++实现平衡二叉树(AVL树)

#pragma once
/*
	二叉查找树的操作:
    -插入
    -遍历
    -删除
    -修改
    -查询
    -清空
*/
class AVL
{
private:
    // 定义一个节点类型
    typedef struct tagNode {
        tagNode(int nVal, size_t nHeight = 1, tagNode* pParent=nullptr, tagNode* pLeft=nullptr, tagNode* pRight=nullptr) :m_nHeight(nHeight),m_nVal(nVal),m_pLeft(pLeft), m_pRight(pRight), m_pParent(pParent){};
        int m_nVal; // 数据
        size_t m_nHeight; // 节点的高度
        tagNode *m_pParent; // 父节点
        tagNode *m_pLeft; // 左孩子
        tagNode *m_pRight; // 右孩子
    }NODE,*PNODE;
public:
    AVL();
    AVL(const AVL& obj);
    AVL& operator=(const AVL& obj);
    ~AVL();
    // 插入
    bool Insert(int nVal);
    // 删除
    bool Delete(int nVal);
    // 修改
    bool Update(int nSrcVal,int nDstVal);
    // 查询
    bool Find(int nVal);
    // 清空
    void Clear();

    // 层序遍历 一层一层输出
    void LevelTraversal();
    // 递归前序遍历 根左右
    void MLR();
    // 递归中序遍历 左根右
    void LMR();
    // 递归后序遍历 左右根
    void LRM();

    // 中序使用循环
    void LMP_LOOP();
    // 前序使用循环
    void MLR_LOOP();
    // 后序使用循环
    void LRM_LOOP();
private:
    // 递归中序遍历 左根右
    void LMR(PNODE pNode);
    // 递归前序遍历 根左右
    void MLR(PNODE pNode);
    // 递归后序遍历 左右根
    void LRM(PNODE pNode);

    // 中序使用循环
    void LMP_LOOP(PNODE pNode);
    // 前序使用循环
    void MLR_LOOP(PNODE pNode);
    // 后序使用循环
    void LRM_LOOP(PNODE pNode);

    // 查询并返回指针
    PNODE FindNode(int nVal);
    // 删除叶子节点
    void DeleteLeaf(PNODE pLeaf);
    // 删除单分节点
    void DeleteSingle(PNODE pSingle);

    // 调整高度
    void AdjustHeight(PNODE pNode);
    // 获取高度
    size_t GetHeight(PNODE pNode);
    // 计算高度
    size_t CalcHeight(PNODE pNode);
    // 右旋
    void RotateRight(PNODE pNode);
    // 左旋
    void RotateLeft(PNODE pNode);
private:
    PNODE m_pRoot; // 根节点
};


#include "AVL.h"
#include 
#include 
#include 

using namespace std;

AVL::AVL()
{
	// 初始化根节点
	this->m_pRoot = nullptr; 
}

AVL::AVL(const AVL& obj)
{
	this->m_pRoot = nullptr;
	*this = obj;
}

AVL& AVL::operator=(const AVL& obj)
{
	if (this == &obj) return *this;
	// 清除自己
	Clear();
	// 拷贝obj
	/*
		通过队列完成层序遍历
	*/
	deque trees;
	/*
		根节点入队
		然后出队 打印,再依次把左右两边入队
		循环此操作
	*/
	trees.push_back(obj.m_pRoot);
	while (!trees.empty()) {
		// 获取队首
		auto temp = trees.front();
		Insert(temp->m_nVal); 
		// 弹出队首
		trees.pop_front();
		// 把左右两边入队
		if (temp->m_pLeft != nullptr) {
			trees.push_back(temp->m_pLeft);
		}
		if (temp->m_pRight != nullptr) {
			trees.push_back(temp->m_pRight);
		}
	}
	return *this;
}

AVL::~AVL()
{
	// 释放内存
	Clear();
}

/*
	插入元素
*/
bool AVL::Insert(int nVal)
{
	// 创建节点
	PNODE pNewNode = new NODE(nVal); // pNewNode 保存new出来的这个地址
	// 如果分配失败的话
	if(pNewNode == nullptr){
		return false;
	}
	// 如果分配成功的话
	if(this->m_pRoot == nullptr){
		// 如果现在是一颗空树
		this->m_pRoot = pNewNode; // 相当于和pNewNode一样保存第一个new出来的节点地址
		return true;
	}
	// 如果不是空树 开始遍历 直至某个节点的叶子节点为null就插入
	PNODE pNode = this->m_pRoot; // 用一个临时节点 表示根节点 不修改根节点的数据
	while(true){
		// 如果当前节点的值 大于我们要插入的值 左边
		if(nVal < pNode->m_nVal){
			if(pNode->m_pLeft != nullptr){
				// 如果还有左孩子继续判断
				pNode = pNode->m_pLeft;
			}else{
				// 当前节点插入到左边
				pNode->m_pLeft = pNewNode;
				// 保存父节点
				pNewNode->m_pParent = pNode;

				/*
					调整高度
				*/
				AdjustHeight(pNode);

				return true;
			}
		}else if(nVal > pNode->m_nVal){
			// 如果当前节点的值 小于我们要插入的值 右边
			if (pNode->m_pRight != nullptr) {
				// 如果还有右孩子 继续判断
				pNode = pNode->m_pRight;
			}else {
				// 当前节点插入到右边
				pNode->m_pRight = pNewNode;
				// 保存父节点
				pNewNode->m_pParent = pNode;

				/*
					调整高度
				*/
				AdjustHeight(pNode);

				return true;
			}
		}else{
			// 暂时不考虑相等
			return false;
		}
	}
	return true;
}

// 删除叶子节点
void AVL::DeleteLeaf(PNODE pLeaf)
{
	/*
		如果被删除的叶子节点是根节点
		因为只有根节点的话 根节点就是叶子节点
	*/
	// 获取父节点
	auto pParendNode = pLeaf->m_pParent;
	if (pParendNode == nullptr) {
		delete pParendNode; // 直接删除根节点
		pParendNode = nullptr;
		this->m_pRoot = nullptr; // 把根节点指针置为null
		return;
	}

	/*
		如果要删除的不是根节点
		判断这个叶子节点是在父亲的左边还是右边
		如果是在父亲的左边 那么就把父亲的左边置为null
		如果是在父亲的右边 那么就把父亲的右边置为null
	*/
	if(pParendNode->m_pLeft == pLeaf){
		// 如果是左孩子 左孩子置空
		pParendNode->m_pLeft = nullptr;
	}else{
		// 如果是右孩子 右孩子置空
		pParendNode->m_pRight = nullptr;
	}
	// 最后释放内存
	delete pLeaf; 
	pLeaf = nullptr;

	if (pParendNode != nullptr)
	{
		// 删除完毕 从父节点开始重写调整高度
		AdjustHeight(pParendNode);
	}
}

/*
	删除单分支节点
*/
void AVL::DeleteSingle(PNODE pSingle)
{
	/*
		   p     p	        p       p	    
		  /  	   \       / 	     \    
		 S1    		 S1   S1 	   	  S1 
		/ 			/ 		\	   	   \ 	
	   C1 		   C1 		 C1 	    C1 	

					 ||
					 ||
					 ||
				\	 ||    /
				  \     /
				     \/

			   p     p	        p       p	    
			  /  	   \       / 	     \    
			 C1    		 C1   C1 	   	  C1 

		所以其实就是把单分支的孩子向上提就好了

	所以找到当前这个分支节点的父亲
	让当前这个分支节点的父亲直接指向这个分支的孩子就ok了
	*/
	
	/*
		获取要删除的这个单分支节点的父节点
	*/
	auto pParentNode = pSingle->m_pParent;
	/*
		判断这个节点是有左孩子还是右孩子 
		pLeftOrRightNode 为要删除的这个单分支节点的左孩子或者右孩子
	*/
	auto pLeftOrRightNode = pSingle->m_pLeft == nullptr ? pSingle->m_pRight : pSingle->m_pLeft;
	
	// 如果父节点为空 代表删除的是根节点
	if (pParentNode == nullptr){
		// 根节点 切换 为它的左右节点
		this->m_pRoot = pLeftOrRightNode;
		pLeftOrRightNode->m_pParent = nullptr; // 他作为新的根节点 没有父亲
		delete pSingle; // 释放根节点内存
		pSingle = nullptr;
		return; 
	}

	// 修改拿到的这个节点的父节点 为要删除的节点的父节点
	pLeftOrRightNode->m_pParent = pParentNode; // 就等于跳过中间那一层
	
	/*
		跳过中间那一层 开始提节点 到要删除节点的父亲的左右边 代替原来要删除的节点的位置
	*/
	if(pSingle == pParentNode->m_pLeft){
		// 提上来的节点放左边
		pParentNode->m_pLeft = pLeftOrRightNode;
	}else{
		// 提上来的节点放右边
		pParentNode->m_pRight = pLeftOrRightNode;
	}
	// 释放内存
	delete pSingle;
	pSingle = nullptr;

	if (pParentNode != nullptr)
	{
		// 删除完毕 从父节点开始重写调整高度
		AdjustHeight(pParentNode);
	}
}

// 调整高度
void AVL::AdjustHeight(PNODE pNode)
{
	/*
		沿着父节点,一路到根节点调整高度
		每次取出左右两边的最大值+1给自身

		来到这里 
		就证明这个节点的父亲是没有孩子,或者只有一边有孩子
	*/
	while(pNode != nullptr){
		// 先设置当前节点的高度
		/*if (pNode->m_pLeft != nullptr && pNode->m_pRight != nullptr) {
			// 如果两边都不为空 那么取最大的 + 1
			pNode->m_nHeight = 
				(pNode->m_pLeft->m_nHeight > pNode->m_pRight->m_nHeight ? 
				pNode->m_pLeft->m_nHeight + 1 : pNode->m_pRight->m_nHeight + 1) ;
		}else if(pNode->m_pLeft == nullptr && pNode->m_pRight == nullptr){
			// 如果左右两边都为空 那么直接为1
			pNode->m_nHeight = 1;
		}else{
			if (pNode->m_pLeft != nullptr) {
				// 如果左边不为空 取左边的高度 + 1
				pNode->m_nHeight = pNode->m_pLeft->m_nHeight + 1;
			}else{
				// 如果左边是空的那么就右边不为空 取右边的高度 + 1
				pNode->m_nHeight = pNode->m_pRight->m_nHeight + 1;
			}
		}*/

		// 调整高度
		pNode->m_nHeight = CalcHeight(pNode);

		// 获取高度
		int nLeftHeight = GetHeight(pNode->m_pLeft);
		int nRightHeight = GetHeight(pNode->m_pRight);

		// 开始调整树 判断树是否平衡
		// 如果当前节点的左子树的高度 - 右子数的高度 > 1 右旋
		if((nLeftHeight - nRightHeight) > 1){
			/*
				在当前这个不平衡的节点需要右旋之前
				我们还需要判断需不需要子节点先左旋一次
			*/
			if(GetHeight(pNode->m_pLeft->m_pLeft) >= GetHeight(pNode->m_pLeft->m_pRight)){
				// 如果左子树的左孩子比右孩子高,则一次单选
				// 右旋 传入当前节点 对当前节点左右子树进行右旋操作
				RotateRight(pNode);
			}else{
				// 否则需要两次
				// 先子树左旋
				RotateLeft(pNode->m_pLeft);
				// 再当前需要平衡的节点右旋
				RotateRight(pNode);
			}
		}

			

		// 如果当前节点的右子树的高度 - 左子树的高度 > 1 左旋
		if((nRightHeight - nLeftHeight) > 1){
			// 同理这里也是
			if(GetHeight(pNode->m_pRight->m_pRight) >= GetHeight(pNode->m_pRight->m_pLeft)){
				// 左旋 传入当前节点 对当前节点左右子树进行左旋操作
				RotateLeft(pNode);
			}else{
				// 否则需要两次
				// 先子树右旋
				RotateRight(pNode->m_pRight);
				// 再当前需要平衡的节点左旋
				RotateLeft(pNode);
			}
		}

		// 再去对当前节点的父亲操作
		pNode = pNode->m_pParent;
	}
}

// 获取高度
size_t AVL::GetHeight(PNODE pNode)
{
	if (pNode == nullptr)
	{
		return 0;
	}
	return pNode->m_nHeight;
}

// 计算高度
size_t AVL::CalcHeight(PNODE pNode)
{
	return GetHeight(pNode->m_pLeft) > GetHeight(pNode->m_pRight) ?
		GetHeight(pNode->m_pLeft) + 1 : GetHeight(pNode->m_pRight) + 1;
}

// 右旋
void AVL::RotateRight(PNODE pNode)
{
	/*
		K 不平衡
			 p
			 |
			 K
			/ \
		   M   E
		  / \
		 N   L
		/
       T
			||
			||
		   \  /         p从指向M变成了指向K
		    \/          K多了一个左孩子L,并且K指向了M
			 p          L的父亲从N变成了K,作为K的左孩子
			 |          M的父亲变为了P
			 M
			/ \
		   N   K
		  /   / \
	     T   L	 E

		 pNode  在这里是K 不平衡节点
	*/
	auto pK = pNode;
	auto pP= pK->m_pParent;
	auto pM = pK->m_pLeft;
	auto pL = pM->m_pRight;

	if(pP == nullptr){
		// 说明K是一个根节点 没有父亲
		this->m_pRoot = pM; // 修改根节点指向
	}else{
		// 不为空 修改P的指向
		if (pK == pP->m_pLeft) {
			// 如果K原本是左孩子 M作为新的左孩子
			pP->m_pLeft = pM;
		}else {
			// M作为新的右孩子
			pP->m_pRight = pM;
		}
		
	}
	
	// 修改K
	pK->m_pParent = pM; // 父节点为M
	pK->m_pLeft = pL; // 左孩子为K

	// 修改M
	pM->m_pParent = pP; // 修改M的父亲
	pM->m_pRight = pK; // 右孩子为K

	// 修改L
	if(pL != nullptr){
		// 如果有L存在 才修改父亲
		pL->m_pParent = pK; // 父亲为K
	}

	// 调整高度
	pK->m_nHeight = CalcHeight(pK);
	pM->m_nHeight = CalcHeight(pM);
}

// 左旋
void AVL::RotateLeft(PNODE pNode)
{
	/*
		K 不平衡
			 p
			 |
			 K
			/ \
		   E   M
			  / \
			 N   L
				  \
				   T
			||
			||
		   \  /        
			\/         P指向K变成指向M
			 p         K的父亲变成了M,K的右孩子为N
			 |         M的父亲变成了P
			 M         N的父亲为K
			/ \        
		   K   L
		  / \   \
		 E   N 	 T

		 pNode  在这里是K 不平衡节点
	*/
	auto pK = pNode;
	auto pP = pK->m_pParent;
	auto pM = pK->m_pRight;
	auto pN = pM->m_pLeft;

	// 修改P
	// 如果当前的K就是根节点
	if(pP == nullptr){
		this->m_pRoot = pM; // 修改根节点为M
	}else{
		// 如果pP存在修改pP的孩子
		if(pP->m_pRight == pK){
			// 如果K原本是右边 M也是右边
			pP->m_pRight = pM;
		}else{
			// 如果K原本的左边 M也是左边
			pP->m_pLeft = pM;
		}
	}
	// 修改K
	pK->m_pParent = pM;
	pK->m_pRight = pN; // 如果没有N 刚好也是nullptr 不用理

	// 修改M 
	pM->m_pParent = pP; // 如果pP是空 那么这里M就是根节点 根节点的父亲为nullptr 不用理
	pM->m_pLeft = pK; // M的左孩子是K

	// 修改N
	if (pN != nullptr)
		pN->m_pParent = pK; // 如果不为空 修改父亲 为空不处理

	// 调整高度
	pK->m_nHeight = CalcHeight(pK);
	pM->m_nHeight = CalcHeight(pM);
}


/*
	根据值删除节点
*/
bool AVL::Delete(int nVal)
{
	/*
		如果要删除的是叶子节点 直接删除
		如果要删除的不是叶子节点:
		单分支:
			子节点向上提
		双分支:
			左子树里面最大最接近要删除的值的数的节点【只可能是叶子或者有左子树】
			右子树里面最小最接近要删除的值的数的节点【只可能是叶子或者有右子树】
			【选其中一种,无论选择哪一种
			最后都会变成叶子或者单分支类型
			然后再执行上面的操作即可】

		按照上面的思路 我们往下找下去只能是叶子或者单分支
	*/
	// 查询节点
	auto pNodeToDel = FindNode(nVal);
	if(pNodeToDel == nullptr){
		// 如果没找到这个节点 
		return false;
	}
	// 1.叶子
	// 如果找到的这个节点是一个叶子节点
	if(pNodeToDel->m_pLeft == nullptr && pNodeToDel->m_pRight == nullptr){
		DeleteLeaf(pNodeToDel);
		return true;
	}
	// 如果代码能走到这就代表它不是叶子 那么我们判断 如果有一边为空 就是单分支了
	// 2.单分支
	if(pNodeToDel->m_pLeft == nullptr || pNodeToDel->m_pRight == nullptr){
		DeleteSingle(pNodeToDel);
		return true;
	}
	// 这里就不用判断了 能走到这里一定就是双分支了 既不是叶子 也不是单分支
	// 3.双分支
	/*
		这里选用查找要删除的节点的左子树中的最大值来进行 值的替换和删除
	*/
	auto pMaxInLeft = pNodeToDel->m_pLeft; 
	// 当这个循环结束 我们就找到了 被删除节点中的左子树的最大值了
	while(pMaxInLeft->m_pRight != nullptr){
		pMaxInLeft = pMaxInLeft->m_pRight;
	}
	// 找到最大值了 和 原本的节点的值进行替换
	int tempVal = pNodeToDel->m_nVal;
	pNodeToDel->m_nVal = pMaxInLeft->m_nVal;
	pMaxInLeft->m_nVal = tempVal;
	// 交换值完毕 接着就是把 pMaxInLeft 给删掉
	// 它可能是叶子节点 也 可能是单分支
	// 如果他是叶子节点
	if (pMaxInLeft->m_pLeft == nullptr && pMaxInLeft->m_pRight == nullptr) {
		DeleteLeaf(pMaxInLeft);
		return true;
	}
	// 如果它是单分支
	else{
		DeleteSingle(pMaxInLeft);
		return true;
	}
}

/*
	根据原本的值找到节点
	然后进行更新
*/
bool AVL::Update(int nSrcVal, int nDstVal)
{
	/*
		先删除再插入即可
	*/
	if(Find(nSrcVal)){
		Delete(nSrcVal);
		Insert(nDstVal);
	}
	return false;
}

/*
	根据值查找是否有这个节点存在
*/
bool AVL::Find(int nVal)
{
	if (this->m_pRoot == nullptr) {
		// 如果是空树查找失败
		return false;
	}
	// 如果不是空树开始遍历
	PNODE pNode = this->m_pRoot;
	while(true){
		if(nVal < pNode->m_nVal){
			// 如果小于 向左边
			if(pNode->m_pLeft == nullptr){
				// 左边没有了
				return false; // 那就是没有找到
			}else{
				// 如果左边还有 向左边移动
				pNode = pNode->m_pLeft;
			}
		}else if(nVal > pNode->m_nVal){
			// 如果大于 向右边
			if(pNode->m_pRight == nullptr){
				// 右边没有了
				return false; // 那就是没有了
			}else{
				// 如果还有 向右边移动继续找
				pNode = pNode->m_pRight;
			}
		}else{
			// 相等
			return true;
		}
	}
	return false;
}

/*
	根据值查找节点
	如果找到了返回节点对应的指针
*/
AVL::PNODE AVL::FindNode(int nVal)
{
	/*
		根据值查找返回结点
	*/
	// 如果不是空树 从根节点开始
	PNODE pNode = this->m_pRoot;
	while (pNode != nullptr){ 
		// 小于找左边
		if(nVal < pNode->m_nVal){
			pNode = pNode->m_pLeft;
			// 大于找右边
		}else if(nVal > pNode->m_nVal){
			pNode = pNode->m_pRight;
		}else{
			// 相等直接返回
			return pNode;
		}
	}
	// 如果退出循环了那就是找不到
	return nullptr;
}

void AVL::Clear()
{
	while (this->m_pRoot != nullptr){
		Delete(this->m_pRoot->m_nVal);
	}
}

// 层序遍历
void AVL::LevelTraversal()
{
	/*
		通过队列完成层序遍历
	*/
	deque trees;
	if (this->m_pRoot == nullptr){
		cout << "空树" << endl;
		return;
	}
	/*
		根节点入队
		然后出队 打印,再依次把左右两边入队
		循环此操作
	*/
	trees.push_back(this->m_pRoot);
	while(!trees.empty()){
		// 获取队首
		auto temp = trees.front();
		// 弹出队首
		trees.pop_front();
		cout << temp->m_nVal <<  " ";
		// 把左右两边入队
		if(temp->m_pLeft != nullptr){
			trees.push_back(temp->m_pLeft);
		}
		if (temp->m_pRight != nullptr) {
			trees.push_back(temp->m_pRight);
		}
	}
	cout << endl;
}

// 前序遍历 根左右
void AVL::MLR()
{
	if (this->m_pRoot == nullptr) {
		cout << "空树" << endl;
		return;
	}
	MLR(this->m_pRoot);
}

// 中序遍历 左根右
void AVL::LMR()
{
	if (this->m_pRoot == nullptr) {
		cout << "空树" << endl;
		return;
	}
	LMR(this->m_pRoot);
}

// 后序遍历 左右根
void AVL::LRM()
{
	if (this->m_pRoot == nullptr) {
		cout << "空树" << endl;
		return;
	}
	LRM(this->m_pRoot);
}

// 中序使用循环
void AVL::LMP_LOOP()
{
	if (this->m_pRoot == nullptr) {
		cout << "空树" << endl;
		return;
	}
	LMP_LOOP(this->m_pRoot);
}

// 前序使用循环
void AVL::MLR_LOOP()
{
	if (this->m_pRoot == nullptr) {
		cout << "空树" << endl;
		return;
	}
	MLR_LOOP(this->m_pRoot);
}

// 后序使用循环
void AVL::LRM_LOOP()
{
	if (this->m_pRoot == nullptr) {
		cout << "空树" << endl;
		return;
	}
	LRM_LOOP(this->m_pRoot);
}

// 中序遍历 左根右
void AVL::LMR(PNODE pNode)
{
	// 开始递归
	if(pNode != nullptr){
		LMR(pNode->m_pLeft);
		cout << pNode->m_nVal << " ";
		LMR(pNode->m_pRight);
	}
}

// 前序遍历 根左右
void AVL::MLR(PNODE pNode)
{
	// 开始递归
	if (pNode != nullptr) {
		cout << pNode->m_nVal << " ";
		MLR(pNode->m_pLeft);
		MLR(pNode->m_pRight);
	}
}

// 后序遍历 左右根
void AVL::LRM(PNODE pNode)
{
	// 开始递归
	if (pNode != nullptr) {
		LRM(pNode->m_pLeft);
		LRM(pNode->m_pRight);
		cout << pNode->m_nVal << " ";
	}
}

// 中序使用循环
void AVL::LMP_LOOP(PNODE pNode)
{
	// 换行
	cout << endl;
	// 定义一个栈
	stack treesStack;
	// 根节点入栈
	treesStack.push(pNode);
	// 当栈不为空的时候
	while (!treesStack.empty()){
		if(pNode->m_pLeft != nullptr){
			// 如果左边不为空入栈
			treesStack.push(pNode->m_pLeft);
			pNode = pNode->m_pLeft;
			continue; // 直接进入下一次循环
		}
		// 如果左边为空 从栈里面取出来
		auto curNode = treesStack.top(); // 获取栈顶元素
		cout << curNode->m_nVal << " "; // 输出栈顶元素
		treesStack.pop(); // 弹出栈顶元素
		// 如果有右孩子 右孩子入栈
		if(curNode->m_pRight != nullptr){
			treesStack.push(curNode->m_pRight);
			pNode = curNode->m_pRight;
			continue;
		}
	}
}

// 前序使用循环
void AVL::MLR_LOOP(PNODE pNode)
{
	// 换行
	cout << endl;
	// 定义一个栈
	stack treesStack;
	/*
		一路向左输出根,如果根有右孩子 右孩子入栈
		如果输出之后没有右孩子
		右孩子出栈
		接着右孩子作为根 重复上面操作
	*/
	while(true){
		// 当前节点不为空的话
		while(pNode != nullptr){
			// 输出根的值
			cout << pNode->m_nVal << " ";
			// 判断有没有右孩子
			if(pNode->m_pRight != nullptr){
				// 入栈
				treesStack.push(pNode->m_pRight);
			}
			// 往左走
			pNode = pNode->m_pLeft;
		}

		// 如果栈为空了 遍历结束
		if (treesStack.empty()) {
			break;
		}

		// 退出这个循环就是左边为空了 需要从栈里面取出来一个
		// 如果左边为空 从栈里面取出来
		// 同时当前根节点修改为弹出来的这个元素
		pNode = treesStack.top(); // 获取栈顶元素
		treesStack.pop(); // 弹出栈顶元素
	}
}

// 后序使用循环
void AVL::LRM_LOOP(PNODE pNode)
{
	// 换行
	cout << endl;
	// 定义一个栈
	stack treesStack;
	// 记录最后一次输出的值
	PNODE pLastHandledNode = nullptr;

	while(true){

		// 一路向左入栈
		while(pNode != nullptr){
			treesStack.push(pNode);
			pNode = pNode->m_pLeft;
		}

		// 栈为空
		if(treesStack.empty()){
			break;
		}

		// 这样就左边全部入栈完毕了 访问栈顶
		auto curNode = treesStack.top();

		if(curNode->m_pRight == pLastHandledNode || curNode->m_pRight == nullptr){
			// 如果上一次输出的就是它的右节点 或者它没有右节点 那么它就可以处理了
			cout << curNode->m_nVal << " ";
			treesStack.pop(); // 出栈
			pLastHandledNode = curNode; // 更新上一次输出的节点
		}else{
			// 否则把处理右节点
			pNode = curNode->m_pRight;
		}
		
	}
}

#include 
#include 
#include "AVL.h"

using namespace std;

int main()
{

	int ary[] = {
		50,
		20,80,
		10,40,60,120,
		30,55,70,110,130,
		56
	};
	AVL avl;
	for (int i = 0; i < sizeof(ary) / sizeof(ary[0]); i++) {
		avl.Insert(ary[i]);
	}

	avl.Delete(56);
	avl.Delete(40);
	avl.Delete(20);

	avl.LMP_LOOP();

	system("pause");
	return 0;
}

你可能感兴趣的:(C语言,c++,开发语言,后端)