導入
前に書いたバイナリ・ソートツリーは、建物は完全に順序を注文された場合、バイナリ・ソートツリーを構築し、このような状況が発生します。
明らかに、このような状況は、リンクされたリストの中に二分探索木の縮退を行います。これが起こるとき、それは線形検索に権限委譲バイナリ・ソート木、のための外観は、私たちは、バイナリ・ソートツリーの形を合理化する必要があり、できるだけ多くの木の各ノードは、そのため、2つの子ノードを有するように全体二分木の高さは約あろう(ログ(N)\)\、その\(\ N-)はノードの数です。
基本プロパティ
AVL木はまた、平衡二分木として知られ、自己均衡バイナリ・ソートツリーで、本質的にはまだバイナリ・ソートツリーですが、要件「バランス」を追加し、バランスはAVL木の上の任意のノードを指し、 (バランス係数と呼ばれる)は、2つの部分木の高さの差の絶対値が超えていない\(1 \)を。これは、木の上、AVL高さに留まることができるようになります確保することである\(O(LOGN)\)レベル。
データ構造の定義
各ノードは、因子でバランスされている必要があるため、これAVLツリー構造内の変数を追加しheight
、現在のノードを記録するために使用されるサブツリーの高さのルートです。
typedef struct Node
{
char data;
int height;
struct Node* Left;
struct Node* Right;
}*AVLTree;
取得しroot
たノードの高さ:
int getHeight(Node *root){
if(!root) return 0;//空节点高度为0
return root->height;
}
基本操作
求めます
AVL木は二分探索木なので、同じバイナリ検索ツリーと検索操作です。AVL木の高さがある(O(LOGN)\)\検索動作時間複雑であるので、レベル、(O(LOGN)\)\。
あなたは、二分探索木とまったく同じコードを取得することができます:
//找不到返回NULL,找到返回该节点。
//非递归
Node* Find(AVLTree t, int x) {
if (!t)return NULL;
if (t->data == x) return t;
if (x < t->data) return BSTreeFind(t->Left, x);
if (x > t->data) return BSTreeFind(t->Right, x);
}
//非递归
Node* Find(AVLTree T,int x) {
BSTree p = T;
while (p) {
if (x == p->data)
return p;
p = x > p->data ? p->Right : p->Left;
}
return NULL;
}
挿入
L
左の下のバイナリ・ソート木を見て、脇に挿入AVL木の問題を入れてください。私たちは、平和的な共存を持っていた、ある日突然、重量Bは反乱に、Aよりも大きいと感じますが、ルートノードBを行い、また、調整後の木はまだバイナリ・ソートの木であることを確認する必要があります。
☆Aより所有権にほとんど値は、Δの調整の位置を変えず、所有権にBより大きく、AにBの調整後に残った子供たちは、その後、▲のでA、他の場所に移動しなければならないので、値の関係右B、▲満たすA <▲<Bは、そう右の部分木であることができる▲なろう。
この調整プロセスは、以下のように呼ばれるL、分解プロセスは、以下のように調整されます。
コードは以下の通りであります:
void L(AVLTree *root){
Node* temp = (*root)->Right; //root指向结点A,temp指向结点B
(*root)->Right = temp->Left; //图示步骤2
temp->Left = *root; //图示步骤3
root->height = max(getHeight(root->Left), getHeight(root->Rihgt)) + 1;//更新结点A高度
temp = max(getHeight(temp->Left), getHeight(temp->Rihgt)) + 1;//更新结点B高度
*root = temp;//图示步骤4
}
右回りの
次のように右利き左利きは逆のプロセスは、次のとおりです。
次のように分解プロセスを調整すると、次のとおりです。
コードは以下の通りであります:
void R(AVLTree *root) {
Node* temp = (*root)->Left;//root指向结点B,temp指向结点A
(*root)->Left = temp->Right;
temp->Right = *root;
root->height = max(getHeight(root->Left), getHeight(root->Rihgt)) + 1;
temp = max(getHeight(temp->Left), getHeight(temp->Rihgt)) + 1;
*root = temp;
}
AVLツリーが変更され、次にノードバランス要因がある可能性があり、ノードがそれに挿入され、バランス係数の接続点が存在するであろう、今平衡二分木を持っていると仮定すると、次の挿入操作を議論しましたこのような不均衡は、バイナリツリーをバランスする場所サブツリーのルートノードへのノードが、アンバランスであるように、1よりも大きい場合、次の4つに分けることができます。
LL、RR型
Zuozuo(LL)、右右(RR)、LL、ツリー(挿入位置のバランスの喪失にツリーリード)は左利きされていないだけで、右利きの手段RR。
LL型のため、右利きのルートノードAでありする必要があります。
RRのルートノードの左にする必要があるタイプ。
以下のようにコードは次のとおりです。
void RR_Rotate(AVLTree *root){
L(root);
}
void LL_Rotate(AVLTree *root) {
R(root);
}
LR、RL型
右左左と右(LR)、(RL)。
LRタイプB必要がLのルートノードであるために、Aは、右利きのルートノードです。
右利きのルートノードであるRLタイプBの必要性のために、Aは左利き用のルート・ノードです。
void LR_Rotate(AVLTree *root) {
L(&(*root)->Left);
R(root);
}
void RL_Rotate(AVLTree *root) {
R(&(*root)->Right);
L(root);
}
挿入接合部
挿入アルゴリズムは、回転バランスのバイナリツリーの使用を必要とするように決定される不均衡状態である場合
AVLTree InsertAVLTree(AVLTree root, int x) {
if (root == NULL) {
root = new Node;
root->Left = NULL;
root->Right = NULL;
root->data = x;
return root;
}
if (x > root->data) {
//递归返回插入位置的父节点或者祖父……。
root->Right = InsertAVLTree(root->Right, x);
//如果插入之后失去了平衡
if (height(root->Left) - height(root->Right) == -2) {
//如果插入的值大于,当前节点的左孩子节点,说明该节点是插在root的右子树上的
if (x > root->Left->data) RR_Rotate(&root);
else RL_Rotate(&root);
}
}
else if (x < root->data) {
root->Left = InsertAVLTree(root->Left, x);
if (height(root->Left) - height(root->Right) == 2) {
if (x < root->Left->data) LL_Rotate(&root);
else LR_Rotate(&root);
}
}
else {
cout << "the number is already included." << endl;
return NULL;
}
return root;
}
[ノードの削除
ノードを削除すると、より外から判断削除ノード背の高い木のあるもの、ほとんどのバイナリツリーの並べ替えです。
void AVLTreeDel(AVLTree *root, int data)
{
if (!*root) {
cout << "delete failed" << endl;
return;
}
Node *p = *root;
if (data == p->data) {
//左右子树都非空
if (p->Left && p->Right) {
//在高度更大的那个子树上进行删除操作
//进左子树,右转到底,进右子树,左转到底,转弯碰壁,杀孩子。
if (height(p->Left) > height(p->Right)) {
Node *pre=NULL,*q = p->Left;
if (!q->Right)
q->Right = p->Right;
else {
while (q->Right) {
pre = q;
q = q->Right;
}
pre->Right = q->Left;
q->Left = p->Left;
q->Right = p->Right;
}
*root = q;
}
else {
Node *pre = NULL, *q = p->Right;
if (!q->Left)
q->Left = p->Left;
else {
while (q->Left) {
pre = q;
q = q->Left;
}
pre->Left = q->Right;
q->Left = p->Left;
q->Right = p->Right;
}
*root=q;
}
}
else
(*root) = (*root)->Left ? (*root)->Left : (*root)->Right;
delete p;
}
else if (data < p->data){//要删除的节点在左子树中
//在左子树中进行递归删除
AVLTreeDel(&(*root)->Left, data);
//判断是否仍然满足平衡条件
if (height(p->Right) - height(p->Left) == 2){
//如果当前节点右孩子的左子树更高
if (height(p->Right->Left) > height(p->Right->Right))
RL_Rotate(root);
else
RR_Rotate(root);
}
}
else{
AVLTreeDel(&(*root)->Right, data);
if (height(p->Left) - height(p->Right) == 2) {
if (height((*root)->Left->Left) > height((*root)->Left->Right))
LL_Rotate(root);
else
LR_Rotate(root);
}
}
}
完全なテストコード:
#pragma once
#include "top.h"
typedef BTreeNode Node, *AVLTree;
void RR_Rotate(AVLTree *root){
Node* Right = (*root)->Right;
(*root)->Right = Right->Left;
Right->Left = *root;
*root = Right;
}
void LL_Rotate(AVLTree *root) {
Node* Left = (*root)->Left;
(*root)->Left = Left->Right;
Left->Right = *root;
*root = Left;
}
void LR_Rotate(AVLTree *root) {
RR_Rotate(&(*root)->Left);
return LL_Rotate(root);
}
void RL_Rotate(AVLTree *root) {
LL_Rotate(&(*root)->Right);
RR_Rotate(root);
}
AVLTree AVLTreeInsert(AVLTree root, int x) {
if (root == NULL) {
root = new Node;
root->Left = NULL;
root->Right = NULL;
root->data = x;
return root;
}
if (x > root->data) {
root->Right = AVLTreeInsert(root->Right, x);
//递归返回插入位置的父节点或者祖父……,如果失去了平衡
if (height(root->Left) - height(root->Right) == -2) {
//如果插入的值大于,当前节点的右孩子节点,说明该节点是插在root的右子树上的
//if (x > root->Left->data) RR_Rotate(&root);不能保证该节点一定有左子树
if (x > root->Right->data)RR_Rotate(&root);
else RL_Rotate(&root);
}
}
else if (x < root->data) {
root->Left = AVLTreeInsert(root->Left, x);
if (height(root->Left) - height(root->Right) == 2) {
if (x < root->Left->data) LL_Rotate(&root);
else LR_Rotate(&root);
}
}
else {
cout << "the number is already included." << endl;
return NULL;
}
return root;
}
AVLTree AVLTreeCreat(int *a, int length) {
AVLTree T = NULL;
for (int i = 0; i < length; i++) {
T = AVLTreeInsert(T, a[i]);
}
return T;
}
Node* AVLFind(AVLTree T, int x) {
Node *p = T;
while (p) {
if (x == p->data) break;
p = x > p->data ? p->Right : p->Left;
}
return p;
}
AVLTree AVLMax(AVLTree p)
{
if (!p) return NULL;
if (p->Right == NULL)
return p;
return AVLMax(p->Right);
}
AVLTree AVLMin(AVLTree p)
{
if (!p)
return NULL;
if (p->Left == NULL)
return p;
return AVLMin(p->Left);
}
void AVLTreeDel(AVLTree *root, int data)
{
if (!*root) {
cout << "delete failed" << endl;
return;
}
Node *p = *root;
if (data == p->data) {
//左右子树都非空
if (p->Left && p->Right) {
//在高度更大的那个子树上进行删除操作
//进左子树,右转到底,进右子树,左转到底,转弯碰壁,杀孩子。
if (height(p->Left) > height(p->Right)) {
Node *pre=NULL,*q = p->Left;
if (!q->Right)
q->Right = p->Right;
else {
while (q->Right) {
pre = q;
q = q->Right;
}
pre->Right = q->Left;
q->Left = p->Left;
q->Right = p->Right;
}
*root = q;
}
else {
Node *pre = NULL, *q = p->Right;
if (!q->Left)
q->Left = p->Left;
else {
while (q->Left) {
pre = q;
q = q->Left;
}
pre->Left = q->Right;
q->Left = p->Left;
q->Right = p->Right;
}
*root=q;
}
}
else
(*root) = (*root)->Left ? (*root)->Left : (*root)->Right;
delete p;
}
else if (data < p->data){//要删除的节点在左子树中
//在左子树中进行递归删除
AVLTreeDel(&(*root)->Left, data);
//判断是否仍然满足平衡条件
if (height(p->Right) - height(p->Left) == 2){
//如果当前节点右孩子的左子树更高
if (height(p->Right->Left) > height(p->Right->Right))
RL_Rotate(root);
else
RR_Rotate(root);
}
}
else{
AVLTreeDel(&(*root)->Right, data);
if (height(p->Left) - height(p->Right) == 2) {
if (height((*root)->Left->Left) > height((*root)->Left->Right))
LL_Rotate(root);
else
LR_Rotate(root);
}
}
}
int height(BTree L) {
if (L == NULL)
return 0;
int left = height(L->Left);
int right = height(L->Right);
return left >= right ? left + 1 : right + 1;
}
void checkCreat() {
int length = 10;
int *a = getNoRepateRandomArray(length, 10);
for (int i = 0; i < length; i++) {
cout << a[i] << ",";
}
cout << endl;
AVLTree T = AVLTreeCreat(a, length);
int t = rand() % length;
AVLTreeDel(&T, a[t]);
for (int i = t; i < length - 1; i++) {
a[i] = a[i + 1];
}
Preorder(T);
cout << endl;
Inorder(T);
cout << endl;
Postorder(T);
cout << endl;
free(a);
}