节点类:
package Demo31;
public class TreeNode {
private TreeNode left;
private Integer data;
private TreeNode right;
@Override
public String toString() {
return "TreeNode{" +
"left=" + left +
", data=" + data +
", right=" + right +
'}';
}
public TreeNode(Integer data) {
this.data = data;
}
public TreeNode getLeft() {
return left;
}
public void setLeft(TreeNode left) {
this.left = left;
}
public Integer getData() {
return data;
}
public void setData(Integer data) {
this.data = data;
}
public TreeNode getRight() {
return right;
}
public void setRight(TreeNode right) {
this.right = right;
}
}
构建二叉搜索树:
package Demo31;
public class BinTree {
TreeNode root;
public TreeNode getRoot() {
// 获取根节点
return root;
}
public void Insert(TreeNode temp, int val) {
//插入节点,二叉搜索树的左子树都小于根节点,右子树都大于等于根节点
//本代码没有考虑出现重复节点的情况
TreeNode node = new TreeNode(val);
if (root == null) {
root = node;
return;
}
//如果发现,要插入的节点小于当前节点
if (node.getData() < temp.getData()) {
//如果当前节点的左子树不存在,直接设置左子树为要插入的节点
if (temp.getLeft() == null) {
temp.setLeft(node);
} else {// 否则,让当前节点往左子树走
Insert(temp.getLeft(), val);
}
} else {//反之,一样
if (temp.getRight() == null) {
temp.setRight(node);
} else {
Insert(temp.getRight(), val);
}
}
}
public TreeNode search(int val) {
// 在二叉树中搜索值为 val 的节点并返回
if (root == null) {
return null;
}
TreeNode t = root;
while (true) {
if (val < t.getData()) {//如果 val 小于当前节点 t 的值,让 t 往左走
if (t.getLeft() == null) {
return null;
} else {
t = t.getLeft();
}
} else if (val > t.getData()) {
if (t.getRight() == null) {
return null;
} else {
t = t.getRight();
}
} else {
return t;
}
}
}
public TreeNode searchParentNode(TreeNode node, int val) {
// 搜素值为 val 的节点的父亲节点
//此方法在删除节点中用
if (root == null) {
return null;
}
// 如果发现当前节点的左子树或者右子树的值等于 val,说明当前节点就是父亲节点
if ((node.getLeft() != null && node.getLeft().getData() == val) || (node.getRight() != null && node.getRight().getData() == val)) {
return node;
}
// 如果当前节点的值大于要找的 val,让当前节点往左走
if (val < node.getData() && node.getLeft != null) {
return searchParentNode(node.getLeft(), val);
} else if (val > node.getData() && node.getRight != null){
return searchParentNode(node.getRight(), val);
} else return null;//不满足上述情况,就说明该节点没有父亲节点,说明该节点是个根节点
}
public int deleteRightTreeNode(TreeNode node) {
// 找到右子树的最小值,在删除有两个子节点的节点时使用,画图可分析
while (node.getLeft() != null) {//由于传过来的就是右子树
//所以只需要不断往左找就行,找到最小的
node = node.getLeft();
}
delete(node.getData());// 别忘了将该节点删除
return node.getData();
}
public void delete(int val) {
// 删除节点,考虑的情况比较多,不过不难,仔细就 okk
if (root == null) return;// 根节点为空直接返回
TreeNode node = search(val);//找到要删除的节点
TreeNode parNode = searchParentNode(getRoot(), val);//找到要删除的节点的父亲节点(有可能是空,下面会判断)
if (node == null) return;//没找到要删除的节点,直接返回
if (node.getLeft() == null && node.getRight() == null) {
// 说明此节点是一个叶子结点,我们只需要找到该节点是父节点的左子树还是右子树
//如果该节点也是根节点,直接让根节点等于 null
if (parNode == null) {
root = null;
return;
}
if (parNode.getLeft() != null && parNode.getLeft().getData() == val) {//是左子树
parNode.setLeft(null);
} else {
parNode.setRight(null);
}
} else if (node.getLeft() != null && node.getRight() != null) {
//要删除的节点有左右子树,只需要要让该节点的值等于右子树的最小值,并且删除右子树的最小值
// 定义最小值,找到
int minRightTreeNode = deleteRightTreeNode(node.getRight());
// 让该节点的值等于最小值
node.setData(minRightTreeNode);
} else { // 最复杂的情况,该节点只有一个子树,并且不知道是哪个
if (parNode != null) {// 如果该节点不是跟节点
if (node.getLeft() != null) {// 判断该节点有左子树还是右子树
if (parNode.getLeft() != null && parNode.getLeft().getData() == val) {// 判断该节点是父亲节点的左子树还是右子树
//这里一定要仔细看代码,画个图,比较绕。
parNode.setLeft(node.getLeft());
} else {
parNode.setRight(node.getLeft());
}
} else {
if (parNode.getLeft() != null && parNode.getLeft().getData() == val) {
parNode.setLeft(node.getRight());
} else {
parNode.setRight(node.getRight());
}
}
} else {// 该节点是根节点,找到该节点有左子树还是右子树,让根节点等于即可
if (node.getLeft() != null) {
root = node.getLeft();
} else {
root = node.getRight();
}
}
}
}
public void preSearch(TreeNode tree) {
//前序遍历,不多说了
if (tree != null) {
System.out.println(tree.getData());
preSearch(tree.getLeft());
preSearch(tree.getRight());
}
}
}
这里我画个图解释一下删除的节点只有一个子树的情况:
删除节点 3,3 是有左子树的,并且 3 是父亲节点的左子树,所以让父亲节点的左子树指向 3 的左子树
此时:3 是有右子树的,3 是父亲节点的左孩子,只需让父亲节点的左孩子指向 3 的右孩子