您的位置:首页 > 编程语言 > Java开发

减治法在查找算法中的应用(JAVA)--二叉查找树的查找、插入、删除

2018-02-03 17:29 471 查看
减治法在查找算法中的应用

二叉查找树的查找与插入:

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根节点的值;

(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;

(3)左、右子树也分别为二叉排序树。

对于二叉查找树这里我们介绍查找、插入和删除操作:

这些操作会将问题的规模变成一个更小的二叉树,也运用到了减治法的思想。

查找思路:如果树为空,直接返回,查找失败。反之,将查找值key与根root的值比较,如果相等,则root即为所找;若key < root.v,则继续在左子树查找;若key > root.v,则继续在右子树查找。

public static Node find(int key) {
if (root == null) {
System.out.println("The tree is empty!");
return null;
}
Node cur = root;
while (cur.v != key) {
if (key < cur.v) {
cur = cur.l;
}
else {
cur = cur.r;
}
if (cur == null) {
return null;
}
}
return cur;
插入思路:基本思想和查找操作类似,如果为空树,直接返回,插入节点即为根节点;否则,比较根节点的值与插入节点的值。注意用parent记录遍历到最后的cur值。

public static Node find(int key) {
if (root == null) {
System.out.println("The tree is empty!");
return null;
}
Node cur = root;
while (cur.v != key) {
if (key < cur.v) {
cur = cur.l;
}else {
cur = cur.r;
}
if (cur == null) {
return null;
}
}
return cur;
}删除思路:删除操作是二叉树操作中最复杂的问题。对于二叉树的删除有一下三种情况:
(1)删除叶子结点。可直接删除,不会影响其他

(2)删除结点有且只有一侧孩子结点。孩子结点覆盖待删除结点,删除孩子结点

(3)删除结点下既有左孩子,又有右孩子。在待删除结点的右孩子下,找到v值最小的,用这个结点覆盖要删除的结点。(这里是因为中序遍历结点的后继结点一定是在右子树中v值最小的结点)

public static boolean delete(int key) {
Node cur = root;
Node parent = root;
boolean hasLeft = true;
while (cur != null && cur.v != key) {
parent = cur;
if (key < cur.v) {
cur = cur.l;
hasLeft = true;
} else {
cur = cur.r;
hasLeft = false;
}
}
if (cur == null) {
return false;
}
if (cur.l == null && cur.r == null) {
/**
* 要删除的节点为叶子节点,直接删除
* */
if (cur == root) {
root = null;
}
if (hasLeft) {
parent.l = null;
} else {
parent.r = null;
}
} else if (cur.r == null) {
/**
* 要删除的节点只有左孩子
* */
if (cur == root) {
root = cur.l;
}
if (hasLeft) {
parent.l = cur.l;
} else {
parent.r = cur.l;
}
} else if (cur.l == null) {
/**
* 要删除的节点只有右孩子
* */
if (cur == root) {
root = cur.r;
}
if (hasLeft) {
parent.l = cur.r;
}else {
parent.r = cur.r;
}
} else {
/**
* 要删除的节点既有左孩子又有右孩子
* 思路:用待删除节点右子树中的v值最小的结点来替代要删除的节点,然后删除右子树中结点
* 右子树中v值最小的节点一定没有左子树,所以删除的这个结点一定是属于叶子节点或只有右子树的节点
* */
Node directPostNode = getPost(cur);
cur.v = directPostNode.v;
}
return true;
}
private static N
4000
ode getPost(Node delNode) {
Node parent = delNode;
Node dir = delNode;
Node cur = delNode.r;
while (cur != null) {
parent = dir;
dir = cur;
cur = cur.l;
}
if (dir != delNode.r) {//从树中删除此直接后继节点
parent.l = dir.r;
dir.r = null;
}
return dir;
}完整代码如下:
class Node {
int v;
Node l;
Node r;

public Node(int v) {
this.v = v;
}
}
public class Main {
public static Node root;

public static Node find(int key) {
if (root == null) {
System.out.println("The tree is empty!");
return null;
}
Node cur = root;
while (cur.v != key) {
if (key < cur.v) {
cur = cur.l;
}
else {
cur = cur.r;
}
if (cur == null) {
return null;
}
}
return cur;
}

public static void insert(Node node) {
if (root == null) {
root = node;
return;
}
Node cur = root;
Node parent = root;
boolean hasLeft = true;
while (cur != null) {
parent = cur;
if (node.v > cur.v) {
cur = cur.r;
hasLeft = true;
} else {
cur = cur.l;
hasLeft = false;
}
}
if (hasLeft) {
parent.l = node;
} else {
parent.r = node;
}
}
public static boolean delete(int key) {
Node cur = root;
Node parent = root;
boolean hasLeft = true;
while (cur != null && cur.v != key) {
parent = cur;
if (key < cur.v) {
cur = cur.l;
hasLeft = true;
} else {
cur = cur.r;
hasLeft = false;
}
}
if (cur == null) {
return false;
}
if (cur.l == null && cur.r == null) {
/**
* 要删除的节点为叶子节点,直接删除
* */
if (cur == root) {
root = null;
}
if (hasLeft) {
parent.l = null;
} else {
parent.r = null;
}
} else if (cur.r == null) {
/**
* 要删除的节点只有左孩子
* */
if (cur == root) {
root = cur.l;
}
if (hasLeft) {
parent.l = cur.l;
} else {
parent.r = cur.l;
}
} else if (cur.l == null) {
/**
* 要删除的节点只有右孩子
* */
if (cur == root) {
root = cur.r;
}
if (hasLeft) {
parent.l = cur.r;
}else {
parent.r = cur.r;
}
} else {
/**
* 要删除的节点既有左孩子又有右孩子
* 思路:用待删除节点右子树中的v值最小的结点来替代要删除的节点,然后删除右子树中结点
* 右子树中v值最小的节点一定没有左子树,所以删除的这个结点一定是属于叶子节点或只有右子树的节点
* */
Node directPostNode = getPost(cur);
cur.v = directPostNode.v;
}
return true;
}
private static Node getPost(Node delNode) {

Node parent = delNode;
Node dir = delNode;
Node cur = delNode.r;
while (cur != null) {
parent = dir;
dir = cur;
cur = cur.l;
}
if (dir != delNode.r) {//从树中删除此直接后继节点
parent.l = dir.r;
dir.r = null;
}
return dir;

}

public static void preorder(Node node) {
System.out.print(node.v + " ");
if (node.l != null)
preorder(node.l);
if (node.r != null)
preorder(node.r);
}

public static void main(String[] args) {
/**
* 插入
* */
insert(new Node(20));
insert(new Node(10));
insert(new Node(30));
/**
* 查找
* */
System.out.println(find(20));
/**
* 删除
* */
delete(20);
/**
* 前序遍历
* */
preorder(root);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息