AVL tree 代码

写到后来,写吐了..... 跟教材的相比,还是教材的思路更清晰一些,我这个能跑起来,但是写的过程太痛苦

package indi.tom.dataStructure.avltree;

import org.junit.Test;

import indi.tom.dataStructure.avltree.AVLTreeTest.AVLTree;
import indi.tom.dataStructure.avltree.AVLTreeTest.ValueNotFoundException;



/**
 * @Author: Tom
 * @Date: 2021年1月3日 下午8:43:56
 * @Version: 1.0
 * @Description: A demo of AVL tree, built on top of BST tree. The main
 *               difference between BST and AVL tree is that the AVL tree
 *               addNode() method, The addNode() method guarantee that after
 *               adding the new node, the tree is still a self-balancing BST
 *               tree which is a tree that the height difference of the left and
 *               right subtree doesn't exceeds 1. It utilize the leftRotate()
 *               and rightRotate() method to make it.
 */
public class AVLTreeTest {
	public static void main(String[] args) throws ValueNotFoundException {
		AVLTree avlTree = new AVLTree();
		for (int i = 0; i < 10; i++) {
			avlTree.add(i);
		}

       avlTree.inOrder();
       
       avlTree.add(10);
       avlTree.delete(4);
       
       avlTree.inOrder();
       

	}

	@Test
	public void test01() throws ValueNotFoundException {
		AVLTree avlTree = new AVLTree();
		for (int i = 0; i < 10; i++) {
			avlTree.add(i);
		}
		System.out.println(avlTree);

	}

	

	static class AVLTree {
		Node root;
		
		public AVLTree() {}

		public AVLTree(Node root) {
			super();
			this.root = root;
		}

		// In order traverse
		public void inOrder() {
			root.inOrder();
		}

		// BST search
		public Node search(int value) {
			if (root == null)
				return null;
			return root.search(value);
		}

		// BST add
		public void add(int value) {
			
		
			if (root == null) {
				root = new Node(value);
			}else {
				root.add(value);
			}		
			
		
		}

		/**
		 * 
		 * @Description: Delete the node with given value from the tree
		 *               ****Difficult*****
		 * @param value The Node value to be deleted
		 * @return no return value
		 * @throws ValueNotFoundException when the given value is not found in the tree.
		 */
		public void delete(int value) throws ValueNotFoundException {
			// 1. root is null or not found in the tree
			if (root == null)
				throw new ValueNotFoundException("This is a blank tree");
			Node searchResultNode = search(value);
			if (searchResultNode == null)
				throw new ValueNotFoundException("The given value is not found");
			Node parent = searchParent(root, value);

			// 2. root node is the one that has the value
			if (parent == null) {
				if (root.getLeft() == null && root.getRight() == null) {
					root = null;
				} else if (root.getLeft() != null && root.getRight() != null) {
					int minValue = getAndDeleteRightTreeMinValue(root.getRight());
					root.setValue(minValue);
					root.balance();

				} else if (root.getLeft() != null && root.getRight() == null) {
					this.root = root.getLeft();
				} else if (root.getLeft() == null && root.getRight() != null) {
					this.root = root.getRight();
				}
				// 3. the value exists being held by an non-root node
			} else {
				// 3.1 searchResultNode is a leaf node, remove it directly
				if (searchResultNode.getLeft() == null && searchResultNode.getRight() == null) {
					if (parent.getLeft() == searchResultNode) {
						parent.setLeft(null);
					} else if(parent.getRight() == searchResultNode){
						parent.setRight(null);
					}
					this.root.balance();
					// 3.2 both the left and right child of searchResultNode is not null
				} else if (searchResultNode.getLeft() != null && searchResultNode.getRight() != null) {
					int minValue = getAndDeleteRightTreeMinValue(searchResultNode.getRight());
					searchResultNode.setValue(minValue);
					this.root.balance();
					// 3.3 left child is not null
				} else if (searchResultNode.getLeft() != null && searchResultNode.getRight() == null) {
					parent.setLeft(searchResultNode.getLeft());
					this.root.balance();
					// 3.4 right child is not null
				} else {
					parent.setRight(searchResultNode.getRight());
					this.root.balance();
				}
			}

		}

		// get the min value in the right subtree and remove the corresponding node
		private int getAndDeleteRightTreeMinValue(Node node) throws ValueNotFoundException {

			while (node.getLeft() != null) {
				node = node.getLeft();
			}

			int minimal = node.getValue();
			// delete the minimal node
			delete(minimal);
			return minimal;

		}

		private Node searchParent(Node node, int value) {

			if (node.getValue() == value)
				return null;
			Node target = null;
			if (node.getLeft() != null) {
				if (node.getLeft().getValue() == value) {
					return node;
				} else {
					target = searchParent(node.getLeft(), value);
					if (target != null)
						return target;
				}

			}
			if (node.getRight() != null) {
				if (node.getRight().getValue() == value) {
					return node;
				} else {
					target = searchParent(node.getRight(), value);
					if (target != null)
						return target;
				}

			}

			return null;
		}

		@Override
		public String toString() {
			return this.root.toString();
		}
		
		
	}

	static class ValueNotFoundException extends Exception {

		private static final long serialVersionUID = 1L;

		public ValueNotFoundException() {
			super();
		}

		public ValueNotFoundException(String message) {
			super(message);
		}

		public ValueNotFoundException(String message, Throwable cause) {
			super(message, cause);
		}
	}

}
package indi.tom.dataStructure.avltree;

/**
 * @Author: Tom
 * @Date: 2021年1月4日 下午9:20:45
 * @Version: 1.0
 * @Description:
 */
class Node {

	private int value;
	private Node left, right;

	public Node(int value) {
		super();
		this.value = value;

	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}

	public Node getLeft() {
		return left;
	}

	public void setLeft(Node left) {
		this.left = left;
	}

	public Node getRight() {
		return right;
	}

	public void setRight(Node right) {
		this.right = right;
	}

	// InOrder traverse
	public void inOrder() {
		if (this.left != null) {
			this.left.inOrder();
		}
		System.out.println(value);
		if (this.right != null) {
			this.right.inOrder();
		}
	}

	// search
	public Node search(int value) {
		Node target = null;
		if (this.value == value)
			return this;
		if (this.left != null) {
			target = this.left.search(value);
			if (target != null)
				return target;
		}
		if (this.right != null) {
			target = this.right.search(value);
			if (target != null)
				return target;
		}
		return null;
	}

	// add

	public Node add(int value) {

		Node target = new Node(value);
		// 1. add new node to the right
		if (this.value <= value) {
			// 1.1 if right == null, add to right directly
			if (this.right == null) {
				this.right = target;
				// 1.2 if right != null, call right.add() recursively
			} else {
				this.right.add(value);
				// 1.2.1 compare the left and right subtree, if the difference is greater than
				// 1, adjust it

				// a. left rotate the entire tree (this is possible as right subtree add one)
				if (right.height() - (left == null ? 0 : left.height()) > 1) {
					// before left rotate the entire tree, check if the right.left > right.right, if
					// so, right rotate the right subtree
					if ((right.left == null ? 0 : right.left.height()) > (right.right == null ? 0
							: right.right.height())) {
						right.rightRotate();
						// then check if the entire tree, right.height - left.heitht > 1, if so, left
						// rotate the entire tree
						if ((right.height() - (left == null ? 0 : left.height())) > 1) {
							this.leftRotate();
						}
					} else if ((right.right == null ? 0 : right.right.height()) > (right.left == null ? 0
							: right.left.height())) {
						this.leftRotate();
						// The last case is right.right.height()=right.left.height(), but it's not
						// possible because before add to the right,
						// it must be that right.height > left.height, then it's possible right.height()
						// - left.height() > 1.
						// So before add, it must be right.height - left.right = 1, then add 1 node to
						// right, if right.left.height = right.right.height,
						// then the right subtree height must has no change
					} /*
						 * else if(right.right.height() == right.left.height()) {this is not possible
						 * under the condition that (right.height() - left.height()) > 1}
						 */
				} /* else if(left.height() - right.height() > 1) {this is no possible} */

			}

			// 2. add new node to the left
		} else {
			// 2.1 if left == null, add to left directly
			if (this.left == null) {
				this.left = target;
				// 2.2 if left != null, call left.add() recursively
			} else {
				this.left.add(value);
				if ((left.height() - (right == null ? 0 : right.height())) > 1) {
					// if(left.right.height()>left.left.height()), left rotate the left subtree,
					// then check if left.height - right.height still > 1, if so,
					// right rotate the entire tree
					if ((left.right == null ? 0 : left.right.height()) > (left.left == null ? 0 : left.left.height())) {
						left.leftRotate();
						if ((left.height() - right.height()) > 1) {
							this.rightRotate();
						}
					} else if ((left.right == null ? 0 : left.right.height()) < (left.left == null ? 0
							: left.left.height())) {
						this.rightRotate();
					} /*
						 * else if(eft.right.height()<left.left.height()) {this is not possible under
						 * the condition that (left.height() - right.height()) > 1}
						 */

				} /* else if((right.height()-left.height()) > 1) {this is not gonna happen} */

			}
		}
		return target;

	}

	// adjust the entire tree to make sure it's a balancing search tree
	public void balance() {
		if (this.left == null && this.right == null) {
			return;
		} else if (this.left == null && this.right != null) {
			if (right.height() > 1) {
				// left rotate
				this.leftRotate();
			}

		} else if (this.left != null && this.right == null) {
			if (left.height() > 1) {
				this.rightRotate();
			}

		} else if (this.left != null && this.right != null) {
			if ((left.height() - right.height()) > 1) {
				// if(left.right.height()>left.left.height()), left rotate the left subtree,
				// then check if left.height - right.height still > 1, if so,
				// right rotate the entire tree
				if (left.right.height() > left.left.height()) {
					left.leftRotate();
					if ((left.height() - right.height()) > 1) {
						this.rightRotate();
					}
				} else if (left.right.height() < left.left.height()) {
					this.rightRotate();
				}

			} else if ((right.height() - left.height()) > 1) {
				// before left rotate the entire tree, check if the right.left > right.right, if
				// so, right rotate the right subtree
				if (right.left.height() > right.right.height()) {
					right.rightRotate();
					// then check if the entire tree, right.height - left.heitht > 1, if so, left
					// rotate the entire tree
					if ((right.height() - left.height()) > 1) {
						this.leftRotate();
					}
				} else if (right.right.height() >= right.left.height()) {
					this.leftRotate();

				}

			}
		}

	}

	// right rotate
	public void rightRotate() {
		
		// original = root = this
		// create a new Node for the original root node
		Node newNode = new Node(value);
		// new node.right = root.right
		newNode.right = this.right;
		// new node.eft = root.left.right
		newNode.left = this.left.right;
		// root.value = left.value;
		this.value = left.value;
		// root.right = new node
		this.right = newNode;
		// root.left = left.left
		this.left = left.left;
	}

	// left rotate
	public void leftRotate() {
		
		// root = this
		// clone the current root node
		Node newNode = new Node(this.value);
		// newNode.left = root.left
		newNode.left = this.left;
		// newNode.right = root.right.left
		newNode.right = this.right.left;
		// root.value = right.value
		this.value = right.value;
		// root.right = right.right
		this.right = right.right;
		// root.left = newNode
		this.left = newNode;

	}

	// calculate height
	public int height() {
		if (left != null && right == null) {
			
			return left.height() + 1;
		} else if (left == null && right != null) {
			return right.height() + 1;
		} else if (left != null && right != null) {
			return Math.max(left.height(), right.height()) + 1;
		} else {
			return 1;
		}

	}

	@Override
	public String toString() {
		return "Node [value=" + value + ", left=" + left + ", right=" + right + "]";
	}

	

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值