数据结构——————————————写avl树

这个树折磨了我两天,中间都不想写了,但是想想开始了,不写完好像缺点什么,所以就觉得还是写完吧

写一个二叉树难点旋转

麻烦点:获取其不平衡节点的父节点

以及不平衡节点


接下来写这个平衡二叉树

avl就是一颗平衡二叉树

什么是平衡二叉树呢?

继续先百度一波定义:

在AVL树中任何节点的两个子树的高度最大差为1。

这便是一个平衡二叉树,它每个节点的左右子树最大差在2以内

 

下来这个为不平衡的二叉树,红色节点的右子树深2,右子树为0,差值超过了1,所以不为平衡二叉树

为什么有平衡二叉树这个概念?

如果一个二叉查找树不改变,那么它会可能会变成一个链表,查找的时候时间复杂度为N,在使用二叉树时可能废掉大量时间,如果是一个平衡二叉树,那么查找起来它时间复杂度知只是大于logN,可以节省大量的时间。

造成不平衡的插入情况

当一个二叉查找树中插入一个数据时期使其成为不平衡的二叉树一共有4中可能

1.对a的左儿子左子树进行一次插入

插入1

10的左子树深度为3,右子树深度为1,差2

2.对a的左儿子的右子树进行一次插入

插入8

10的左子树深度为3,右子树深度为1,差2

3.对a的右儿子的左子树的进行一次插入

插入12

10的左子树深度为1,右子树深度为3,差2

4.对a的右儿子的右子树一次插入

插入25

15的左子树深度为0,右子树深度为2,差2

蓝色为插入的数据

a为不平衡的节点

1和4的情况相同,关于a是对称,所以只需要弄懂一种情况就可以了

2.3情况相同,也是关于a对称,只需要弄懂其中一个就可以了

不平衡的情况进行调节

1.单旋转

单旋转是来解决1和4情况的。

图:

我们主要说一下情况一

如图此时k1不平衡点,此时k2太深,那么我们应该如何做呢?

因为左边的树深右边浅,所以我们可以把右边加深,左变浅

这个时候我们可以把k2往上移一层,代替k1位置,

k1>k2,所以将k1变为k2右节点,

Y大于k2小于k1所以Y变为k1的左节点 。

变平衡后

1.4原理相同所以我也就不在写另外一个了

2.双旋转

双旋转是用来解决2和3问题的

图:

遇到2和3情况使用单旋转已经做不到了。

这个时候我们需要将k3往上移,我们把k3可以看成新的根

当我们把k3移到k1的位置,此刻我们应该如何变化呢?

k1<k3所以k3的左孩子为k1

k2>k3所以k3的左孩子为k2

B大于k1小于k3,所以B为k1的右子树

C大于3小于k2,所以C为k2的左子树

(B和C中有一个是null,不过这并不影响)

双旋转后:

2和3的思路是相同的,所以就不另外介绍了

代码

这里没有写删除节点如何调节平衡

删除和插入没有多少区别,先删除某一个节点,然后在判断这个树是否平衡

树节点代码:

package Tree;


public class TreeNode<T> {
	T t;//数据
	TreeNode<T> left;//左孩子
	TreeNode<T> right;//右孩子
    public TreeNode(T t){
		this.t=t;
	}
}

 调节平衡代码:

package Tree;

import java.util.Stack;

public class AVLTree {
	private TreeNode<Integer> treeRoot;
	// 插入在节点的左孩子的左子树
	public void LL(TreeNode<Integer> treeFather, TreeNode<Integer> node) {
		TreeNode<Integer> nodeLeftChild = node.left;
		TreeNode<Integer> nodeLeftChildRight = nodeLeftChild.right;

		nodeLeftChild.right = node;
		node.left = nodeLeftChildRight;
		if (treeFather == treeRoot) {
			treeRoot = nodeLeftChild;
		} else if (treeFather.left == node) {
			treeFather.left = nodeLeftChild;
		} else {
			treeFather.right = nodeLeftChild;
		}
	}

	// 插入右孩子右节点
	public void RR(TreeNode<Integer> treeFather, TreeNode<Integer> node) {
		TreeNode<Integer> nodeRightChild = node.right;
		TreeNode<Integer> nodeRightChildLeft = nodeRightChild.left;

		nodeRightChild.left = node;
		node.right = nodeRightChildLeft;

		if (treeFather == treeRoot) {
			treeRoot = nodeRightChild;
		} else if (treeFather.left == node) {
			treeFather.left = nodeRightChild;
		} else {
			treeFather.right = nodeRightChild;
		}
	}

	// 添加到左孩子的右子树
	public void LR(TreeNode<Integer> treeFather, TreeNode<Integer> node) {
		TreeNode<Integer> nodeLeft = node.left;
		TreeNode<Integer> nodeLeftChildRight = nodeLeft.right;
		TreeNode<Integer> nodeLeftChildRightChildLeft = nodeLeftChildRight.left;
		TreeNode<Integer> nodeLeftChileRightChildRight = nodeLeftChildRight.right;

		nodeLeftChildRight.left = nodeLeft;
		nodeLeftChildRight.right = node;
		nodeLeft.right = nodeLeftChildRightChildLeft;
		node.left = nodeLeftChileRightChildRight;

		if (treeFather == treeRoot) {
			treeRoot = nodeLeftChildRight;
		} else if (treeFather.left == node) {
			treeFather.left = nodeLeftChildRight;
		} else {
			treeFather.right = nodeLeftChildRight;
		}
	}

	// 添加到右孩子左子树
	public void RL(TreeNode<Integer> treeFather, TreeNode<Integer> node) {
		TreeNode<Integer> nodeRight = node.right;
		TreeNode<Integer> nodeRightChildLeft = nodeRight.left;
		TreeNode<Integer> nodeRightChildLeftRight = nodeRightChildLeft.right;
		TreeNode<Integer> nodeRightChildLeftLeft = nodeRightChildLeft.left;

		nodeRightChildLeft.right = nodeRight;
		nodeRightChildLeft.left = node;
		node.right = nodeRightChildLeftLeft;
		nodeRight.left = nodeRightChildLeftRight;

		if (treeFather == treeRoot) {
			treeRoot = nodeRightChildLeft;
		} else if (treeFather.left == node) {
			treeFather.left = nodeRightChildLeft;
		} else {
			treeFather.right = nodeRightChildLeftRight;
		}
	}

	// 判断节点树的深度
	private int length(TreeNode<Integer> node) {
		if (node == null) {
			return 0;
		}
		int left = length(node.left);
		int right = length(node.right);

		return 1 + ((left > right) ? left : right);
	}

	// 判断是否平衡
	private int balance(TreeNode<Integer> node) {
		int left = length(node.left);
		int right = length(node.right);
		return left - right;
	}

	// 查找节点的父节点
	//修改
	private TreeNode<Integer> findNodeFather(TreeNode<Integer> nodefather, TreeNode<Integer> node) {
		Stack<TreeNode<Integer>> stack1 = new Stack<>();
		    Stack<Integer> stack2 = new Stack<>();
		    int i = 1;
		    while(nodefather != null || !stack1.empty())
		    {
		        while (nodefather != null)
		        {
		            stack1.push(nodefather);
		            stack2.push(0);
		            nodefather = nodefather.left;
		        }
		        while(!stack1.empty() && stack2.peek() == i)
		        {
		            stack2.pop();
		            TreeNode<Integer> node1=stack1.pop();
		            if(node1.left==node||node1.right==node) {
		            	return node1;
		            }
		        }

		        if(!stack1.empty())
		        {
		            stack2.pop();
		            stack2.push(1);
		            nodefather = stack1.peek();
		            nodefather = nodefather.right;
		        }
		    }
		    return null;
	}

	// 使用哪一个旋转
	private void madeBalance(TreeNode<Integer> node) {
		TreeNode<Integer> nodeFather =treeRoot;
		int n = balance(node);//判断是哪个孩子过长导致不平衡
		int m;//判断是左(右)孩子哪个子树过长
		if (n>-2&&n<2) {
			return;
		} else if (n > 1) {
			
			if (node != treeRoot) {
				nodeFather=findNodeFather(nodeFather, node);
			}
			m = balance(node.left);
			
			if (m > 0) {
				LL(nodeFather, node);
			} else {
				LR(nodeFather, node);
			}
		} else {
		
			if (node != treeRoot) {
				nodeFather=findNodeFather(nodeFather, node);
			}
			m = balance(node.right);
			if (m > 0) {
				RL(nodeFather, node);
			} else {
				RR(nodeFather, node);
			}

		}
	}
	//找出不平衡的节点
	private void findNOBlance(TreeNode<Integer> node) {
		if(node==null) {
			return;
		}
		findNOBlance(node.left);
		findNOBlance(node.right);
		int m=balance(node);
		if((m>1||m<-1)) {
			madeBalance(node);
			return;
		}
	}
	//插入数据
	public void insert(Integer t) {
		//第一次插入数据时如果treeroot没有定义首先定义
		if(treeRoot==null) {
			treeRoot=new TreeNode<Integer>(t);
			return;
		}
		//in插入借点
		//tree指针
		TreeNode<Integer> in = new TreeNode<>(t);
		TreeNode<Integer> tree = treeRoot;
		insert(tree, in);
		//插入数据后就判断是否平衡
		TreeNode<Integer> node=treeRoot;
		findNOBlance(node);
	}
	private void insert(TreeNode<Integer> tree, TreeNode<Integer> in) {
		//如果插入数据与树中数据相同则直接返回,二叉查找树中不能有重复的数据
		if (in.t == tree.t) {
			return;
		}
		//如果大于此节点数,则在右子树中查找
		if (tree.t > in.t) {
			if (tree.left == null) {
				tree.left = in;
			} else {
				insert(tree.left, in);
			}
			//否则在左子树中查找
		} else {
			if (tree.right == null) {
				tree.right = in;
			} else {
				insert(tree.right, in);
			}
		}
	}

		// 判断此树是否为空
		public boolean isEmpty() {
			return treeRoot == null;
		}

		// 将此树置为空
		public void makeEmpty() {
			treeRoot = null;
		}
		// 遍历输入
		public String toString() {

			Tree<Integer> t = new Tree<Integer>();
			t.layer(treeRoot);
			
			return null;
		}
}

测试代码:

package Tree;

public class Test {
	public static void main(String[] args) {
	AVLTree tree=new AVLTree();
	tree.insert(10);
	tree.insert(5);
	tree.insert(15);
	tree.insert(3);
	tree.insert(6);
	tree.insert(7);
	tree.toString();

	}
}

考科二又挂了希望下一次能过

猜你喜欢

转载自blog.csdn.net/go_____________ahead/article/details/84648554
今日推荐