Java实现AVL树详细注释解释代码

引入

此文章记录我学习的笔记,写的不好见谅。

1.AVL树是特殊的二叉搜索树,除了保持原有的二叉搜索树特性,还会一直保持搜索节点的时间复杂度为log(N)。

2.与二叉搜索树的不同于:节点增加一个高度的变量来记录此时的高度。

3.AVL树核心在于旋转,分为:左旋、右旋、左右旋、右左旋

代码

  • Java实现代码
import java.util.Stack;

public class AvlBinaryTree {
	/* 插入节点,3种情况
	1.往左边插,计算后的高度若失衡,需要右旋或者左右旋转
	2.往右边插,计算后的高度若失衡,需要左旋或者右左旋转
	3.找到适当位置,把当前节点new出来,并返回去
	*/
	public AvlTreeNode insert(AvlTreeNode treenode, int x){
		if(treenode == null){
			treenode = new AvlTreeNode(x);
		}else if(x < treenode.val){
			// 往左边插入
			treenode.leftNode = insert(treenode.leftNode, x);
			// 需要计算是否失衡
			if(treenode.leftNode != null && treenode.rightNode != null){
				// 根据高度来判断是否失衡,往左边插入,一定是左边减去右边高度
				if(treenode.leftNode.height - treenode.rightNode.height >= 2){
					// 判断插入的节点是否在左边节点的右边,这样需要发生左右旋
					if(x > treenode.leftNode.val){
						treenode = leftRightRoation(treenode);
					}else{
						// 若只在左边只需要右旋
						treenode = rightRoation(treenode);
					}
				}
			}
		}else if(x > treenode.val){
			// 往右边插入
			treenode.rightNode = insert(treenode.rightNode, x);
			// 需要计算是否失衡
			if(treenode.leftNode != null && treenode.rightNode != null){
				// 根据高度来判断是否失衡,往右边插入,一定是右边减去左边高度
				if(treenode.rightNode.height - treenode.leftNode.height >= 2){
					// 判断插入的节点是否在右边节点的左边,这样需要发生右左旋
					if(x < treenode.rightNode.val){
						// 发生右左旋
						treenode = rightLeftRoation(treenode);
					}else{
						// 若只在右边只需要左旋
						treenode = leftRoation(treenode);
					}
				}
			}
		}
		// 更新自己的树高,根据自己左右节点的高度来得到自身的高度
		treenode.height = mymax(treenode.leftNode, treenode.rightNode) + 1;
		return treenode;
	}
	
	// 旋转操作
	// 左旋
	public AvlTreeNode leftRoation(AvlTreeNode avlnode){
		// 总:把当前节点的右节点的左节点当做自己的右孩子,自己当做右节点的左孩子
		// 1.提取右节点节点
		AvlTreeNode rightnd = avlnode.rightNode;
		// 2.将右节点的左节点当做父节点的右孩子
		avlnode.rightNode = rightnd.leftNode;
		// 3.将父节点当做右节点的左节点
		rightnd.leftNode = avlnode;
		
		// 这里要重新更新大小
		// 先更新子节点的avlnode,再更新(新)头节点 rightnd
		avlnode.height = mymax(avlnode.leftNode, avlnode.rightNode) + 1;
		rightnd.height = mymax(rightnd.leftNode, rightnd.rightNode) + 1;
		return rightnd;
	}
	
	// 右旋
	public AvlTreeNode rightRoation(AvlTreeNode avlnode){
		// 总:把当前节点的左节点的右节点当做自己的左孩子,自己当做左节点的右孩子
		// 1.提取左边节点节点
		AvlTreeNode leftnd = avlnode.leftNode;
		// 2.将左节点的右节点当做父节点的左孩子
		avlnode.leftNode = leftnd.rightNode;
		// 3.将父节点当做左节点的右节点
		leftnd.rightNode = avlnode;
		
		// 这里要重新更新大小
		// 先更新子节点的avlnode,再更新(新)头节点 leftnd的高度
		avlnode.height = mymax(avlnode.leftNode, avlnode.rightNode) + 1;
		leftnd.height = mymax(leftnd.leftNode, leftnd.rightNode) + 1;
		return leftnd;
	}
	// 右左旋
	public AvlTreeNode rightLeftRoation(AvlTreeNode avlnode){
		// 两次旋转,第一次:以右子节点右旋,第二次:根节点左旋
		avlnode.rightNode = rightRoation(avlnode.rightNode);
		avlnode = leftRoation(avlnode);
		return avlnode;
	}
	// 左右旋
	public AvlTreeNode leftRightRoation(AvlTreeNode avlnode){
		// 两次旋转,第一次:以左子节点左旋,第二次:根节点右旋
		avlnode.leftNode = leftRoation(avlnode.leftNode);
		avlnode = rightRoation(avlnode);
		return avlnode;
	}
	// 辅助操作
	// 处理高度左右节点高度对比
	public int mymax(AvlTreeNode left, AvlTreeNode right){
		if(left == null && right == null){
			return 0;
		}else if(left != null && right != null){
			return left.height > right.height ? left.height : right.height;
		}else if(left == null){
			return right.height;
		}else if(right == null){
			return left.height;
		}
		return 0;
	}
	
	// 遍历
	// 中序遍历
	public void midorder(AvlTreeNode curnode, boolean isprintheight){
		Stack<AvlTreeNode> stack = new Stack<>();
		while(curnode != null || !stack.isEmpty()){
			// 依次把左子树压入栈
			while(curnode != null){
				stack.push(curnode);
				curnode = curnode.leftNode;
			}
			// 遍历完左子树,弹出栈顶并访问
			curnode = stack.pop();
			if(isprintheight){
				System.out.print("节点:"+curnode.val+" 的高度:"+curnode.height+"; ");
			}else{
				System.out.print(curnode.val+" ");
			}
			// 变换为它的右节点继续中序遍历
			curnode = curnode.rightNode;
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		AvlBinaryTree ab = new AvlBinaryTree();
		
		// 构建树,测试发生左旋转的时候
		AvlTreeNode root = new AvlTreeNode(6);
		root = ab.insert(root, 4);
		root = ab.insert(root, 8);
		root = ab.insert(root, 7);
		root = ab.insert(root, 9);
		// root树根在不平衡的时候是会变的,此时增加此10的节点会发生不平衡,以6节点作左旋
		root = ab.insert(root, 10);
		ab.midorder(root, true);
		
		// 构建树,测试发生右旋转的时候
		root = new AvlTreeNode(6);
		root = ab.insert(root, 8);
		root = ab.insert(root, 4);
		root = ab.insert(root, 3);
		root = ab.insert(root, 5);
		// root树根在不平衡的时候是会变的,此时增加此2的节点会发生不平衡,以6节点作右旋
		root = ab.insert(root, 2);
		ab.midorder(root, true);
		
		// 构建树,测试发生右左旋转的时候
		root = new AvlTreeNode(8);
		root = ab.insert(root, 5);
		root = ab.insert(root, 16);
		root = ab.insert(root, 18);
		root = ab.insert(root, 15);
		// root树根在不平衡的时候是会变的,此时增加此14的节点会发生不平衡,先以16节点作右旋,再以8左旋
		root = ab.insert(root, 14);
		ab.midorder(root, true);
		
		// 构建树,测试发生左右旋转的时候
		root = new AvlTreeNode(16);
		root = ab.insert(root, 18);
		root = ab.insert(root, 10);
		root = ab.insert(root, 9);
		root = ab.insert(root, 11);
		// root树根在不平衡的时候是会变的,此时增加此12的节点会发生不平衡,先以10节点作左旋,再以16节点右旋
		root = ab.insert(root, 12);
		ab.midorder(root, true);
	}
}

  • 运行中序遍历的结果
    在这里插入图片描述

  • 对应的旋转过程(手画,不是很好看,见谅)
    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
AVL树是一种自平衡的二叉搜索树,它的升序遍历可以通过中序遍历来实现。下面是Java实现AVL树升序遍历的示例代码: ```java // AVL树节点定义 class Node { int key; int height; Node left; Node right; Node(int key) { this.key = key; this.height = 1; } } // AVL树类定义 class AVLTree { Node root; // 获取节点的高度 int getHeight(Node node) { if (node == null) { return 0; } return node.height; } // 更新节点的高度 void updateHeight(Node node) { node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1; } // 获取节点的平衡因子 int getBalanceFactor(Node node) { if (node == null) { return 0; } return getHeight(node.left) - getHeight(node.right); } // 右旋操作 Node rotateRight(Node y) { Node x = y.left; Node T2 = x.right; x.right = y; y.left = T2; updateHeight(y); updateHeight(x); return x; } // 左旋操作 Node rotateLeft(Node x) { Node y = x.right; Node T2 = y.left; y.left = x; x.right = T2; updateHeight(x); updateHeight(y); return y; } // 插入节点 Node insertNode(Node node, int key) { if (node == null) { return new Node(key); } if (key < node.key) { node.left = insertNode(node.left, key); } else if (key > node.key) { node.right = insertNode(node.right, key); } else { return node; // 不允许插入重复的节点 } updateHeight(node); int balanceFactor = getBalanceFactor(node); // 左旋操作 if (balanceFactor > 1 && key < node.left.key) { return rotateRight(node); } // 右旋操作 if (balanceFactor < -1 && key > node.right.key) { return rotateLeft(node); } // 左右旋操作 if (balanceFactor > 1 && key > node.left.key) { node.left = rotateLeft(node.left); return rotateRight(node); } // 右左旋操作 if (balanceFactor < -1 && key < node.right.key) { node.right = rotateRight(node.right); return rotateLeft(node); } return node; } // 中序遍历 void inorderTraversal(Node node) { if (node != null) { inorderTraversal(node.left); System.out.print(node.key + " "); inorderTraversal(node.right); } } } // 测试代码 public class Main { public static void main(String[] args) { AVLTree tree = new AVLTree(); tree.root = tree.insertNode(tree.root, 10); tree.root = tree.insertNode(tree.root, 20); tree.root = tree.insertNode(tree.root, 30); tree.root = tree.insertNode(tree.root, 40); tree.root = tree.insertNode(tree.root, 50); tree.root = tree.insertNode(tree.root, 25); System.out.println("AVL树的升序遍历结果:"); tree.inorderTraversal(tree.root); } } ``` 运行以上代码,输出结果为:10 20 25 30 40 50,即AVL树的升序遍历结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值