【数据结构 Java版】了解二叉搜索树

x33g5p2x  于2021-11-17 转载在 Java  
字(2.3k)|赞(0)|评价(0)|浏览(359)

1. 概念

二叉搜索树(又称二叉排序树),它可以是一棵空树,也可以是一棵具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有的节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有的节点的值都大于根节点的值
  • 它的左子树和右子树也都为二叉搜索树

通过性质,我们也容易得出一个结论:

可以通过中序遍历来判断这棵二叉树是否为搜索二叉树,如果结果有序,则是搜索二叉树

示例图:

2. 操作

在进行下面搜索二叉树的几个操作实现之前,我们先写一个基本的搜索二叉树类,在这个类中来实现我们的操作

实现代码:

  1. public class BinarySearchTree {
  2. // 将节点直接定义在二叉树类的内部
  3. static class TreeNode{
  4. public int val;
  5. public TreeNode left;
  6. public TreeNode right;
  7. public TreeNode(int val){
  8. this.val=val;
  9. }
  10. }
  11. // 查找
  12. // 插入
  13. // 删除
  14. }

2.1 查找

思想:

  • 若节点不为空:

  • 如果根节点 key == 查找值 key,返回 true

  • 如果根节点 key > 查找值 key,在其左子树继续查找

  • 如果根节点 key < 查找值 key,在其右子树继续查找

  • 否则返回 false

实现代码:

  1. // 查找
  2. public TreeNode search(TreeNode root,int key){
  3. while(root!=null){
  4. if(root.val==key){
  5. return root;
  6. }else if(root.val>key){
  7. root=root.left;
  8. }else{
  9. root=root.right;
  10. }
  11. }
  12. return null;
  13. }

2.2 插入

思想:

  • 若跟节点为空,则在根节点插入
  • 若不为空,则找到数值应该插入的叶子节点,来进行判断插入

实现代码:

  1. public void insertTree(int key){
  2. if (root==null){
  3. root=new TreeNode(key);
  4. }
  5. TreeNode cur=root;
  6. TreeNode parent=null;
  7. while(cur!=null){
  8. if(cur.val<key){
  9. parent=cur;
  10. cur=cur.right;
  11. }else{
  12. parent=cur;
  13. cur=cur.left;
  14. }
  15. }
  16. TreeNode node=new TreeNode(key);
  17. if(parent.val<key){
  18. parent.right=node;
  19. }else{
  20. parent.left=node;
  21. }
  22. }

2.3 删除

思想:

  • 先通过查找找到要删除的节点,再设置一个节点记为其父节点

  • 找到删除的节点之后

  • 若待删除的结点的左节点为空

  • 如果待删除结点为根节点,让根节点为右子树即可

  • 如果待删除结点不是根节点,且为父节点的左子树,只要让父节点的左子树为待删除结点的右子树即可

  • 如果待删除结点不是根节点,且为父节点的右子树,只要让父节点的右子树为待删除结点的右子树即可

  • 若待删除的结点的右结点为空

  • 如果待删除结点为根节点,让根节点为左子树即可

  • 如果待删除结点不是根节点,且为父节点的左子树,只要让父节点的左子树为待删除结点的左子树即可

  • 如果待删除结点不是根节点,且为父节点的右子树,只要让父节点的右子树为待删除结点的左子树即可

  • 若待删除的结点的左右节点都不为空,那么使用替换法,找到左子树的最大值或者右子树的最小值,来将待删除结点给替换,这样,我们只要再将将其替换的结点删除即可

实现代码:

  1. public void remove(int key){
  2. TreeNode cur=root;
  3. TreeNode parent=null;
  4. while(cur!=null){
  5. if(cur.val<key){
  6. parent=cur;
  7. cur=cur.right;
  8. }else if(cur.val==key){
  9. removeNode(cur,parent);
  10. }else{
  11. parent=cur;
  12. cur=cur.left;
  13. }
  14. }
  15. }
  16. public void removeNode(TreeNode cur,TreeNode parent){
  17. if(cur.left==null){
  18. if(cur==root){
  19. root=cur.right;
  20. } else if(cur==parent.left){
  21. parent.left=cur.right;
  22. } else if(cur==parent.right){
  23. parent.right=cur.right;
  24. }
  25. }else if(cur.right==null){
  26. if(cur==root){
  27. root=cur.left;
  28. } else if(cur==parent.left){
  29. parent.left=cur.left;
  30. } else if(cur==parent.right){
  31. parent.right=cur.left;
  32. }
  33. }else{
  34. TreeNode tp=cur;
  35. TreeNode target=cur.right;
  36. while (target.left!=null) {
  37. tp = target;
  38. target = target.left;
  39. }
  40. cur.val=target.val;
  41. if(tp.left==target){
  42. tp.left=target.right;
  43. }else{
  44. tp.right=target.right;
  45. }
  46. }
  47. }

3. 性能分析及优化

通过分析,我们发现删除和插入操作之前都必须先查找,故查找效率代表了二叉搜索树的这几个操作的性能

以下来分析下两种特殊的搜索二叉树的查找的时间复杂度

  • 完全二叉树(时间复杂度为:O(logN)

  • 单支二叉树(时间复杂度为:O(N)

如果是一棵单支树的话,时间复杂度其实就达到了 O(N),为了优化的更快则出现了:AVL 树红黑树

相关文章

最新文章

更多