Root of AVL Tree (Establishment of Binary Balanced Tree)

Foreword

Establishing a binary balanced tree based on the insertion sequence and outputting the root node is actually to investigate whether the process of establishing a binary balanced tree can be mastered. This question was written last year, but it has been stuck. It was finally written this time, and I really saw some very delicate operations, whether it is adjustment or insertion.

Title description

An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.
LL型
RR type
RL type
LR type

Input format

Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

Output format

For each test case, print the root of the resulting AVL tree in one line.

Sample

Input example 1

5
88 70 61 96 120

Sample output 1

70

Input sample 2

7
88 70 61 96 120 90 65

Sample output 2

88

Ideas

emmmm ... Briefly introduce the balanced binary tree. It is such a binary search tree . The height difference between the left and right subtrees of any node does not exceed 1. The purpose of balancing binary trees is to achieve the highest search efficiency.
The adjustment process will not be introduced ...
and then the process of building a balanced binary tree.
The process of building a balanced binary tree is mainly based on insertion. The insertion process is the same as the process of searching for a binary tree, but after each insertion , an adjustment step must be added , because each insertion may make it unbalanced. After the establishment is completed, the root node can be output.
Exquisite in the code part.

achieve

Complete code

#include<iostream>
using namespace std;

typedef struct Node{
	int data;
	struct Node* lchild;
	struct Node* rchild;

} Node;

int myHeight(Node * t) {
	if (t == NULL)
		return 0;
	else {
		int l = myHeight(t->lchild);
		int r = myHeight(t->rchild);
		return (l > r ? l : r) + 1;			//一定要加括号,注意优先级的问题
	}
}

bool myIsBalance(Node *t) {
	int l = myHeight(t->lchild);
	int r = myHeight(t->rchild);
	if (l - r <= 1 && l - r >= -1)
		return true;
	else
		return false;
}

Node* LL(Node* root) {
	Node *p = root->lchild;
	root->lchild = p->rchild;
	p->rchild = root;
	return p;				//返回新的根结点
}

Node* RR(Node* root) {
	Node* p = root->rchild;
	root->rchild = p->lchild;
	p->lchild = root;
	return p;
}

Node* LR(Node* root) {
	root->lchild = RR(root->lchild);
	return LL(root);
}

Node* RL(Node* root) {
	root->rchild = LL(root->rchild);
	return RR(root);
}

Node* myNewNode(int key) {
	Node *p = new Node;
	p->lchild = NULL;
	p->rchild = NULL;
	p->data = key;
	return p;
}

void myInsert(Node *&t, int key) {			
	if (t == NULL)
		t = myNewNode(key);
	else {
		if (key > t->data) {			
			myInsert(t->rchild, key);       
			if (myIsBalance(t) == false) {		
 				if (key > t->rchild->data)		
					t = RR(t);
				else										
					t = RL(t);
			}
		}
		else {
			myInsert(t->lchild, key);
			if (myIsBalance(t) == false) {
				if (key < t->lchild->data)
					t = LL(t);
				else
					t = LR(t);
			}
		}
	}
	return;
}


int main() {                    //主函数
	Node* tree = NULL;
	int num;
	cin >> num;
	for (int i = 0; i < num; i++) {                //逐个插入即可
		int temp;
		cin >> temp;
 		myInsert(tree, temp);                 //插入函数(包括调整)
	}
	cout << tree->data;
	return 0;
}

Storage structure

The most common chain storage

typedef struct Node{
	int data;
	struct Node* lchild;
	struct Node* rchild;

} Node;

Adjustment process

Corresponding to four kinds of imbalance conditions: LL, LR, RR, RL. Note that what needs to be adjusted here is the closest unbalanced node in the insertion node, because after adjusting this, the unbalanced nodes further away will become balanced.
There is a trick in the implementation process. LL and RR are basic situations, while LR and RL can be realized by a combination of two basic operations. Then perform LL operation on the unbalanced node.
There is a better trick, pay attention to the adjustment process here, the input is the address of the node to be adjusted, and the return value is the address of the root node after adjustment, so that many operations can be saved during the adjustment process, avoiding pointer Some problems caused by wrong fingers.

Node* LL(Node* root) {
	Node *p = root->lchild;
	root->lchild = p->rchild;
	p->rchild = root;
	return p;				//返回新的根结点
}

Node* RR(Node* root) {
	Node* p = root->rchild;
	root->rchild = p->lchild;
	p->lchild = root;
	return p;
}

Node* LR(Node* root) {
	root->lchild = RR(root->lchild);
	return LL(root);
}

Node* RL(Node* root) {
	root->rchild = LL(root->rchild);
	return RR(root);
}

Check for imbalance

  1. Use recursion to get height
  2. Determine whether the balance is based on the height difference between the two subtrees
int myHeight(Node * t) { 
	if (t == NULL)
		return 0;
	else {
		int l = myHeight(t->lchild);
		int r = myHeight(t->rchild);
		return (l > r ? l : r) + 1;			//一定要加括号,注意优先级的问题
	}
}

bool myIsBalance(Node *t) {
	int l = myHeight(t->lchild);
	int r = myHeight(t->rchild);
	if (l - r <= 1 && l - r >= -1)
		return true;
	else
		return false;
}

Insert the main process

Exquisite use of recursive process to achieve insertion and adjustment!

  1. As long as you design a basic case as the implementation of the insertion function, you can insert it when p = NULL is selected here
  2. Because the recursion is bottomed first and returned layer by layer, when the layer is returned to the root node for judgment after the insertion process is executed, it must be the first to touch the minimum imbalance tree and adjust it, so that the recursion after adjustment The outer nodes (that is, the nodes that are further away from the insertion node in the tree) must have been balanced, using the recursive nature cleverly
  3. Note that the parameters passed in by the recursive function are a node pointer and a keyword. When making adjustments, the incoming node t is the pointer to be adjusted. At this time, the content of t needs to be changed. Here, t should use a reference, because t is actually a child node of the upper layer node, Therefore, you must use references to ensure that you can change, not just pass in values, which is meaningless. At this time, combined with the adjustment function, you can achieve the purpose of changing the node pointer. (It's confusing ...
    Note: You don't need a reference, you just need to return the value as a pointer, so you can change the pointer of the pointer passed into the function as a reference without changing the reference. Update this version if you have time.
Node* myNewNode(int key) {
	Node *p = new Node;
	p->lchild = NULL;
	p->rchild = NULL;
	p->data = key;
	return p;
}

void myInsert(Node *&t, int key) {			//未曾设想的道路,精妙!
	if (t == NULL)                                  //基本情况(base case)
		t = myNewNode(key);
	else {
		if (key > t->data) {			//默认插在了右边,所以如果不平衡只需要考虑右边的情况即可,即RL、RR,下同
			myInsert(t->rchild, key);       //精妙的是,因为是递归插入的,所以最先被检查到的肯定是最靠近插入结点的,即最近失衡树
			if (myIsBalance(t) == false) {	//检查插入之后是否失衡
 				if (key > t->rchild->data)		
                                 //要么就是在右边的右边,不能用key == rchild->rchild->data判断,因为哪怕是最近失衡结点,也有可能离插入结点超过两层,这里选择使用大小判断正是利用了二叉搜索树的性质
					t = RR(t);      //因为这个赋值语句直接改变了t的指向,所以在传参时,必须要使用引用才行
				else											
					t = RL(t);
			}
		}    
		else {
			myInsert(t->lchild, key);
			if (myIsBalance(t) == false) {
				if (key < t->lchild->data)
					t = LL(t);
				else
					t = LR(t);
			}
		}
	}
	return;
}

Guess you like

Origin www.cnblogs.com/Za-Ya-Hoo/p/12725387.html