二进制搜索树(BST)–搜索插入和删除

时间:2020-02-23 14:41:15  来源:igfitidea点击:

在本教程中,我们将讨论二进制搜索树数据结构。
我们将实现在Binary Search Tree中搜索,插入和删除值的功能。
我们将以递归方式和迭代方式实施这些操作。

二进制搜索树

二叉搜索树具有以下属性:

  • 所有节点的左子节点应始终小于父节点。

  • 正确的子节点始终大于父节点。

在以下各节中,我们将介绍如何以递归和迭代方式在BST中搜索,插入和删除。

让我们首先创建我们的二叉树数据结构:

public class BinaryTree {

	public TreeNode root;

	public static class TreeNode {

		public TreeNode left;
		public TreeNode right;
		public Object data;

		public TreeNode(Object data) {
			this.data = data;
			left = right = null;
		}
	}
}

注意,上述实现不是二叉搜索树,因为在树中插入元素没有限制。

BST递归搜索

以下Java程序包含用于在BST中递归搜索值的函数。

public class SearchInsertRemoveFromTree {

  public static void main(String[] args) {

	/**
	 *   Our Example Binary Search Tree
	 *       10
	 *     5    20
	 *   4  8  15 25
	 */

      BinaryTree tree = new BinaryTree();
      tree.root = new TreeNode(10);
      tree.root.left = new TreeNode(5);
      tree.root.right = new TreeNode(20);
      tree.root.left.left = new TreeNode(4);
      tree.root.left.right = new TreeNode(8);
      tree.root.right.left = new TreeNode(15);
      tree.root.right.right = new TreeNode(25);

      System.out.println("Search Value 2 is in tree? " + searchRecursively(tree.root, 2));
      System.out.println("Search Value 10 in tree? " + searchRecursively(tree.root, 10));
  }

  public static boolean searchRecursively(TreeNode root, int value) {

      if (root == null)
          return false;

      if ((int) root.data == value)
          return true;

      if (value < (int) root.data)
          return searchRecursively(root.left, value);

      else if (value > (int) root.data)
          return searchRecursively(root.right, value);

      return false;
  }
}

BST反复搜索

要迭代搜索,请改用以下方法:

public static boolean searchIteratively(TreeNode root, int value) {

      while (root != null) {
          if ((int) root.data == value)
              return true;

          if (value < (int) root.data)
              root = root.left;

          else
              root = root.right;
      }

      return false;
  }

让我们看一下如何在二进制搜索树中插入新节点。

BST递归插入

public static TreeNode insertionRecursive(TreeNode root, int value) {

      if (root == null)
          return new TreeNode(value);

      if (value < (int) root.data) {
          root.left = insertionRecursive(root.left, value);
      } else if (value > (int) root.data) {
          root.right = insertionRecursive(root.right, value);
      }

      return root;

  }

public static void printInorderTraversal(TreeNode root) {
      if (root != null) {
          printInorderTraversal(root.left);
          System.out.print(root.data + " ");
          printInorderTraversal(root.right);
      }
  }

在main方法中调用上述方法:

tree.root = insertionRecursive(tree.root, 24);
tree.root = insertionRecursive(tree.root, 2);
printInorderTraversal(tree.root);

该树以有序遍历的形式打印。

BST插入迭代

要将节点迭代地插入BST树中,我们将需要使用两个指针遍历该树。

public static TreeNode insertionIterative(TreeNode root, int value) {

      TreeNode current, parent;

      TreeNode tempNode = new TreeNode(value);

      if (root == null) {
          root = tempNode;
          return root;
      } else {
          current = root;
      }

      while (true) {
          parent = current;

          if (value < (int) current.data) {
              current = current.left;
              if (current == null) {
                  parent.left = tempNode;
                  return root;
              }

          } else if (value > (int) current.data) {
              current = current.right;

              if (current == null) {
                  parent.right = tempNode;
                  return root;
              }
          }

      }
  }

BST递归删除元素

从BST中删除元素比搜索和插入要复杂一些,因为我们必须确保BST属性得到保留。

要删除节点,我们需要先搜索它。
然后,我们需要确定该节点是否有子节点。

  • 如果没有孩子-删除即可。

  • 如果是单个孩子-将那个孩子复制到该节点。

  • 如果有两个孩子-确定右子树中的下一个最高元素(顺序后继)。
    用顺序后继节点替换要删除的节点。
    删除顺序的后继副本。

可通过在节点的右子节点中找到最小值来获得有序后继者。

以下Java程序从BST中删除元素:

public static TreeNode deleteRecursively(TreeNode root, int value) {

      if (root == null)
          return root;

      if (value < (int) root.data) {
          root.left = deleteRecursively(root.left, value);
      } else if (value > (int) root.data) {
          root.right = deleteRecursively(root.right, value);
      } else {

          if (root.left == null) {
              return root.right;
          } else if (root.right == null)
              return root.left;

          root.data = inOrderSuccessor(root.right);
          root.right = deleteRecursively(root.right, (int) root.data);
      }

      return root;

  }

  public static int inOrderSuccessor(TreeNode root) {
      int minimum = (int) root.data;
      while (root.left != null) {
          minimum = (int) root.left.data;
          root = root.left;
      }
      return minimum;
  }

main方法中调用上述delete方法:

tree.root = deleteRecursively(tree.root, 4);
tree.root = deleteRecursively(tree.root, 20);
printInorderTraversal(tree.root);

输出为:2 5 8 10 15 24 25

让我们反复进行相同的操作。

BST迭代删除元素

public static TreeNode deleteNodeIteratively(TreeNode root, int value) {
      TreeNode parent = null, current = root;
      boolean hasLeft = false;

      if (root == null)
          return root;

      while (current != null) {
          if ((int) current.data == value) {
              break;
          }

          parent = current;
          if (value < (int) current.data) {
              hasLeft = true;
              current = current.left;
          } else {
              hasLeft = false;
              current = current.right;
          }
      }

      if (parent == null) {
          return deleteNodeIteratively(current);
      }

      if (hasLeft) {
          parent.left = deleteNodeIteratively(current);
      } else {
          parent.right = deleteNodeIteratively(current);
      }

      return root;
  }

  private static TreeNode deleteNodeIteratively(TreeNode node) {

      if (node != null) {
          if (node.left == null && node.right == null) {
              return null;
          }

          if (node.left != null && node.right != null) {
              TreeNode inOrderSuccessor = deleteInOrderSuccessorDuplicate(node);
              node.data = inOrderSuccessor.data;
          } else if (node.left != null) {
              node = node.left;
          } else {
              node = node.right;
          }
      }

      return node;
  }

  private static TreeNode deleteInOrderSuccessorDuplicate(TreeNode node) {
      TreeNode parent = node;
      node = node.right;
      boolean rightChild = node.left == null;

      while (node.left != null) {
          parent = node;
          node = node.left;
      }

      if (rightChild) {
          parent.right = node.right;
      } else {
          parent.left = node.right;
      }

      node.right = null;
      return node;
  }

BST操作的时间复杂度为O(h)。
h是树的高度。