尚硅谷Java數據結構學習記錄32-平衡二叉樹詳解

平衡二叉樹的目的在於使左子樹和右子樹的長度差不超過1

 

左旋轉  右子樹要更長,因此要向左旋轉,具體見代碼或下圖

右旋轉 右旋轉是根結點的左子樹的左子樹比根結點的右子樹長,需要右旋轉

 

左旋轉和右旋轉往往是結合使用的,如 左子樹的右子樹的長度要大於根結點的右子樹的長度,整體上是右旋轉,但是在左子樹上是要先左旋轉。結果是先將根結點的左子樹進行左旋轉,然後發現根結點的左子樹的長度還是大於右結點,再進行右旋轉

 

package AVL;
/*
 * 左旋右旋的思路總結:
 * 1。左旋是右子樹的長度比左子樹長,需要向左轉
 * 2.
 */


public class AVLTree {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//int[] array = {4,3,6,5,7,8};
		int[] array = {10,12,8,9,7,6};

		AVLTreeC avlTree = new AVLTreeC();
		for(int i = 0; i < array.length; i++) {
			avlTree.add(new Node(array[i]));
		}
		
		//遍歷
		System.out.println("中序遍歷");
		avlTree.infixOrder();
		
		System.out.println("長度");
		System.out.println(avlTree.root.height());
		
		System.out.println("左子樹的長度:"+avlTree.getRoot().left.height());
		System.out.println("右子樹的長度"+avlTree.getRoot().right.height());
		System.out.println("當前根結點"+avlTree.getRoot().value);
		System.out.println("當前根結點的左結點"+avlTree.getRoot().right.value);


	}
	
	//創建AVL樹
	static class AVLTreeC{
		private Node root;
		public Node getRoot() {
			return root;
		}

		//添加結點的方法
		public void add(Node node) {
			if(root == null) {
				root = node;  //如果root爲空則直接讓root指向node
			}else {
				root.add(node);
			}
		}
		
		//中序遍歷
		public void infixOrder() {
			if(root != null) {
				root.infixOrder();
			}else {
				System.out.println("該二叉樹爲空");
			}
		}
		
		//查找要刪除的結點
		public Node search(int value) {
			if(root == null) {
				return null;
			}else {
				return root.search(value);
			}
		}
		
		//刪除結點
		public void delNode(int value) {
			if(root == null)
				return;
			else {
				//需要先找到要刪除的結點 targetNode
				Node targetNode = search(value);
				//如果沒有找到要刪除的結點
				if(targetNode == null) {
					return;
				}
				//如果我們發現當前二叉樹只有一個結點
				if(root.left == null && root.right == null) {
					root = null;
					return;
				}

				
				
				//去找到targetNode的父結點
				Node parent = searchParent(value);
				//如果要刪除的結點是葉子結點
				if(targetNode.left == null && targetNode.right == null) {
					//判斷targetNode 是父結點的左子結點,還是右子結點
					if(parent.left != null && parent.left.value == value) {
						parent.left = null;
					}else if(parent.right != null && parent.right.value == value){
						parent.right = null;
					}
				} else if (targetNode.left != null && targetNode.right != null) {
//					int minVal = delRigthTree(targetNode.right);
//					targetNode.value = minVal;
					//下面代碼是按左子樹的最大值
					int maxVal = delLeftTree(targetNode.left);
					targetNode.value = maxVal;
				} else {
					// 刪除只有一個子樹的結點
					// 如果要刪除的結點有左子結點
					if (targetNode.left != null) {
						if(parent != null) {
							// 如果targetNode 是parent的左子結點
							if (parent.left.value == value) {
								parent.left = targetNode.left;
							} else {
								parent.right = targetNode.left;
							}
						}else {
							root = targetNode.left;
						}
	
					}
					else {
						if(parent != null) {
							// 如果要刪除結點有右子結點
							if (parent.left.value == value) {
								if (targetNode.right != null) {
									// 如果targetNode 是parent的左子結點
									
										parent.left = targetNode.right;
									} else {
										parent.right = targetNode.right;
									}
								
							}
						}else {
							root = root.left;
						}
		
					}
				}

			}
		}
		
		
		//找左子樹的最大結點 即找左子樹的最大右結點
		public int delLeftTree(Node node) {
			Node target = node;
			while(target.right != null){
				target = target.right;
			}
			delNode(target.value);
			return target.value;
		}
		
		//刪除雙子樹結點
		
		//1.返回的以Node爲根節點的二叉排序樹的最小結點的值
		//2.刪除Node爲根節點的二叉排序樹的最小結點
		public int delRigthTree(Node node) {
			Node target = node;
			//循環的查找左子結點,就會找到最小值
			while(target.left != null) {
				target = target.left;
			}
			//這時 target指向最小結點
			delNode(target.value);
			return target.value;
		}
		
		//查找父結點
		public Node searchParent(int value) {
			if(root == null)
				return null;
			else
				return root.searchParent(value);
		}
	}
	

	static class Node{
		int value;
		Node left;
		Node right;
		public Node(int value) {
			super();
			this.value = value;
		}
		
		//返回左子樹的高度
		public int leftHeight() {
			if(left == null)
				return 0;
			return left.height();
		}	
		
		//返回右子樹的高度
		public int rightHeight(){
			if(right == null)
				return 0;
			return right.height();
		}
		//返回以該點爲根節點的樹的長度
		public int height() {
			return Math.max(left == null ? 0 : left.height(), right == null ? 0 :right.height()) + 1;
		}
		
		
		//右旋轉方法
		private void rightRotate() {
			//創建新的結點,以當前根結點的值
			Node newNode = new Node(value);
			//把當前新結點的右子樹設置爲當前結點的右子樹
			newNode.right = right;
			//把當前新結點的左子樹設置爲當前結點的左子樹的右子樹
			newNode.left = left.right;
			//把當前結點的值設置爲左子樹的值
			value = left.value;
			//把結點的 右子樹設爲新結點
			right = newNode;
			//左子樹是左左
			left = left.left;
		}
		
		//左旋轉方法
		private void leftRotate() {
			//創建新的結點,以當前根結點的值
			Node newNode = new Node(value);
			//新的結點的左子樹設置爲當前結點的左子樹
			newNode.left = left;
			//新結點的右子樹設置爲當前結點的右子樹的左子樹
			newNode.right = right.left;
			//把當前結點的值換位右子結點的值
			value = right.value;
			//把當前結點的左子樹設置爲新結點
			left = newNode;
			right = right.right;
			
		}
		@Override
		public String toString() {
			return "Node [value=" + value + "]";
		}
		
		//添加結點的方法
		//使用遞歸的方式添加結點,需要注意滿足二叉排序樹的要求
		public void add(Node node) {
			if(node == null) {
				return;
			}
			
			//判斷傳入的結點的值和根結點的關係
			if(node.value < this.value) {
				if(this.left == null) {
					this.left = node;
				}else {
					this.left.add(node);
				}
			}else {
				if(this.right == null){
					this.right = node;
				}else {
					this.right.add(node);
				}
			}
			
			
			//當添加一個結點後,如果右子樹的高度比左子樹的高度大1 則進行左旋轉
			if(rightHeight() - leftHeight() >1) {
				if(right != null && right.leftHeight() > right.rightHeight()) {
					right.rightHeight();
					leftRotate();
				}else {
					leftRotate();

				}
				return;


			}if(leftHeight() - rightHeight() > 1) {
				if(left != null && left.rightHeight() > left.leftHeight()) {
					left.leftRotate();
					rightRotate();

				}else {
					rightRotate();
	
				}
				return;
			}
		}
		
		//找到要刪除的結點
		public Node search(int value) {
			if(value == this.value) {
				//找到就是該結點
				return this;
			}else if(value < this.value){
				//如果左子結點爲空
				if(this.left == null) {
					return null;
				}
				return this.left.search(value);
			}else {
				//如果當前查找的值不小於結點,向右子樹遞歸查找
				if(this.right == null) {
					return null;
				}
				return this.right.search(value);
			}
		}
		
		
		//查找要刪除你結點的父結點
		public Node searchParent(int value) {
			//如果當前結點就是要刪除的結點的父結點,就返回
			if((this.left != null && this.left.value == value)
					||(this.right != null && this.right.value == value)) {
				return this;
			}else {
				//如果查找的值小於當前結點的值,並且當前結點的左子結點不爲空
				if(value < this.value && this.left != null){
					return this.left.searchParent(value);
				}else if(value > this.value && this.right != null) {
					return this.right.searchParent(value);
				}else {
					return null; //沒有找到父結點
				}
			}
		}
		
		
		
		//中序遍歷
		public void infixOrder() {
			if(this.left != null) {
				this.left.infixOrder();
			}
			System.out.println(this);
			if(this.right != null) {
				this.right.infixOrder();
			}
		}
		
	}


}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章