Raíz del árbol AVL (establecimiento del árbol binario equilibrado)

Prólogo

Establecer un árbol balanceado binario basado en la secuencia de inserción y generar el nodo raíz es en realidad investigar si se puede dominar el proceso de establecer un árbol balanceado binario. Esta pregunta se escribió el año pasado, pero se ha quedado estancada, finalmente se escribió esta vez, y realmente vi algunas operaciones muy delicadas , ya sea un proceso de ajuste o de inserción.

Descripción del título

Un árbol AVL es un árbol de búsqueda binaria con equilibrio automático. En un árbol AVL, las alturas de los dos subárboles secundarios de cualquier nodo difieren en como máximo uno; si en algún momento difieren en más de uno, se realiza un reequilibrio para restaurar esta propiedad. Las Figuras 1-4 ilustran las reglas de rotación.
Ahora, dada una secuencia de inserciones, se supone que debe indicar la raíz del árbol AVL resultante.
LL 型
Tipo RR
Tipo RL
Tipo LR

Formato de entrada

Cada archivo de entrada contiene un caso de prueba. Para cada caso, la primera línea contiene un número entero positivo N (≤20) que es el número total de claves que se insertarán. Luego se dan N claves enteras distintas en la siguiente línea. Todos los números en una línea están separados por un espacio.

Formato de salida

Para cada caso de prueba, imprima la raíz del árbol AVL resultante en una línea.

Muestra

Ejemplo de entrada 1

5
88 70 61 96 120

Salida de muestra 1

70

Muestra de entrada 2

7
88 70 61 96 120 90 65

Salida de muestra 2

88

Ideas

emmmm ... Introduce brevemente el árbol binario balanceado. Es un árbol de búsqueda binario . La diferencia de altura entre los subárboles izquierdo y derecho de cualquier nodo no excede 1. El propósito de equilibrar árboles binarios es lograr la mayor eficiencia de búsqueda.
El proceso de ajuste no se introducirá ...
y luego el proceso de construir un árbol binario equilibrado.
El proceso de construcción de un árbol binario equilibrado se basa principalmente en la inserción, el proceso de inserción es el mismo que el proceso de búsqueda de un árbol binario, pero después de cada inserción , se debe agregar un paso de ajuste , ya que cada inserción puede hacer que esté desequilibrado. Una vez completado el establecimiento, se puede generar el nodo raíz.
Exquisito en la parte del código.

Lograr

Código completo

#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;
}

Estructura de almacenamiento

La cadena de almacenamiento más común.

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

} Node;

Proceso de ajuste

Corresponde a cuatro tipos de condiciones de desequilibrio: LL, LR, RR, RL. Tenga en cuenta que lo que debe ajustarse aquí es el nodo no balanceado más cercano en el nodo de inserción, porque después de ajustar esto, los nodos no balanceados más alejados se equilibrarán.
Hay un truco en el proceso de implementación: LL y RR son situaciones básicas, mientras que LR y RL se pueden realizar mediante una combinación de dos operaciones básicas. Por ejemplo, en el caso de LR, primero puede realizar la operación RR en el nodo izquierdo del nodo desequilibrado. Luego realice la operación LL en el nodo no balanceado.
Hay un mejor truco, preste atención al proceso de ajuste aquí, la entrada es la dirección del nodo que se ajustará y el valor de retorno es la dirección del nodo raíz después del ajuste, para que pueda guardar muchas operaciones y evitar punteros al realizar el proceso de ajuste Algunos problemas causados ​​por dedos equivocados.

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);
}

Verificar desequilibrio

  1. Usa la recursividad para obtener altura
  2. Determine si el equilibrio se basa en la diferencia de altura entre los dos subárboles
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;
}

Insertar el proceso principal

¡Uso exquisito del proceso recursivo para lograr la inserción y el ajuste!

  1. Siempre que diseñe un caso básico como la implementación de la función de inserción, puede insertarlo cuando p = NULL está seleccionado aquí
  2. Debido a que la recursión se toca primero y se devuelve capa por capa, cuando la capa se devuelve al nodo raíz para su juicio después de que se ejecuta el proceso de inserción, debe ser el primero en tocar el árbol de desequilibrio mínimo y hacer ajustes, de modo que la recursión después del ajuste Los nodos externos (es decir, los nodos que están más lejos del nodo de inserción en el árbol) deben haber sido equilibrados, utilizando la naturaleza recursiva de manera inteligente
  3. Tenga en cuenta que los parámetros pasados ​​por la función recursiva son un puntero de nodo y una palabra clave. Al realizar ajustes, el nodo entrante t es el puntero que se debe ajustar. En este momento, el contenido de t necesita ser cambiado. Aquí, t debería usar una referencia, porque t es en realidad un nodo hijo del nodo de la capa superior, Por lo tanto, debe usar referencias para asegurarse de que puede cambiar, no solo pasar valores, lo que no tiene sentido. En este momento, combinado con la función de ajuste, puede lograr el propósito de cambiar el puntero de nodo. (Es confuso ...
    Nota: no necesita una referencia, solo necesita devolver el valor como un puntero, para que pueda cambiar el puntero de la función que se pasa a la función como referencia sin cambio de referencia. Actualice esta versión si tiene tiempo.
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;
}

Supongo que te gusta

Origin www.cnblogs.com/Za-Ya-Hoo/p/12725387.html
Recomendado
Clasificación