AVL樹原理及實現(C語言實現以及Java語言實現)

歡迎探討,若有錯誤敬請指正 html

如需轉載,請註明出處http://www.cnblogs.com/nullzx/ java

1. AVL定義

AVL樹是一種改進版的搜索二叉樹。對於通常的搜索二叉樹而言,若是數據剛好是按照從小到大的順序或者從大到小的順序插入的,那麼搜索二叉樹就對退化成鏈表,這個時候查找,插入和刪除的時間都會上升到O(n),而這對於海量數據而言,是咱們沒法忍受的。即便是一顆由徹底隨機的數據構形成的搜索二叉樹,從統計角度去分析,在進行若甘次的插入和刪除操做,這個搜索二叉樹的高度也不能使人滿意。這個時候你們就但願能有一種二叉樹解決上述問題。這個時候就出現平衡搜索二叉樹,它的基本原理就是在插入和刪除的時候,根據狀況進行調整,以下降二叉樹的高度。平衡搜索二叉樹典型表明就是AVL樹和紅黑樹。 ide

AVL樹:任何一個節點的左子支高度與右子支高度之差的絕對值不超過1。須要咱們注意的是,AVL樹定義不是說從根節點到葉子節點的最短距離比最長短距離大1。 函數

image

上圖就是一顆AVL樹,從根節點到葉子節點的最短距離是5,最長距離是9。 測試

 

2. 旋轉的定義

由於每種書中對旋轉的定義不一致,因此咱們有必要在這裏特此說明一下 this

以某一個節點爲軸,它的左子枝順時針旋轉,做爲新子樹的根,咱們稱之爲順時針旋轉(clockwise)或者右旋轉 3d

同理,以某一個節點爲軸,它的右子枝逆針旋轉,做爲新子樹的根,咱們稱之爲逆時針旋轉(anticlockwise)或者左旋轉 指針

 

3. AVL插入操做

AVL樹的插入操做首先會按照普通搜索二叉樹的插入操做進行,當插入一個數據後,咱們會沿着插入數據時所通過的的節點回溯,回溯的過程當中會判回溯路徑中的每一個節點的左子支高度與右子支高度之差的絕對值是否超過1,若是超過1咱們就進行調整,調整的目的是使得該節點知足AVL樹的定義。調整的狀況能夠分爲如下四旋轉操做,旋轉操做能夠下降樹的高度,同時不改變搜索二叉樹的性質(即任何一個節點左子支中的所有節點小於該節點,右子支的所有節點大於該節點)。 調試

3.1 狀況1

節點X左子支比右子支高度大2,且插入的節點位於X的左孩子節點XL的左子支上 htm

image

3.2 狀況2

節點X右子支比左子支高度大2,且插入的節點位於節點X右孩子節點XR的右子支上

image

3.3 狀況3

節點X左子支比右子支高度大2,且插入的節點位於節點X左孩子節點XL的右子支上

image

3.4 狀況4

節點X左子支比右子支高度大2,且插入的節點位於節點X左孩子節點XL的右子支上

 

image

4. AVL刪除操做

AVL樹的刪除操做和插入操做同樣,首先會按照普通搜索二叉樹的刪除操做進行,當刪除一個數據後,和插入操做同樣,咱們一般採起的策略是沿着刪除數據時所通過的的節點回溯,回溯的過程當中會判斷該節點的左子支高度與右子支高度之差的絕對值是否超過1(或者說大2),若是超過1,咱們就進行調整,調整的目的是使得該節點知足AVL樹的定義。調整的狀況能夠分爲四種,和插入過程徹底同樣,這裏不在贅述。

5. C語言實現

5.1節點定義

AVLtree.h文件中的內容

#ifndef __AVLTREE_H__
#define __AVLTREE_H__
typedef struct Node{
	int height; //該節點做爲子樹時的高度
	int data;   //表示每一個節點存貯的數據
	Node* left;
	Node* right;
}Node, *AVLtree; 
//AVLtree  表示Node*
//AVLtree* 就表示Node**

int Insert(AVLtree* T, int D);
int Delete(AVLtree* T, int D);
int Find(AVLtree T, int x);
int Destroy(AVLtree* T);

//下面兩個遍歷函數主要用於測試
void InOredrTraverse(AVLtree T);
void PreOredrTraverse(AVLtree T);
#endif

 

5.2代碼實現

AVLtree.cpp文件中的內容

#include"AVLtree.h"
#include<stdlib.h>
#include<stdio.h>

#define MAX(x1,x2) ((x1) > (x2) ? (x1) : (x2))

//一下函數用於輔助實現插入刪除操做,做用域於僅限於AVLtree.cpp
static void PostOrderTraverse(AVLtree T);
static int GetHeight(AVLtree T);
static void LeftRotate(AVLtree* T);
static void RightRotate(AVLtree* T);
static int FindMin(AVLtree T);

//返回值用於表示插入是否成功,-1表示失敗(說明樹中已包含該數據),0表示成功
int Insert(AVLtree* T,int D){
	//參數檢查
	if(T == NULL){
		return -1;
	}

	//找到插入的位置
	if(*T == NULL){
		*T = (Node*)malloc(sizeof(Node));
		(*T)->data = D;
		(*T)->height = 1;
		(*T)->left = NULL;
		(*T)->right = NULL;
		return 0;
	}else{
		//樹中已存在該數據
		if(D == (*T)->data){
			return -1;
		}else
		if(D > (*T)->data){//在右子樹中插入
			if(Insert(&(*T)->right,D) == -1){
				return -1;
			}

			//插入後,當回溯到該節點進行檢查,若是不知足平衡條件,則調整
			//由於是在右子支中插入,若是高度只差等於2,只多是右子支比左子支高
			if(GetHeight((*T)->right) - GetHeight((*T)->left) == 2){
				if(D > (*T)->right->data){
					LeftRotate(T);//對應狀況2,左旋
				}else{//對應狀況4,先右旋再左旋
					RightRotate(&(*T)->right);
					LeftRotate(T);
				}
			}
		}else
		if(D < (*T)->data){//在左子樹中插入
			if(Insert(&(*T)->left,D)){
				return -1;
			}

			if(GetHeight((*T)->left) - GetHeight((*T)->right) == 2){
				if(D < (*T)->left->data){
					RightRotate(T);//對應狀況1,左旋
				}else{//對應狀況3,先右旋再左旋
					LeftRotate(&(*T)->left);
					RightRotate(T);
				}
			}
		}
	}

	//更新當前節點的高度
	(*T)->height = MAX(GetHeight((*T)->left),GetHeight((*T)->right))+1;
	return 0;
}

//返回-1表示,樹中沒有該數據,刪除失敗,
int Delete(AVLtree* T,int D){
	static Node* tmp;
	if(T == NULL){
		return -1;
	}

	if(*T == NULL){//樹爲空,或者樹中沒有該數據
		return -1;
	}else{
		//找到要刪除的節點
		if(D == (*T)->data){
			//刪除的節點左右子支都不爲空,必定存在前驅節點
			if((*T)->left != NULL && (*T)->right != NULL){
				D = FindMin((*T)->right);//找後繼替換
				(*T)->data = D;
				Delete(&(*T)->right,D);//而後刪除後繼節點,必定成功
				//在右子支中刪除,刪除後有可能左子支比右子支高度大2
				if(GetHeight((*T)->left)-GetHeight((*T)->right) ==  2){
					//判斷哪個左子支的的兩個子支哪一個比較高
					if(GetHeight((*T)->left->left) >= GetHeight((*T)->left->right)){
						RightRotate(T);
					}else{
						LeftRotate(&(*T)->left);
						RightRotate(T);
					}
				}
			}else
			if((*T)->left == NULL){//左子支爲空
				tmp = (*T);
				(*T) = tmp->right;
				free(tmp);
				return 0;
			}else
			if((*T)->right == NULL){//右子支爲空
				tmp = (*T);
				(*T) = tmp->left;
				free(tmp);
				return 0;
			}			
		}else
		if(D > (*T)->data){//在右子支中尋找待刪除的節點
			if(Delete(&(*T)->right,D) == -1){
				return -1;//刪除失敗,不須要調整,直接返回
			}
			if(GetHeight((*T)->left)-GetHeight((*T)->right) ==  2){
				if(GetHeight((*T)->left->left) >= GetHeight((*T)->left->right)){
					RightRotate(T);
				}else{
					LeftRotate(&(*T)->left);
					RightRotate(T);
				}
			}
		}else
		if(D < (*T)->data){//在左子支中尋找待刪除的節點
			if(Delete(&(*T)->left,D) == -1){
				return -1;
			}
			if(GetHeight((*T)->right) - GetHeight((*T)->left) == 2){
				if(GetHeight((*T)->right->right) >= GetHeight((*T)->right->left)){
					LeftRotate(T);
				}else{
					RightRotate(&(*T)->right);
					LeftRotate(T);
				}
			}
		}
	}
	//更新當前節點的高度
	(*T)->height = MAX(GetHeight((*T)->left),GetHeight((*T)->right))+1;
	return 0;
}

int Find(AVLtree T,int x){
	while(T != NULL){
		if(T->data == x){
			return 0;
		}else
		if(x > T->data){
			T = T->right;	
		}else{
			T = T->left;	
		}
	}
	return -1;
}

int Destroy(AVLtree* T){
	if(T == NULL){
		return -1;
	}

	PostOrderTraverse(*T);
	*T = NULL;
	return 0;
}

void InOredrTraverse(AVLtree T){
	if(T != NULL){
		InOredrTraverse(T->left);
		printf("%3d ",T->data);
		InOredrTraverse(T->right);;
	}
}

void PreOredrTraverse(AVLtree T){
	if(T != NULL){
		printf("%3d:%2d(%3d,%3d)\n",T->data,T->height,
			   T->left == NULL?-1:T->left->data,
			   T->right == NULL?-1:T->right->data
			  );
		PreOredrTraverse(T->left);
		PreOredrTraverse(T->right);
	}
}


static void PostOrderTraverse(AVLtree T){
	if(T != NULL){
		PostOrderTraverse(T->left);
		PostOrderTraverse(T->right);
		free(T);
	}
}

//空數的高度爲0
static int GetHeight(AVLtree T){
	if(T == NULL){
		return 0;
	}else{
		return T->height;
	}
}

static void LeftRotate(AVLtree* T){
	Node *P,*R;
	P = *T;
	R = P->right;
	P->right = R->left;
	R->left = P;
	*T = R;
	
	//旋轉之後要更新節點的高度
	P->height = MAX(GetHeight(P->left),GetHeight(P->right))+1;
	R->height = MAX(GetHeight(R->left),GetHeight(R->right))+1;
}

static void RightRotate(AVLtree* T){
	Node *P,*L;
	P = *T;
	L = P->left;
	P->left = L->right;
	L->right = P;
	*T = L;
	//旋轉之後要更新節點的高度
	P->height = MAX(GetHeight(P->left),GetHeight(P->right))+1;
	L->height = MAX(GetHeight(L->left),GetHeight(L->right))+1;
}

static int FindMin(AVLtree T){
	if(T == NULL){
		return -1;
	}

	while(T->left != NULL){
		T = T->left;
	}
	return T->data;
}

6. Java語言泛型實現

package datastruct;

import java.util.Comparator;

public class AVLtree <E>{
	private static class Node<E>{
		int h;
		E element;
		Node<E> left;
		Node<E> right;
		//因爲java中不像C語言那樣有二級指針的概念,因此添加一個父類的引用,方便程序編寫
		Node<E> parent;
		
		public Node(E element, int h, Node<E> left, Node<E> right, Node<E> parent){
			this.element = element;
			this.h = h;
			this.left = left;
			this.right = right;
			this.parent = parent;
		}
	}
	
	private Node<E> root;//指向僞根節點的引用
	private int size = 0;//節點個數
	Comparator<? super E> cmp;//節點大小的比較器
	
	//若是調用了不帶參數的構造函數,則使用該內部類做爲比較器,
	//但此時泛型E須要繼承Comparable接口,不然運行時會拋出異常
	private static class Cmp<T> implements Comparator<T>{
		@SuppressWarnings({ "unchecked", "rawtypes" })
		@Override
		public int compare(T e1, T e2) {
			return ((Comparable)e1).compareTo(e2);
		}
		
	}
	
	//帶比較器的構造函數
	public AVLtree(Comparator<? super E> cmp){
		if(cmp == null){
			throw new IllegalArgumentException();
		}
		this.cmp = cmp;
		//建立一個僞根節點,該節點的右子支纔是真正的AVL樹的根
		//使用僞根節點節點的目的是,對插入和刪除操做遞歸的形式可以統一
		root = new Node<E>(null, -1, null, null, null);
	}
	
	//不帶比較器的構造函數
	public AVLtree(){
		this.cmp = new Cmp<E>();
		root = new Node<E>(null, -1, null, null, null);
	}
	
	//若是樹中節點有變更,從底向上逐級調用該函數,能夠更新節點的高度
	private int getHight(Node<E> x){
		if(x == null){
			return 0;
		}else{
			return x.h;
		}
	}
	
	//求某個節點做爲根時,該子樹的最小值
	private E treeMin(Node<E> x){
		while(x.left != null){
			x = x.left;
		}
		return x.element;
	}
	
	public int size(){
		return size;
	}
	
	//先根遍歷,調試時使用
	public void preorderTraverse(){
		if(root != null){
			preorderTraverse0(root.right);
		}
	}
	
	private void preorderTraverse0(Node<E> x){
		if(x != null){
			System.out.print(x.element+" ");
			if(x.left != null){
				System.out.print(x.left.element+" ");
			}else{
				System.out.print("null  ");
			}
			
			if(x.right != null){
				System.out.print(x.right.element+" ");
			}else{
				System.out.print("null  ");
			}
			System.out.println();
			preorderTraverse0(x.left);
			preorderTraverse0(x.right);
		}
	}
	
	//逆時針旋轉(左旋),參數表示軸節點
	private void antiClockwiseRotate(Node<E> X){
		Node<E> P = X.parent;
		Node<E> XR = X.right;
		if(P.left == X){
			P.left = XR;
		}else{
			P.right = XR;
		}
		XR.parent = P;
		
		X.right = XR.left;
		if(XR.left != null){
			XR.left.parent = X;
		}
		
		XR.left = X;
		X.parent = XR;
		
		//旋轉後要更新這兩個節點的高度
		X.h = Math.max(getHight(X.left), getHight(X.right)) + 1;
		XR.h = Math.max(getHight(XR.left), getHight(XR.right)) + 1;
	}
	
	//順時針旋轉(右旋),參數表示軸節點
	private void clockwistRotate(Node<E> X){
		Node<E> P = X.parent;
		Node<E> XL = X.left;
		if(P.left == X){
			P.left = XL;
		}else{
			P.right = XL;
		}
		XL.parent = P;
		
		X.left = XL.right;
		if(XL.right != null){
			XL.right.parent = X;
		}
		
		XL.right = X;
		X.parent = XL;
		
		//旋轉後要更新這兩個節點的高度
		X.h = Math.max(getHight(X.left), getHight(X.right)) + 1;
		XL.h = Math.max(getHight(XL.left), getHight(XL.right)) + 1;
	}
	
	//
	public void insert(E e){
		insert0(root.right, e);
	}
	
	private void insert0(Node<E> x, E e){
		if(x == null){
			root.right = new Node<E>(e, 1, null, null, root);//根節點
			size++;
			return;
		}
		
		if(cmp.compare(e, x.element) > 0){
			if(x.right != null){
				insert0(x.right, e);
				int lh = getHight(x.left);
				int rh = getHight(x.right);
				if(rh - lh == 2){
					if(cmp.compare(e, x.right.element) > 0){
						antiClockwiseRotate(x);
					}else{
						clockwistRotate(x.right);
						antiClockwiseRotate(x);
					}
				}
			}else{
				size++;
				x.right = new Node<E>(e, 1, null, null, x);
			}
		}else
		if(cmp.compare(e, x.element) < 0){
			if(x.left != null){
				insert0(x.left, e);
				int lh = getHight(x.left);
				int rh = getHight(x.right);
				if(lh - rh == 2){
					if(cmp.compare(e, x.left.element) < 0){
						clockwistRotate(x);
					}else{
						antiClockwiseRotate(x.left);
						clockwistRotate(x);
					}
				}
			}else{
				size++;
				x.left = new Node<E>(e, 1, null, null, x);
			}
		}else{
			//元素已存在,咱們用新的元素更新舊,
			//compare返回值等於0,並不表示兩個對象徹底相等
			x.element = e;
		}
		x.h = Math.max(getHight(x.left), getHight(x.right)) + 1;
	}
	
	public boolean delete(E e){
		return delete0(root.right, e);
	}
	
	//返回值表示是否刪除成功
	private boolean delete0(Node<E> x, E e){
		if(x == null){//沒有找到待刪除的元素
			return false;
		}
		
		if(cmp.compare(e, x.element) > 0){
			boolean reval = delete0(x.right, e);
			if(reval == false){
				return false;
			}
			
			int lh = getHight(x.left);
			int rh = getHight(x.right);
			if(lh - rh == 2){
				if(getHight(x.left.left) > getHight(x.left.right)){
					clockwistRotate(x);
				}else{
					antiClockwiseRotate(x.left);
					clockwistRotate(x);
				}
			}
		}else
		if(cmp.compare(e, x.element) < 0){
			boolean reval = delete0(x.left, e);
			if(reval == false){
				return false;
			}

			int lh = getHight(x.left);
			int rh = getHight(x.right);
			if(rh - lh == 2){
				if(getHight(x.right.right) > getHight(x.right.left)){
					antiClockwiseRotate(x);
				}else{
					clockwistRotate(x.right);
					antiClockwiseRotate(x);
				}
			}
		}else{//找到待刪除的元素
			Node<E> P = x.parent;
			
			if(x.left == null){//左子支爲空,可直接刪除,在這一層必定不須要旋轉
				size--;
				if(P.left == x){
					P.left = x.right;
					if(P.left != null){
						P.left.parent = P;
					}
				}else{
					P.right = x.right;
					if(P.right != null){
						P.right.parent = P;
					}
				}
			}else
			if(x.right == null){//右子支爲空,可直接刪除,在這一層必定不須要旋轉
				size--;
				if(P.left == x){
					P.left = x.left;
					if(P.left != null){					
						P.left.parent = P;
					}
				}else{
					P.right = x.left;
					if(P.right != null){
						P.right.parent = P;
					}
				}
			}else{//找到待刪除的節點,用後繼節點代替,而後刪除後繼節點
				E nextVal = treeMin(x.right);
				x.element = nextVal;
				delete0(x.right, nextVal);
				int lh = getHight(x.left);
				int rh = getHight(x.right);
				if(lh - rh == 2){
					if(getHight(x.left.left) > getHight(x.left.right)){
						clockwistRotate(x);
					}else{
						antiClockwiseRotate(x.left);
						clockwistRotate(x);
					}
				}
			}
		}
		x.h = Math.max(getHight(x.left), getHight(x.right)) + 1;
		return true;
	}
	
	public static void main(String[] args){
		AVLtree<Integer> avl = new AVLtree<Integer>();
		/*可自行添加插入,刪除操做進行測試*/
		avl.insert(3);
		avl.insert(5);
		avl.insert(6);
		avl.insert(7);
		avl.insert(8);
		avl.insert(9);
		avl.preorderTraverse();
		System.out.println();
		System.out.println(avl.size());
		
		avl.delete(7);
		avl.delete(8);
		avl.preorderTraverse();
		System.out.println();
		System.out.println(avl.size());
	}
}
相關文章
相關標籤/搜索