1、二叉排序树BST
Binary Sort Tree:对于二叉排序树的任何一个非叶子节点,要求其左子节点的值比当前节点的值小,右子节点的值比当前节点的值大。
1.1 创建二叉排序树并遍历
将一个数组创建成对应的二叉排序树,并使用中序遍历二叉排序树,因为中序遍历一个二叉排序树得出的序列是有序的。
1、Node节点类:
public class Node {
private int value;
private Node left;
private Node right;
public Node(int value) {
this.value = value;
}
/**
* 递归添加节点的方法
* @param node
*/
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);
}
return;
}
if(node.value>this.value){
if(this.right==null){
this.right = node;
}else{
this.right.add(node);
}
}
}
/**
* 中序遍历的方法
*/
public void infixOrder(){
if(this.left!=null){
this.left.infixOrder();
}
System.out.println(this);
if(this.right!=null){
this.right.infixOrder();
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
}
2、BinarySortTree二叉排序树:
public class BinarySortTree {
private Node root;
public void add(Node node){
if(root==null){
root = node;
}else{
root.add(node);
}
}
public void infixOrder(){
if(root!=null){
root.infixOrder();
}else{
System.out.println("树为空");
}
}
}
3、测试类:
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr = {7,3,10,12,5,1,9};
BinarySortTree binarySortTree = new BinarySortTree();
for(int i=0;i<arr.length;i++){
binarySortTree.add(new Node(arr[i]));
}
binarySortTree.infixOrder();
}
}
1.2 二叉排序树删除节点
1. 删除叶子节点思路:
1、先要找到要删除的节点targetNode
2、找到要删除节点的父节点parentNode
3、如果targetNode是parentNode的左子节点,parentNode.left = null
4、如果targetNode是parentNode的右子节点,parentNode.right = null
2. 删除只有一颗子树的节点思路:
1、先要找到要删除的节点targetNode
2、找到要删除节点的父节点parentNode
3、如果targetNode的子节点是左子节点:
若targetNode是parentNode的左子节点,parentNode.left = targetNode.left
若targetNode是parentNode的右子节点,parentNode.right= targetNode.left
4、如果targetNode的子节点是右子节点:
若targetNode是parentNode的左子节点,parentNode.left = targetNode.right
若targetNode是parentNode的右子节点,parentNode.right=targetNode.right
3. 删除只有两颗子树的节点思路:
1、先要找到要删除的节点targetNode
2、找到要删除节点的父节点parentNode
3、从targetNode的右子树找到最小的节点
4、用一个临时变量,将最小节点的值保存在temp中
5、删除最小节点
6、targetNode.value = temp
(1)节点类Node:
public class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
/**
* 查询要删除的节点
* @param value 要删除节点的值
* @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);
}
}
/**
* 查找要删除的节点的父节点
* @param value 要删除的节点的值
* @return
*/
public Node parentSearch(int value) {
if (this.left != null && value == this.left.value || this.right != null && value == this.right.value) {
return this;
}else{
if (value < this.value && this.left != null) {
return this.left.parentSearch(value);
} else if (value > this.value && this.right != null) {
return this.right.parentSearch(value);
}else{
return null;
}
}
}
}
(2)BinarySortTree二叉排序树:
public class BinarySortTree {
private Node root;
/**
* @param node 传入的节点
* @return 返回以node为根节点的二叉排序树的最小节点的值
*/
public int delRightTreeMin(Node node){
Node target = node;
//向左递归找最小节点
while(target.left!=null){
target = target.left;
}
//删除这个最小节点
delNode(target.value);
return target.value;
}
public void delNode(int value){
if(root==null){
return;
}else{
//只有一个根节点,将其删除即可
if(root.left==null && root.right==null){
root = null;
return;
}
//找到要删除的节点
Node targetNode = root.search(value);
if(targetNode==null){
return;
}
//找到要删除的节点的父节点
Node parentNode = root.parentSearch(value);
/**
* 如果要删除的节点是叶子节点
*/
if(targetNode.left==null && targetNode.right==null){
if(parentNode.left!=null && parentNode.left.value == value){
parentNode.left = null;
}else if(parentNode.right!=null && parentNode.right.value==value){
parentNode.right = null;
}
/**
* 如果要删除的节点是由两颗子树的节点
*/
}else if(targetNode.left!=null && targetNode.right!=null){
int minVlalue = delRightTreeMin(targetNode.right);
targetNode.value = minVlalue;
/**
* 如果删除的节点是有一颗子树的节点
*/
}else{
//如果要删除的节点有左子节点
if(targetNode.left!=null){
if(parentNode.left.value == value){
parentNode.left = targetNode.left;
}else if(parentNode.right.value==value){
parentNode.right = targetNode.left;
}
//如果要删除的节点有右子节点
}else{
if(parentNode.left.value ==value){
parentNode.left = targetNode.right;
}else if(parentNode.right.value==value){
parentNode.right = targetNode.right;
}
}
}
}
}
//查找要删除的节点
public Node search(int value){
if(root==null){
return null;
}else{
return root.search(value);
}
}
//查找要删除的节点的父节点
public Node parentSearch(int value){
if(root==null){
return null;
}else{
return root.parentSearch(value);
}
}
}
(3)BinarySortTreeDemo测试类:
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr = {7,3,10,12,5,1,9,2};
BinarySortTree binarySortTree = new BinarySortTree();
for(int i=0;i<arr.length;i++){
binarySortTree.add(new Node(arr[i]));
}
binarySortTree.delNode(1);
binarySortTree.infixOrder();
}
}
2、平衡二叉排序树AVL树
为了防止二叉搜索树退化为链表
特点:它是一颗空树或他的左右两颗子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。
2.1 左旋转
2.2 右旋转
2.3 双旋转
(1)Node节点类:
public class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
//返回以当前节点为根节点的树的高度
public int height(){
return Math.max(left==null ? 0:left.height(),right==null ? 0:right.height())+1;
}
//返回左子树的高度
public int leftHeight(){
if(left==null){
return 0;
}
return left.height();
}
//返回右子树的高度
public int rightHeight(){
if(right==null){
return 0;
}
return right.height();
}
//左旋转
public void leftRotate(){
Node newNode = new Node(value);
newNode.left = this.left;
newNode.right = this.right.left;
this.value = this.right.value;
this.right = this.right.right;
this.left = newNode;
}
//右旋转
public void rightRotate(){
Node newNode = new Node(value);
newNode.right = this.right;
newNode.left = this.left.right;
this.value = this.left.value;
this.left = this.left.left;
this.right = newNode;
}
/**
* 递归添加节点的方法
* @param node
*/
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);
}
}
if(node.value>this.value){
if(this.right==null){
this.right = node;
}else{
this.right.add(node);
}
}
//左旋转
if(rightHeight()-leftHeight()>1){
if(right!=null && right.leftHeight()>left.leftHeight()){
right.rightRotate();
leftHeight();
}else{
leftRotate();
}
}
//右旋转
if(leftHeight()-rightHeight()>1){
if(left!=null && left.rightHeight()>left.leftHeight()){
left.leftRotate();
rightRotate();
}else{
rightRotate();
}
}
}
/**
* 中序遍历的方法
*/
public void infixOrder(){
if(this.left!=null){
this.left.infixOrder();
}
System.out.println(this);
if(this.right!=null){
this.right.infixOrder();
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
}
(2)AVLTree类:
public class AVLTree {
private Node root;
public Node getRoot() {
return root;
}
public void setRoot(Node root) {
this.root = root;
}
//添加节点
public void add(Node node){
if(root==null){
root = node;
}else{
root.add(node);
}
}
//中序遍历二叉搜索树
public void infixOrder(){
if(root!=null){
root.infixOrder();
}else{
System.out.println("树为空");
}
}
}
(3)测试类:
public class AVLTreeDemo {
public static void main(String[] args) {
// int[] arr = {4,3,6,5,7,8};
// int[] arr = {10,12,8,9,7,6};
int[] arr = {3,2,6,5,7,4};
AVLTree avlTree = new AVLTree();
for(int i=0;i<arr.length;i++){
avlTree.add(new Node(arr[i]));
}
avlTree.infixOrder();
System.out.println("没有平衡处理时树的高度:"+avlTree.getRoot().height());
// System.out.println("左子树的高度:"+avlTree.getRoot().leftHeight());
// System.out.println("右子树的高度:"+avlTree.getRoot().rightHeight());
// avlTree.getRoot().leftRotate();
avlTree.getRoot().leftRotate();
System.out.println("平衡处理后树的高度:"+avlTree.getRoot().height());
}
}