当前位置:   article > 正文

七大查找算法之树表查找---二叉树查找算法

二叉树查找算法

二叉树查找算法

       二叉查找树是先对待查找的数据进行生成树,确保树的左分支的值小于右分支的值,然后在就行和每个节点的父节点比较大小,查找最适合的范围。 这个算法的查找效率很高,但是如果使用这种查找方法要首先创建树。

原理: 

       二叉查找树(BinarySearch Tree,也叫二叉搜索树 BST,或称二叉排序树Binary Sort Tree)或者是一棵空树,或者是具有下列性质的二叉树:

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

  2)若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

  3)任意节点的左、右子树也分别为二叉查找树;

  4) 没有键值相等的节点(no duplicate nodes)。

BST 中实现查找元素:

根据BST的特性,对于每个节点:

  1. 如果目标值等于节点的值,则返回节点
  2. 如果目标值小于节点的值,则继续在左子树中搜索
  3. 如果目标值大于节点的值,则继续在右子树中搜索

在上面的二叉搜索树中搜索目标值为 4 的节点

  1. def search(self, node, parent, data):
  2. if node is None:
  3. return False, node, parent
  4. if node.data == data:
  5. return True, node, parent
  6. if node.data > data:
  7. return self.search(node.leftChild, node, data)
  8. else:
  9. return self.search(node.rightChild, node, data)

BST 中实现插入元素:

与搜索操作类似,对于每个节点,我们将:

  1. 根据节点值与目标节点值的关系,搜索左子树或右子树;
  2. 重复步骤 1 直到到达外部节点;
  3. 根据节点的值与目标节点的值的关系,将新节点添加为其左侧或右侧的子节点。

è¿éåå¾çæè¿°

这样,我们就可以添加一个新的节点并依旧维持二叉搜索树的性质。

  1. def insert(self, data):
  2. flag, n, p = self.search(self.root, self.root, data)
  3. if not flag:
  4. new_node = BSTNode(data)
  5. if data > p.data:
  6. p.rightChild = new_node
  7. else:
  8. p.leftChild = new_node

BST中实现删除操作:

      删除要比我们前面提到过的两种操作复杂许多。有许多不同的删除节点的方法,根据其子节点的个数,我们需考虑以下三种情况:

      1. 如果目标节点没有子节点,我们可以直接移除该目标节点。
      2. 如果目标节只有一个子节点,我们可以用其子节点作为替换。
      3. 如果目标节点有两个子节点,我们需要用其中序后继节点或者前驱节点来替换,再删除该目标节点。

例 1:目标节点没有子节点

例 2:目标节只有一个子节点

例 3:目标节点有两个子节点

  1. def delete(self, root, data):
  2. flag, n, p = self.search(root, root, data)
  3. if flag is False:
  4. return "关键字不存在,删除失败"
  5. else:
  6. if n.leftChild is None:
  7. if n == p.leftChild:
  8. p.leftChild = n.rightChild
  9. else:
  10. p.rightChild = n.rightChild
  11. del p
  12. elif n.rightChild is None:
  13. if n == p.leftChild:
  14. p.leftChild = n.leftChild
  15. else:
  16. p.rightChild = n.leftChild
  17. del p
  18. else: # 左右子树均不为空
  19. pre = n.rightChild
  20. if pre.leftChild is None:
  21. n.data = pre.data
  22. n.rightChild = pre.rightChild
  23. del pre
  24. else:
  25. next = pre.leftChild
  26. while next.leftChild is not None:
  27. pre = next
  28. next = next.leftChild
  29. n.data = next.data
  30. pre.leftChild = next.rightChild
  31. del p

代码分析:

  1. class BSTNode:
  2. def __init__(self, data):
  3. self.data = data
  4. self.leftChild = None
  5. self.rightChild = None
  6. class BST:
  7. def __init__(self, node_list):
  8. self.root = BSTNode(node_list[0])
  9. for data in node_list[1:]:
  10. self.insert(data)
  11. def search(self, node, parent, data):
  12. if node is None:
  13. return False, node, parent
  14. if node.data == data:
  15. return True, node, parent
  16. if node.data > data:
  17. return self.search(node.leftChild, node, data)
  18. else:
  19. return self.search(node.rightChild, node, data)
  20. def insert(self, data):
  21. flag, n, p = self.search(self.root, self.root, data)
  22. if not flag:
  23. new_node = BSTNode(data)
  24. if data > p.data:
  25. p.rightChild = new_node
  26. else:
  27. p.leftChild = new_node
  28. def delete(self, root, data):
  29. flag, n, p = self.search(root, root, data)
  30. if flag is False:
  31. return "关键字不存在,删除失败"
  32. else:
  33. if n.leftChild is None:
  34. if n == p.leftChild:
  35. p.leftChild = n.rightChild
  36. else:
  37. p.rightChild = n.rightChild
  38. del p
  39. elif n.rightChild is None:
  40. if n == p.leftChild:
  41. p.leftChild = n.leftChild
  42. else:
  43. p.rightChild = n.leftChild
  44. del p
  45. else: # 左右子树均不为空
  46. pre = n.rightChild
  47. if pre.leftChild is None:
  48. n.data = pre.data
  49. n.rightChild = pre.rightChild
  50. del pre
  51. else:
  52. next = pre.leftChild
  53. while next.leftChild is not None:
  54. pre = next
  55. next = next.leftChild
  56. n.data = next.data
  57. pre.leftChild = next.rightChild
  58. del p
  59. # 先序遍历
  60. def preOrderTraverse(self, node):
  61. if node is not None:
  62. print(node.data)
  63. self.preOrderTraverse(node.leftChild)
  64. self.preOrderTraverse(node.rightChild)
  65. # 中序遍历
  66. def inOrderTraverse(self, node):
  67. if node is not None:
  68. self.inOrderTraverse(node.leftChild)
  69. print(node.data)
  70. self.inOrderTraverse(node.rightChild)
  71. # 后序遍历
  72. def postOrderTraverse(self, node):
  73. if node is not None:
  74. self.postOrderTraverse(node.leftChild)
  75. self.postOrderTraverse(node.rightChild)
  76. print(node.data)

性能总结:

  • 二叉排序树以链式进行存储,保持了链接结构在插入和删除操作上的优点。
  • 在极端情况下,查询次数为1,但最大操作次数不会超过树的深度。也就是说,二叉排序树的查找性能取决于二叉排序树的形状,也就引申出了后面的平衡二叉树。
  • 给定一个元素集合,可以构造不同的二叉排序树,当它同时是一个完全二叉树的时候,查找的时间复杂度为O(log(n)),近似于二分查找。
  • 当出现最极端的斜树时,其时间复杂度为O(n),等同于顺序查找,效果最差。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/634949
推荐阅读
相关标签
  

闽ICP备14008679号