平衡二叉树相关算法

最近更新于 2022-10-09, 发布于 2022-10-07

0. 数据结构

typedef struct AVLNode {
	int bf_ = 0;
	int data_ = 0;
	AVLNode* lchild_ = nullptr;
	AVLNode* rchild_ = nullptr;
} AVLNode, *AVLTree;

1. 构造函数

1.1. 计算结点的平衡因子

这里并不要求 tree 已经是平衡二叉树.

int buildBalanceFactor(AVLTree tree)
{
	// Deal with empty tree;
	if (tree == nullptr) {
		return 0; 
	}

	// Now non-empty tree;
	// If leaf;
	if (tree->lchild_ == nullptr && tree->rchild_ == nullptr) {
		tree->bf_ = 0;
		return 1;
	}
	// Now non-leaf node;
	int hL = buildBalanceFactor(tree->lchild_);
	int hR = buildBalanceFactor(tree->rchild_);
	tree->bf_ = hL - hR; 
	return (hL > hR) ? hL + 1 : hR + 1; 
}

1.2. 构造 AVL 树 (控制台输入)

#include <stack>

#include <vector>

using std::stack;
using std::pair;
using AVLpair = pair<AVLNode*, bool>;

// result = {
//				{ B, ubFlag }, 
//				{ A, ubFlag }, 
//				{ R, ubFlag }
//			}
// 
//         R		->head
//        /
//       A			->rootOfMinimalUBTree
//      / \
//     B   ...		->UBChildOfRoot
//    /				->C is on the l(r)childtree of B,
//   ...			//so result == false(true);
//   ...
//  /
// C				->newNode
// Notice that B and C will never be the same node,
// otherwise A could not be unbalanced;
// Therefore, mov.second indicates where newNode inserted on B;

static int buildBalanceFactor(AVLTree tree)
{
	// Deal with empty tree;
	if (tree == nullptr) {
		return 0;
	}

	// Now non-empty tree;
	// If leaf;
	if (tree->lchild_ == nullptr && tree->rchild_ == nullptr) {
		tree->bf_ = 0;
		return 1;
	}
	// Now non-leaf node;
	int hL = buildBalanceFactor(tree->lchild_);
	int hR = buildBalanceFactor(tree->rchild_);
	tree->bf_ = hL - hR;
	return (hL > hR) ? hL + 1 : hR + 1;
}

static void setChild(AVLpair& pr, AVLTree node)
{
	if (!pr.second) {
		pr.first->lchild_ = node;
	}
	else {
		pr.first->rchild_ = node;
	}

	return;
}

static void singleLRot(AVLTree root)
{
	AVLNode* list[2] = { root->rchild_, root };

	list[1]->rchild_ = list[0]->lchild_;
	list[0]->lchild_ = list[1];

	return;
}

static void singleRRot(AVLTree root)
{
	AVLNode* list[2] = { root->lchild_, root };

	list[1]->lchild_ = list[0]->rchild_;
	list[0]->rchild_ = list[1];

	return;
}

AVLTree buildAVL(void)
{
	std::cout << "An AVL tree is being built. " << std::endl;
	std::cout << "Enter the data in the node after prompting, " << std::endl;
	std::cout << "or enter any non-digit-or-whitespace character to exit. " << std::endl;

	int cache = 0;
	AVLTree tree = nullptr;
	if (scanf("%d", &cache) != 1) {
		return tree;
	}
	// Now root available;
	tree = new AVLNode;
	tree->data_ = cache;

	AVLNode* newNode = nullptr;
	AVLNode* mov = nullptr; 
	stack<AVLpair> stk = {};

	while (scanf("%d", &cache) == 1) {
		// init newNode;
		newNode = new AVLNode; 
		newNode->data_ = cache;

		// insert newNode;
		stk = {}; 
		mov = tree;
		while (mov != nullptr && mov->data_ != cache) {
			stk.push({ mov, (mov->data_ > cache) ? false : true });
			mov = (mov->data_ > cache) ? mov->lchild_ : mov->rchild_;
		}
		if (mov != nullptr) { // i.e. mov->data == cache;
			printf("There is an existing node with data %d. \n", cache);
			continue;
		}
		// Now mov == nullptr and cache is a new value for tree;
		// Now stk has recorded the path of insertation;
		mov = stk.top().first;
		if (mov->data_ > cache) {
			mov->lchild_ = newNode;
		}
		else {
			mov->rchild_ = newNode;
		}
		stk.push({ newNode, false });

		// recompute balance factor;
		buildBalanceFactor(tree);

		// Find the minimal unbalanced tree;
		// init;
		AVLpair* ubList = new AVLpair[3];
		for (size_t index = 0; index < 3; ++index) {
			ubList[index] = AVLpair(nullptr, false);
		}
		// search;
		AVLpair movTop = stk.top();
		stk.pop();
		AVLpair curTop = stk.top();
		while (!stk.empty()) {
			if (curTop.first->bf_ < -1 || curTop.first->bf_ > 1) {
				ubList[0] = movTop;
				ubList[1] = curTop;

				stk.pop();
				ubList[2] = stk.empty() ? AVLpair(nullptr, false) : stk.top();

				break;
			}

			movTop = curTop;
			stk.pop();
			curTop = stk.empty() ? AVLpair(nullptr, false) : stk.top();
		}

		// In case that root.first is the root of tree;
		bool headNull = false; 
		if (ubList[2].first == nullptr) {
			headNull = true;
			ubList[2].first = new AVLNode;
			ubList[2].first->lchild_ = ubList[1].first;
		} // if headNull is true, the pointer `tree` needs to be redirected;

		// node adjustment;
		if (ubList[1].first != nullptr) {
			// LL rotation (right single rot.)
			if (!ubList[1].second && !ubList[0].second) {
				singleRRot(ubList[1].first);

				if (headNull) {
					tree = ubList[1].first;
				}
				else {
					setChild(ubList[2], ubList[0].first);
				}
			}
			// RR rotation (left single rot.)
			else if (ubList[1].second && ubList[0].second) {
				singleLRot(ubList[1].first);

				if (headNull) {
					tree = ubList[1].first;
				}
				else {
					setChild(ubList[2], ubList[0].first);
				}
			}
			// LR rotation (left-right rot.)
			else if (!ubList[1].second && ubList[0].second) {
				AVLNode* newRoot = ubList[0].first->rchild_;
				setChild(ubList[1], ubList[0].first->rchild_);
				singleLRot(ubList[0].first);
				singleRRot(ubList[1].first);

				if (headNull) {
					tree = newRoot;
				}
				else {
					setChild(ubList[2], newRoot);
				}
			}
			// RL rotation (right-left rot.)
			else if (ubList[1].second && !ubList[0].second) {
				AVLNode* newRoot = ubList[0].first->lchild_;
				setChild(ubList[1], ubList[0].first->lchild_);
				singleRRot(ubList[0].first);
				singleLRot(ubList[1].first);

				if (headNull) {
					tree = newRoot;
				}
				else {
					setChild(ubList[2], newRoot);
				}
			}
		}

		// recompute balance factor;
		buildBalanceFactor(tree);
	}

	return tree;
}

2. AVL 树的高度

2.1. 递归法

int getHeight(AVLTree tree)
{
	if (tree == nullptr) {
		return 0;
	}

	return (tree->bf_ > 0 ? getHeight(tree->lchild_) : getHeight(tree->rchild_)) + 1;
}

2.2. 非递归法

int getHeight(AVLTree tree)
{
	AVLNode* mov = tree;
	int height = 0;

	while (mov != nullptr) {
		mov = (mov->bf_ > 0 ? mov->lchild_ : mov->rchild_);
		++height;
	}

	return height;
}

附录

重要内容更新日志

2022-10-09 添加了 AVL 树的构造函数AVL 树高的求法.