数据结构和算法(二叉排序树、二叉排序树结点增加、删除和AVL树转化 [ 左旋转、右旋转 ] )

二叉排序树:

在这里插入图片描述
在这里插入图片描述

二叉排序树 删除结点的三种情况:

第一种情况:
删除叶子节点 (比如:2, 5, 9, 12)
思路
(1) 需求先去找到要删除的结点 targetNode
(2) 找到targetNode 的 父结点 parent
(3) 确定 targetNode 是 parent的左子结点 还是右子结点
(4) 根据前面的情况来对应删除
左子结点 parent.left = null
右子结点 parent.right = null;
第二种情况:
删除只有一颗子树的节点 比如 1
思路
(1) 需求先去找到要删除的结点 targetNode
(2) 找到targetNode 的 父结点 parent
(3) 确定targetNode 的子结点是左子结点还是右子结点
(4) targetNode 是 parent 的左子结点还是右子结点
(5) 如果targetNode 有左子结点
5. 1 如果 targetNode 是 parent 的左子结点
parent.left = targetNode.left;
5.2 如果 targetNode 是 parent 的右子结点
parent.right = targetNode.left;
(6) 如果targetNode 有右子结点
6.1 如果 targetNode 是 parent 的左子结点
parent.left = targetNode.right;
6.2 如果 targetNode 是 parent 的右子结点
parent.right = targetNode.right

第三种情况 :
删除有两颗子树的节点. (比如:7, 3,10 )
思路
(1) 需求先去找到要删除的结点 targetNode
(2) 找到targetNode 的 父结点 parent
(3) 从targetNode 的右子树找到最小的结点
(4) 用一个临时变量,将 最小结点的值保存 temp = 11
(5) 删除该最小结点
(6) targetNode.value = temp

二叉排序树和相应操作实现:

public class BinaryTreeSort {
	public static void main(String[] args) {
		int[] arr = { 7, 3, 10, 12, 5, 1, 9 };
		BinarySortTree tree = new BinarySortTree();
		for (int i = 0; i < arr.length; i++) {
			tree.add(new Node(arr[i]));
		}
		tree.infixOrder();
	}
}

class BinarySortTree {
	public Node rootNode;

	public void add(Node node) {
		if (rootNode == null) {
			this.rootNode = node;
		} else {
			rootNode.add(node);
		}
	}

	public void delNode(int value) {
		if (rootNode == null) {
			return;
		} else {
			Node targetNode = rootNode.search(value);
			// 发现要删除的结点不存在,直接返回
			if (targetNode == null) {
				return;
			}
			// 找到了结点,如果此时树里只有这一个结点,则说明要删除最有一个结点
			if (rootNode.leftNode == null && rootNode.rightNode == null) {
				rootNode = null;
				return;
			}
			//
			Node parentNode = rootNode.searchParent(value);

			// 如果删除的结点是叶子结点
			if (targetNode.leftNode == null && targetNode.rightNode == null) {
				// 如果要删除的结点是父节点的左节点
				if (parentNode != null)
					if (parentNode.leftNode != null && parentNode.leftNode.value == targetNode.value) {
						parentNode.leftNode = null;
					} else if (parentNode.rightNode != null && parentNode.rightNode.value == targetNode.value) {
						parentNode.rightNode = null;
					}

				// 要删除的结点右两颗子树
			} else if (targetNode.leftNode != null && targetNode.rightNode != null) {
//				int min = delRightTreeMin(targetNode.rightNode);
//				targetNode.value = min;

				int max = delLeftTreeMax(targetNode.leftNode);
				targetNode.value = max;

				// 两种方法:
				// 找到右子树最小结点,覆盖要删除的结点数据,删除右子树找到的那个结点
				// 找到左子树最大结点,覆盖要删除的结点数据,删除左子树找到的那个结点
				// 要删除的结点有一颗子树
			} else {
				if (targetNode.leftNode != null) {
					if (parentNode != null) {
						if (parentNode.leftNode.value == value) {
							parentNode.leftNode = targetNode.leftNode;
						} else {
							parentNode.rightNode = targetNode.leftNode;
						}
					} else {
						rootNode = targetNode.leftNode;
					}
				} else {
					if (parentNode != null) {
						if (parentNode.leftNode.value == value) {
							parentNode.leftNode = targetNode.rightNode;
						} else {
							parentNode.rightNode = targetNode.rightNode;
						}
					} else {
						rootNode = targetNode.rightNode;
					}
				}
			}
		}

	}

	public Node search(int value) {
		if (rootNode == null) {
			return null;
		} else {
			return rootNode.search(value);
		}
	}

	public Node searchParent(int value) {
		if (rootNode == null) {
			return null;
		} else {
			return rootNode.searchParent(value);
		}

	}

	public void infixOrder() {
		if (rootNode == null) {
			System.out.println("为空");
		} else {
			rootNode.infixOrder();
		}
	}

	/**
	 * 删除左子树的最大结点
	 * 
	 * @param node 父节点
	 * @return 最大节点值
	 */
	public int delLeftTreeMax(Node node) {
		Node targetNode = node;
		while (targetNode.rightNode != null) {
			targetNode = targetNode.rightNode;
		}
		delNode(targetNode.value);
		return targetNode.value;
	}

	/**
	 * 删除右子树的最小结点
	 * 
	 * @param node 父节点
	 * @return 最小结点的值
	 */
	public int delRightTreeMin(Node node) {
		Node targetNode = node;

		// 找到最小的,一直向左循环
		while (targetNode.leftNode != null) {
			targetNode = targetNode.leftNode;
		}
		delNode(targetNode.value);
		return targetNode.value;

	}
}

class Node {
	int value;
	Node rightNode;
	Node leftNode;

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

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

	public Node search(int value) {
		if (this.value == value) {
			return this;
		}
		if (value < this.value) {
			if (this.leftNode != null) {
				return this.leftNode.search(value);
			} else {
				return null;
			}
		} else {
			if (this.rightNode != null) {
				return this.rightNode.search(value);
			} else {
				return null;
			}
		}
	}

	public Node searchParent(int value) {
		// 如果当前结点的子节点就是寻找的结点,则返回
		if ((this.leftNode != null && this.leftNode.value == value)
				|| (this.rightNode != null && this.rightNode.value == value)) {
			return this;
		} else {
			// 如果查找的值小于当前结点的值
			if (value < this.value && this.leftNode != null) {
				return this.leftNode.searchParent(value);
			} else if (value >= this.value && this.rightNode != null) {
				return this.rightNode.searchParent(value);
			} else {
				return null;
			}
		}

	}

	public void infixOrder() {
		if (this.leftNode != null) {
			this.leftNode.infixOrder();
		}
		System.out.println(this);
		if (this.rightNode != null) {
			this.rightNode.infixOrder();
		}
	}

	public void add(Node node) {
		if (node == null) {
			return;
		}
		if (node.value > this.value) {
			if (this.rightNode != null) {
				this.rightNode.add(node);
			} else {
				this.rightNode = node;
			}
		} else {
			if (this.leftNode != null) {
				this.leftNode.add(node);
			} else {
				this.leftNode = node;
			}
		}
	}

}

平衡二叉树(AVL树):

在这里插入图片描述

左旋转(将头结点左下旋转):

在这里插入图片描述

右旋转(将头结点右下旋转):

在这里插入图片描述
平衡二叉树其实是二叉排序树的升级版:

双旋转:

有时即使使用了旋转,左右子树的高度差依然大于1,这时需要先对(左\右)子树进行旋转,再对根结点进行旋转。

AVL树代码示例:

package bst;

public class AVLTreeDemo {
	public static void main(String[] args) {
		int[] arr = { 10, 11, 7, 6, 8, 9 };

		AVLTree avlTree = new AVLTree();
		for (int i = 0; i < arr.length; i++) {
			avlTree.add(new Node2(arr[i]));
		}

		avlTree.infixOrder();
	}
}

class AVLTree {
	public Node2 rootNode;

	public void add(Node2 node) {
		if (rootNode == null) {
			this.rootNode = node;
		} else {
			rootNode.add(node);
		}
	}

	public void delNode(int value) {
		if (rootNode == null) {
			return;
		} else {
			Node2 targetNode = rootNode.search(value);
			// 发现要删除的结点不存在,直接返回
			if (targetNode == null) {
				return;
			}
			// 找到了结点,如果此时树里只有这一个结点,则说明要删除最有一个结点
			if (rootNode.leftNode == null && rootNode.rightNode == null) {
				rootNode = null;
				return;
			}
			//
			Node2 parentNode = rootNode.searchParent(value);

			// 如果删除的结点是叶子结点
			if (targetNode.leftNode == null && targetNode.rightNode == null) {
				// 如果要删除的结点是父节点的左节点
				if (parentNode != null)
					if (parentNode.leftNode != null && parentNode.leftNode.value == targetNode.value) {
						parentNode.leftNode = null;
					} else if (parentNode.rightNode != null && parentNode.rightNode.value == targetNode.value) {
						parentNode.rightNode = null;
					}

				// 要删除的结点右两颗子树
			} else if (targetNode.leftNode != null && targetNode.rightNode != null) {
//				int min = delRightTreeMin(targetNode.rightNode);
//				targetNode.value = min;

				int max = delLeftTreeMax(targetNode.leftNode);
				targetNode.value = max;

				// 两种方法:
				// 找到右子树最小结点,覆盖要删除的结点数据,删除右子树找到的那个结点
				// 找到左子树最大结点,覆盖要删除的结点数据,删除左子树找到的那个结点
				// 要删除的结点有一颗子树
			} else {
				if (targetNode.leftNode != null) {
					if (parentNode != null) {
						if (parentNode.leftNode.value == value) {
							parentNode.leftNode = targetNode.leftNode;
						} else {
							parentNode.rightNode = targetNode.leftNode;
						}
					} else {
						rootNode = targetNode.leftNode;
					}
				} else {
					if (parentNode != null) {
						if (parentNode.leftNode.value == value) {
							parentNode.leftNode = targetNode.rightNode;
						} else {
							parentNode.rightNode = targetNode.rightNode;
						}
					} else {
						rootNode = targetNode.rightNode;
					}
				}
			}
		}

	}

	public Node2 search(int value) {
		if (rootNode == null) {
			return null;
		} else {
			return rootNode.search(value);
		}
	}

	public Node2 searchParent(int value) {
		if (rootNode == null) {
			return null;
		} else {
			return rootNode.searchParent(value);
		}

	}

	public void infixOrder() {
		if (rootNode == null) {
			System.out.println("为空");
		} else {
			rootNode.infixOrder();
		}
	}

	/**
	 * 删除左子树的最大结点
	 * 
	 * @param node 父节点
	 * @return 最大节点值
	 */
	public int delLeftTreeMax(Node2 node) {
		Node2 targetNode = node;
		while (targetNode.rightNode != null) {
			targetNode = targetNode.rightNode;
		}
		delNode(targetNode.value);
		return targetNode.value;
	}

	/**
	 * 删除右子树的最小结点
	 * 
	 * @param node 父节点
	 * @return 最小结点的值
	 */
	public int delRightTreeMin(Node node) {
		Node targetNode = node;

		// 找到最小的,一直向左循环
		while (targetNode.leftNode != null) {
			targetNode = targetNode.leftNode;
		}
		delNode(targetNode.value);
		return targetNode.value;

	}
}

class Node2 {
	int value;
	Node2 rightNode;
	Node2 leftNode;

	public int leftHeight() {
		if (leftNode == null) {
			return 0;
		}
		return leftNode.height();
	}

	public int rightHeight() {
		if (rightNode == null) {
			return 0;
		}
		return rightNode.height();
	}

	public int height() {
		return Math.max(leftNode == null ? 0 : leftNode.height(), rightNode == null ? 0 : rightNode.height()) + 1;

	}

	// 传入头结点
	public void rightRotate() {
		// 定义新的结点,为头结点的副本
		Node2 newNode = new Node2(value);
		// 新节点接管原头结点的右节点
		newNode.rightNode = this.rightNode;
		// 新节点接管原头结点的左子结点的右子节点
		newNode.leftNode = this.leftNode.rightNode;
		// 至此在树的结构不发生变化的情况下,新的结点完成了原头结点的任务
		// 原头结点可以被覆盖了
		// 用左节点的值覆盖原头结点
		this.value = leftNode.value;
		// 此时左节点成为垃圾,接管左子树(右子树已被接管)
		this.leftNode = this.leftNode.leftNode;
		// 将副本结点加入树结构
		this.rightNode = newNode;
//		Node2 temp = this.leftNode;
//		this.leftNode = temp.rightNode;
//		temp.rightNode = this;
//		

	}

	public void leftRotate() {
		// 创建新的结点,用当前结点的值
		Node2 newNode = new Node2(value);
		// 把新结点的左子树设置成当前结点的左子树
		newNode.leftNode = this.leftNode;

		// 把新结点的右子树设置为当前结点的右子树的左子树
		newNode.rightNode = this.rightNode.leftNode;
		// 把当前结点的值替换成右子结点的值
		this.value = this.rightNode.value;
		// 把当前结点的右子树设置成当前结点的右子树的右子树
		this.rightNode = this.rightNode.rightNode;
		// 把当前结点的左子树设置为新的结点
		leftNode = newNode;

	}

	public Node2(int value) {
		this.value = value;
	}

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

	public Node2 search(int value) {
		if (this.value == value) {
			return this;
		}
		if (value < this.value) {
			if (this.leftNode != null) {
				return this.leftNode.search(value);
			} else {
				return null;
			}
		} else {
			if (this.rightNode != null) {
				return this.rightNode.search(value);
			} else {
				return null;
			}
		}
	}

	public Node2 searchParent(int value) {
		// 如果当前结点的子节点就是寻找的结点,则返回
		if ((this.leftNode != null && this.leftNode.value == value)
				|| (this.rightNode != null && this.rightNode.value == value)) {
			return this;
		} else {
			// 如果查找的值小于当前结点的值
			if (value < this.value && this.leftNode != null) {
				return this.leftNode.searchParent(value);
			} else if (value >= this.value && this.rightNode != null) {
				return this.rightNode.searchParent(value);
			} else {
				return null;
			}
		}

	}

	public void infixOrder() {
		if (this.leftNode != null) {
			this.leftNode.infixOrder();
		}
		System.out.println(this);
		if (this.rightNode != null) {
			this.rightNode.infixOrder();
		}
	}

	public void add(Node2 node) {
		if (node == null) {
			return;
		}
		if (node.value > this.value) {
			if (this.rightNode != null) {
				this.rightNode.add(node);
			} else {
				this.rightNode = node;
			}
		} else {
			if (this.leftNode != null) {
				this.leftNode.add(node);
			} else {
				this.leftNode = node;
			}
		}
		// 如果右子树的高度 大于 左子树的高度,左旋转
		if (rightHeight() - leftHeight() > 1) {
			if (rightNode != null && rightNode.leftHeight() > rightNode.rightHeight()) {
				rightNode.rightRotate();
				leftRotate();
			} else {
				leftRotate();
			}
			return;
		}
		if (leftHeight() - rightHeight() > 1) {
			// 如果它的左子树的右子树高度大于它的右子树的高度
			if (leftNode != null && leftNode.rightHeight() > leftNode.leftHeight()) {
				// 先对当前结点的左节点(左子树) -> 左旋转
				leftNode.leftRotate();
				// 再对当前结点进行右旋转
				rightRotate();
			} else {
				// 如果不满足,直接进行右旋转接可
				rightRotate();
			}
			return;
		}

	}

}
发布了68 篇原创文章 · 获赞 12 · 访问量 5195

猜你喜欢

转载自blog.csdn.net/qq_40963076/article/details/105317360