二叉排序树(BST)
二叉排序树BST(Binary Sort Tree):对于二叉树的任何一个非叶子结点,要求左子节点的值比当前结点的值小,右子节点的值比当前结点的值大。 特别说明:如果右相同的值,可以将该结点放在左子节点或右子节点
创建和遍历
’首先实现二叉排序树的创建和遍历; 二叉排序树的创建和之前学过的二叉树的创建差不多,只是在插入结点的时候多了一个判断条件,需要根据插入结点和原先二叉排序树的结点进行比较找到插入的位置 关于遍历:这里我们代码实现的是中序遍历,对于二叉排序树来说,中序遍历恰好输出的是该组数据从小到大的排列序列 代码实现:
class createBinaryTree {
private binaryNode root;
public void add(binaryNode node) {
if(root == null) {
root = node;
return ;
}
root.add(node);
}
public void infixOrder() {
if(root == null) {
System.out.println("这棵二叉排序树是空的");
return;
}
root.infixOrder();
}
}
class binaryNode{
int value;
binaryNode left;
binaryNode right;
public binaryNode(int value) {
this.value = value;
}
public String toString() {
return "[value=" + value + "]";
}
public void infixOrder() {
if(this == null) return ;
if(this.left != null)
this.left.infixOrder();
System.out.println(this);
if(this.right != null)
this.right.infixOrder();
}
public void add(binaryNode node) {
if(this == null) return ;
if(node.value < this.value) {
if(this.left != null)
this.left.add(node);
else
this.left = node;
} else {
if(this.right != null)
this.right.add(node);
else
this.right = node;
}
}
}
删除二叉排序树的结点
删除二叉排序树结点的三种情况以及思路分析: (1)待删除的结点是叶子结点:找到目标结点(待删除结点)以及目标结点的父节点,直接将其父节点的left或者right至为空(如果目标结点在left则置 left为空,如果目标结点在right则置right为空) (2)待删除结点是只有一棵子树的结点:找到目标结点以及目标结点的父结点,将原来父亲结点指向目标结点的指针该成指向目标结点的子树; (3)待删除结点是有两颗子树的结点【该情况有两种方法】: 不推荐方法2,方法2只使用于二叉树层数比较少的情况 方法<1>找到目标结点以及目标结点的父节点,在去找目标结点右子树里值最小的结点temp,并将此结点记录下来,然后将temp删除,在将目标结点的值改为temp即可; 方法<2>找到目标结点以及目标结点的父节点,在去找目标结点左子树里值最大的结点temp,并将此结点记录下来,然后将temp删除,在将目标结点的值改为temp即可;
代码实现:
class createBinaryTree {
private binaryNode root;
public binaryNode targetSearch(int value) {
if(root == null) return null;
return root.targetSearch(value);
}
public binaryNode parentSearch(int value) {
if(root == null || root.value == value) return null;
return root.parentSearch(value);
}
public void delete(int value) {
binaryNode target = targetSearch(value);
binaryNode parent = parentSearch(value);
if(target == null) return ;
if(target == root && target.right == null &&target.left == null) {
root = null;
return ;
}
if(target.left == null && target.right == null) {
if(parent.left == target)
parent.left = null;
if(parent.right == target)
parent.right = null;
} else if(target.left != null && target.right != null) {
int min = searchMax(target);
target.value = min;
} else {
if(target.left != null) {
if(parent != null) {
if (parent.left == target)
parent.left = target.left;
else
parent.right = target.left;
} else {
root = target.left;
}
} else {
if(parent != null) {
if (parent.left == target)
parent.left = target.right;
else
parent.right = target.right;
} else {
root = target.right;
}
}
}
public int searchMax(binaryNode node) {
binaryNode temp = node.right;
while(true) {
if(temp.left == null) break;
temp = temp.left;
}
int Min = temp.value;
delete(Min);
return Min;
}
}
class binaryNode{
int value;
binaryNode left;
binaryNode right;
public binaryNode(int value) {
this.value = value;
}
public String toString() {
return "[value=" + value + "]";
}
public binaryNode parentSearch(int value) {
if((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value))
return this;
else {
if(this.value > value && this.left != null)
return this.left.parentSearch(value);
else if(this.value <= value && this.right != null)
return this.right.parentSearch(value);
else
return null;
}
}
public binaryNode targetSearch(int value) {
if(this.value == value) return this;
else if(value < this.value) {
if(this.left != null)
return this.left.targetSearch(value);
else
return null;
}else {
if(this.right != null)
return this.right.targetSearch(value);
else
return null;
}
}
}
平衡二叉树(AVL树)
平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树,可以保证查询效率较高。 具有的特点:他是一棵空树或他的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,平衡二叉树的常用实现方法有红黑树,AVL,替罪羊树,treap,伸展树
为什么会出现平衡二叉树呢,就像我们上面讲的二叉排序树,如果我们给他的数列是{1,3,5,7,9,10,12},那么利用二叉排序树创建出来的树就是这样的: 这样的树查询速率可能不会得到提高,反而还会比原来的数列查找更慢,因此,我们就出现了平衡二叉树来解决这样的问题
左旋转
将二叉排序树装换为平衡二叉树的方法: 如果左子树的高度底,右子树的高度高,并且两个左右两边的高度差大于1,那么就用左旋转 步骤: (1)创建一个新的结点,新结点的值等于当前根节点(root)的值 (2)把新节点的左子树设置为当前结点(root)的左子树 (3)把新结点的右子树设置为当前结点(root)的右子树的左子树 (4)把当前结点(root)的值换为右子节点的值 (5)把当前结点(root)的右子树设置为右子树的右子树 (6)把当前结点(root)的左子树设置为新节点
因为二叉平衡树是在二叉排序树上实现一些功能,因此可以在原来的二叉排序树上进行添加功能即可 代码实现:
class binaryNode{
int value;
binaryNode left;
binaryNode right;
public binaryNode(int value) {
this.value = value;
}
public String toString() {
return "[value=" + value + "]";
}
public int leftHeight() {
if(left == null) return 0;
return left.height();
}
public int rightHeight() {
if(right == null) return 0;
return right.height();
}
public int height() {
return Math.max(left == null ? 0 : left.height(),right == null ? 0 : right.height())+1;
}
private void leftRotate() {
binaryNode node = new binaryNode(value);
node.left = left;
node.right = right.left;
value = right.value;
right = right.right;
left = node;
}
}
右旋转
如果右子树的高度底,左子树的高度高,并且两个左右两边的高度差大于1,那么就用右旋转 步骤: (1)创建一个新的结点,新结点的值等于当前根节点(root)的值 (2)把新节点的右子树设置为当前结点(root)的右子树 (3)把新结点的左子树设置为当前结点(root)的左子树的右子树 (4)把当前结点(root)的值换为左子节点的值 (5)把当前结点(root)的左子树设置为左子树的左子树 (6)把当前结点(root)的右子树设置为新节点
代码实现:
class binaryNode{
int value;
binaryNode left;
binaryNode right;
public binaryNode(int value) {
this.value = value;
}
public String toString() {
return "[value=" + value + "]";
}
public int leftHeight() {
if(left == null) return 0;
return left.height();
}
public int rightHeight() {
if(right == null) return 0;
return right.height();
}
public int height() {
return Math.max(left == null ? 0 : left.height(),right == null ? 0 : right.height())+1;
}
private void leftRotate() {
binaryNode node = new binaryNode(value);
node.left = left;
node.right = right.left;
value = right.value;
right = right.right;
left = node;
}
private void rightRotate() {
binaryNode node = new binaryNode(value);
node.right = right;
node.left = left.right;
value = left.value;
left = left.left;
right = node;
}
public void add(binaryNode node) {
if(this == null) return ;
if(node.value < this.value) {
if(this.left != null)
this.left.add(node);
else
this.left = node;
} else {
if(this.right != null)
this.right.add(node);
else
this.right = node;
}
if(rightHeight() - leftHeight() > 1) {
if(right != null && right.leftHeight() > right.rightHeight())
rightRotate();
leftRotate();
return ;
}
if(leftHeight() - rightHeight() > 1) {
if(left != null && left.rightHeight() > leftHeight())
leftRotate();
rightRotate();
}
}
}
右旋转的代码里面是完成了整个完整的左旋转和右旋转的代码,并且在左旋转和右旋转方法写完后,一定要在add(添加结点)函数里面写进去,就是在没插入一个结点的时候我们就要考虑是否需要进行平衡二叉树
|