데이터 구조의 자체 균형 이 진 트 리 찾기 (1)

오늘부터 우 리 는 자 평형 이 진 트 리 라 고 불 리 는 새로운 이 진 트 리 를 다시 만 났 다.AVL 트 리 는 가장 먼저 발 명 된 밸 런 스 이 진 트 리 다.
AVL 트 리 의 특징 은 트 리 의 모든 노드 에 대해 노드 의 좌우 서브 트 리 의 높이 차이 가 최대 1 이 므 로 AVL 트 리 를 고도 밸 런 스 트 리 라 고도 부른다.AVL 트 리 는 발명자 G. M. Adelson - Velsky 와 E. M. Landis 에서 이름 을 얻 었 다. 그들 은 1962 년 논문 'An algorithm for the organization of information' 에서 발표 했다.
우리 가 노드 의 균형 요 소 를 정의 하 는 것 은 바로 이 노드 의 왼쪽 나무 높이 와 오른쪽 나무 높이 의 차이 이다. 위의 설명 에 따 르 면 우 리 는 + 1, 0, - 1 균형 요 소 를 가 진 노드 는 균형 노드 이 고 다른 것 은 모두 불 균형 노드 라 는 것 을 알 수 있다.노드 가 불 균형 일 때 우 리 는 이 노드 를 균형 화 시 켜 야 한다.우 리 는 균형 인 자 를 노드 의 내부 에 저장 할 수도 있 고 노드 의 높이 를 통 해 계산 할 수도 있다.
높이 가 h 인 AVL 트 리 로 노드 수가 N 이 가장 많 습 니 다.최소최소 노드 n 예 를 들 어 페 베 르 나시 수열 은 수학 귀납법 으로 증명 할 수 있다. = - 1 (Fibonacci polynomial).즉: = 0 (AVL Tree 높이 0 을 나타 내 는 노드 총수) = 1 (AVL Tree 높이 1 을 나타 내 는 노드 총수) = 2 (AVL Tree 높이 2 를 나타 내 는 노드 총수) = + + 1 (AVL Tree 높이 h 를 나타 내 는 노드 총수) 은 노드 수가 N 일 때 높이 h 가 가장 많다 는 것 이다.
 
불 균형 노드 의 균형 화 는 보통 네 가지 상황 이 있 는데 지금 은 아래 에 열거 되 어 있다.
이 네 가지 방식 의 코드 는 다음 과 같다.
	//      
	private AVLTreeNode rotateWithLeftChild(AVLTreeNode node)
	{
		AVLTreeNode root=node.left;
		node.left=root.right;
		root.right=node;
		node.height=Math.max(height(node.left),height(node.right))+1;
		root.height=Math.max(height(root.left),height(root.right))+1;
		return root;
	}
	
	//      
	private AVLTreeNode rotateWithRightChild(AVLTreeNode node)
	{
		AVLTreeNode root=node.right;
		node.right=root.left;
		root.left=node;
		node.height=Math.max(height(node.left),height(node.right))+1;
		root.height=Math.max(height(root.left),height(root.right))+1;
		return root;
	}
	
	//      
	private AVLTreeNode doubleRotateLeftChild(AVLTreeNode node)
	{
		node.left=rotateWithRightChild(node.left);
		return rotateWithLeftChild(node);
	}
	
	//      
	private AVLTreeNode doubleRotateRightChild(AVLTreeNode node)
	{
		node.left=rotateWithLeftChild(node.right);
		return rotateWithRightChild(node);
	}

 
AVL 트 리 의 동작 은 삽입, 삭제, 찾기 세 가지 기본 동작 을 포함 하 는데 이 세 가지 상황 은 평균 과 최 악의 상황 에서 시간 복잡 도 는 모두 O (log n) 이다.
삽입:
AVL 트 리 에 삽입 하면 균형 이 잡 히 지 않 은 이 진 트 리 처럼 주어진 값 을 트 리 에 삽입 한 다음 아래 에서 위로 뿌리 노드 를 되 돌려 삽입 하 는 동안 불 균형 이 된 모든 노드 를 회전 시 켜 완성 할 수 있 습 니 다.루트 노드 로 되 돌아 가 는 길에 최대 1.5 곱 하기 logn 개의 노드 가 있 고 AVL 회전 할 때마다 일정한 시간 을 소모 하기 때문에 삽입 처 리 는 전체적으로 O (logn) 시간 을 소모 합 니 다.
삭제:
AVL 트 리 에서 삭제 하면 삭제 할 노드 를 아래로 한 잎 노드 로 회전 시 킨 다음 에 이 잎 노드 를 직접 잘라 서 완성 할 수 있 습 니 다.잎 노드 로 회전 하 는 동안 최대 log n 개의 노드 가 회전 되 고 매번 AVL 회전 은 일정한 시간 을 소모 하기 때문에 삭제 처 리 는 전체적으로 O (logn) 시간 을 소모 합 니 다.
찾기:
일반 이 진 트 리 처럼 진행 할 수 있 기 때문에 O (log n) 시간 이 걸 립 니 다. AVL 트 리 는 항상 균형 을 유지 하기 때 문 입 니 다.특별한 준비 가 필요 없 이 나무의 구 조 는 찾 아서 바 뀌 지 않 습 니 다.(이것 은 스 트 레 칭 트 리 와 상대 적 으로 서 있 는 것 입 니 다. 찾기 때문에 트 리 구 조 를 변경 합 니 다.)
균형 이 잡 힌 이 진 트 리 와 일반적인 이 진 트 리 의 차 이 를 관찰 하기 위해 서 는 같은 이 진 트 리 에 대해 두 가지 다른 결 과 를 내 놓 을 것 입 니 다. 옮 겨 다 니 는 결 과 를 통 해 이 진 트 리 의 구조 상 태 를 알 수 있 습 니 다.다음은 먼저 일반 두 갈래 로 나 무 를 찾 는 프로그램 을 보 여 줍 니 다.
package mianshiti;
import java.util.*;

public class BinarySearchTree {
	private TreeNode root=null;//   
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BinarySearchTree mytree=new BinarySearchTree();
		mytree.insert(4);
		mytree.insert(3);
		mytree.insert(2);
		mytree.insert(1);
		mytree.insert(5);
		System.out.println("          :");
		mytree.preorder(mytree.getRoot());
		System.out.println();
		System.out.println("          :");
		mytree.inorder(mytree.getRoot());
		System.out.println();
		System.out.println("          :");
		mytree.postorder(mytree.getRoot());
		System.out.println();
		System.out.println("           :");
		mytree.nonRecursivePreorder(mytree.getRoot());
		System.out.println();
		System.out.println("           :");
		mytree.nonRecursiveInorder(mytree.getRoot());
		System.out.println();
		System.out.println("           :");
		mytree.nonRecursivePostorder(mytree.getRoot());
		System.out.println();
	}
	
	//    
	public void preorder(TreeNode node)
	{
		if(node!=null)
		{
			this.getNodeInfo(node);
			preorder(node.left);
			preorder(node.right);
		}
	}
	//    
	public void inorder(TreeNode node)
	{
		if(node!=null)
		{
			inorder(node.left);
			this.getNodeInfo(node);
			inorder(node.right);
		}
	}
	//    
	public void postorder(TreeNode node)
	{
		if(node!=null)
		{
			postorder(node.left);
			postorder(node.right);
			this.getNodeInfo(node);
		}
	}
	//           
	public void nonRecursivePreorder(TreeNode node)
	{
		Stack<TreeNode> mystack=new Stack<TreeNode>();
		if(node!=null)
		{
			mystack.push(node);
			while(!mystack.isEmpty())
			{
				TreeNode temp=mystack.pop();
				this.getNodeInfo(temp);
				if(temp.right!=null)
				{
					mystack.push(temp.right);
				}
				if(temp.left!=null)
				{
					mystack.push(temp.left);
				}
			}
		}
	}
	//           
	public void nonRecursiveInorder(TreeNode node)
	{
		Stack<TreeNode> mystack=new Stack<TreeNode>();
		while(node!=null)
		{
			while(node!=null)
			{
				if(node.right!=null)
				{
					mystack.push(node.right);
				}
				mystack.push(node);
				node=node.left;
			}
			node=mystack.pop();
			while(!mystack.isEmpty()&&node.right==null)
			{
				this.getNodeInfo(node);
				node=mystack.pop();
			}
			this.getNodeInfo(node);
			if(!mystack.isEmpty())
			{
				node=mystack.pop();
			}else
			{
				node=null;
			}
		}
	}
	//           
	public void nonRecursivePostorder(TreeNode node)
	{
		Stack<TreeNode> mystack=new Stack<TreeNode>();
		TreeNode temp=node;
		while(node!=null)
		{
			for(;node.left!=null;node=node.left)
			{
				mystack.push(node);
			}
			while(node!=null&&(node.right==null||node.right==temp))
			{
				this.getNodeInfo(node);
				temp=node;
				if(mystack.isEmpty())
					return;
				node=mystack.pop();
			}
			mystack.push(node);
			node=node.right;
		}
	}

	//    
	public BinarySearchTree()
	{
		this.root=null;
	}
	
	
	public TreeNode getRoot()
	{
		return this.root;
	}
	
	//      
	public void insert(int value)
	{
		TreeNode nextnode=new TreeNode(value);
		TreeNode temp=this.root;
		if(this.root==null)
		{
			this.root=nextnode;
			nextnode.parent=null;
			return ;
		}
		while(temp!=null)
		{
			if(value<temp.data)
			{
				if(temp.left==null)
				{
					temp.left=nextnode;
					nextnode.parent=temp;
					return;
				}else
				{
					temp=temp.left;
				}
			}else if(value>temp.data)
			{
				if(temp.right==null)
				{
					temp.right=nextnode;
					nextnode.parent=temp;
					return;
				}else
				{
					temp=temp.right;
				}
			}
		}
	}
	
	//   begin                 
	private TreeNode minTreeNode(TreeNode begin)
	{
		if(begin==null)
			return null;
		while(begin.left!=null)
		{
			begin=begin.left;
		}
		return begin;
	}
	
	//   begin                 
	private TreeNode maxTreeNode(TreeNode begin)
	{
		if(begin==null)
			return null;
		while(begin.right!=null)
		{
			begin=begin.right;
		}
		return begin;
	}
	
	
	//      
	public void delete(int value)
	{
		if(this.root==null)
		{
			System.out.println("   ,    "+value);
			return;
		}
		TreeNode temp=this.root;
		while(temp!=null)
		{
			if(value>temp.data)
			{
				if(temp.right==null)
				{
					System.out.println("         ");
				}else
				{
					temp=temp.right;
				}
			}else if(value<temp.data)
			{
				if(temp.left==null)
				{
					System.out.println("         ");
				}else
				{
					temp=temp.left;
				}
			}else
			{
				//       
				if(temp.left==null&&temp.right==null)//       
				{
					if(temp.parent.right==temp)
					{
						temp.parent.right=null;
					}else
					{
						temp.parent.left=null;
					}
				}else if(temp.right!=null&&temp.left==null)//     ,      
				{
					if(temp.parent.right==temp)
					{
						temp.parent.right=temp.right;
						temp.right.parent=temp.parent;
					}else
					{
						temp.parent.left=temp.right;
						temp.right.parent=temp.parent;
					}
				}else if(temp.left!=null&&temp.right==null)//      ,     
				{
					if(temp.parent.right==temp)
					{
						temp.parent.right=temp.left;
						temp.left.parent=temp.parent;
					}
					else
					{
						temp.parent.left=temp.left;
						temp.left.parent=temp.parent;
					}
				}else//        
				{
					TreeNode replacenode=minTreeNode(temp.right);
					delete(replacenode.data);
					temp.data=replacenode.data;
				}
				break;
			}
		}
	}
	
	public void getNodeInfo(TreeNode treenode)
	{
		if(treenode!=null)
		{
			System.out.print(treenode.data+" ");
		}
	}
}

class TreeNode{
	public int data;
	public TreeNode left;//    
	public TreeNode right;//    
	public TreeNode parent;//   
	//    
	public TreeNode(int data)
	{
		this(data,null,null,null);
	}
	
	public TreeNode(int data,TreeNode left,TreeNode right,TreeNode parent)
	{
		this.data=data;
		this.left=left;
		this.right=right;
		this.parent=parent;
	}

}

실행 결 과 는 다음 과 같다.
          :
4 3 2 1 5 
          :
1 2 3 4 5 
          :
1 2 3 5 4 
           :
4 3 2 1 5 
           :
1 2 3 4 5 
           :
1 2 3 5 4 

그 다음 에 우 리 는 균형 이 잡 힌 두 갈래 에서 나 온 나무의 실현 을 찾 습 니 다.
package mianshiti;

import java.util.Stack;

//AVL    
public class AVLTree {
	AVLTreeNode rootnode=null;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		AVLTree mytree=new AVLTree();
		mytree.insert(4);
		mytree.insert(3);
		mytree.insert(2);
		mytree.insert(1);
		mytree.insert(5);
		System.out.println("          :");
		mytree.preorder(mytree.getRoot());
		System.out.println();
		System.out.println("          :");
		mytree.inorder(mytree.getRoot());
		System.out.println();
		System.out.println("          :");
		mytree.postorder(mytree.getRoot());
		System.out.println();
		System.out.println("           :");
		mytree.nonRecursivePreorder(mytree.getRoot());
		System.out.println();
		System.out.println("           :");
		mytree.nonRecursiveInorder(mytree.getRoot());
		System.out.println();
		System.out.println("           :");
		mytree.nonRecursivePostorder(mytree.getRoot());
		System.out.println();
	}
	
	public AVLTreeNode getRoot()
	{
		return rootnode;
	}
	
	//    
	public void preorder(AVLTreeNode node)
	{
		if(node!=null)
		{
			this.getNodeInfo(node);
			preorder(node.left);
			preorder(node.right);
		}
	}
	//    
	public void inorder(AVLTreeNode node)
	{
		if(node!=null)
		{
			inorder(node.left);
			this.getNodeInfo(node);
			inorder(node.right);
		}
	}
	//    
	public void postorder(AVLTreeNode node)
	{
		if(node!=null)
		{
			postorder(node.left);
			postorder(node.right);
			this.getNodeInfo(node);
		}
	}
	//           
	public void nonRecursivePreorder(AVLTreeNode node)
	{
		Stack<AVLTreeNode> mystack=new Stack<AVLTreeNode>();
		if(node!=null)
		{
			mystack.push(node);
			while(!mystack.isEmpty())
			{
				AVLTreeNode temp=mystack.pop();
				this.getNodeInfo(temp);
				if(temp.right!=null)
				{
					mystack.push(temp.right);
				}
				if(temp.left!=null)
				{
					mystack.push(temp.left);
				}
			}
		}
	}
	//           
	public void nonRecursiveInorder(AVLTreeNode node)
	{
		Stack<AVLTreeNode> mystack=new Stack<AVLTreeNode>();
		while(node!=null)
		{
			while(node!=null)
			{
				if(node.right!=null)
				{
					mystack.push(node.right);
				}
				mystack.push(node);
				node=node.left;
			}
			node=mystack.pop();
			while(!mystack.isEmpty()&&node.right==null)
			{
				this.getNodeInfo(node);
				node=mystack.pop();
			}
			this.getNodeInfo(node);
			if(!mystack.isEmpty())
			{
				node=mystack.pop();
			}else
			{
				node=null;
			}
		}
	}
	//           
	public void nonRecursivePostorder(AVLTreeNode node)
	{
		Stack<AVLTreeNode> mystack=new Stack<AVLTreeNode>();
		AVLTreeNode temp=node;
		while(node!=null)
		{
			for(;node.left!=null;node=node.left)
			{
				mystack.push(node);
			}
			while(node!=null&&(node.right==null||node.right==temp))
			{
				this.getNodeInfo(node);
				temp=node;
				if(mystack.isEmpty())
					return;
				node=mystack.pop();
			}
			mystack.push(node);
			node=node.right;
		}
	}
	
	public void getNodeInfo(AVLTreeNode node)
	{
		if(node!=null)
		{
			System.out.print(node.data+" ");
		}
	}

	public void insert(int data)
	{
		rootnode=insert(data,rootnode);
	}
	
	private AVLTreeNode insert(int data,AVLTreeNode root)
	{
		if(root==null)
		{
			AVLTreeNode node=new AVLTreeNode(data);
			return node;
		}
		if(data<root.data)
		{
			root.left=insert(data,root.left);
		}else if(data>root.data)
		{
			root.right=insert(data,root.right);
		}else
		{
			System.out.println("   "+data);
		}
		return balance(root);
	}
	
	//       
	private AVLTreeNode balance(AVLTreeNode root)
	{
		if(root==null)
			return root;
		if(height(root.left)-height(root.right)>1)
		{
			if(height(root.left.left)>=height(root.left.right))
			{
				root=rotateWithLeftChild(root);
			}else
			{
				root=doubleRotateLeftChild(root);
			}
		}else if(height(root.right)-height(root.left)>1)
		{
			if(height(root.right.right)>=height(root.right.left))
			{
				root=rotateWithRightChild(root);
			}else
			{
				root=doubleRotateRightChild(root);
			}
		}
		root.height=Math.max(height(root.left), height(root.right))+1;
		return root;
	}
	
	//      
	private AVLTreeNode rotateWithLeftChild(AVLTreeNode node)
	{
		AVLTreeNode root=node.left;
		node.left=root.right;
		root.right=node;
		node.height=Math.max(height(node.left),height(node.right))+1;
		root.height=Math.max(height(root.left),height(root.right))+1;
		return root;
	}
	
	//      
	private AVLTreeNode rotateWithRightChild(AVLTreeNode node)
	{
		AVLTreeNode root=node.right;
		node.right=root.left;
		root.left=node;
		node.height=Math.max(height(node.left),height(node.right))+1;
		root.height=Math.max(height(root.left),height(root.right))+1;
		return root;
	}
	
	//      
	private AVLTreeNode doubleRotateLeftChild(AVLTreeNode node)
	{
		node.left=rotateWithRightChild(node.left);
		return rotateWithLeftChild(node);
	}
	
	//      
	private AVLTreeNode doubleRotateRightChild(AVLTreeNode node)
	{
		node.left=rotateWithLeftChild(node.right);
		return rotateWithRightChild(node);
	}
	
	//         
	private int height(AVLTreeNode node)
	{
		return node==null?-1:node.height;
	}
}

//  AVL    
class AVLTreeNode
{
	int data;
	AVLTreeNode left;
	AVLTreeNode right;
	int height;
	
	//    
	public AVLTreeNode(int data)
	{
		this(data,null,null);
	}
	
	public AVLTreeNode(int data,AVLTreeNode left,AVLTreeNode right)
	{
		this.data=data;
		this.left=left;
		this.right=right;
		this.height=0;
	}
}

실행 결 과 는 다음 과 같다.
          :
3 2 1 4 5 
          :
1 2 3 4 5 
          :
1 2 5 4 3 
           :
3 2 1 4 5 
           :
1 2 3 4 5 
           :
1 2 5 4 3 

좋은 웹페이지 즐겨찾기