折半查找判定树是用于描述折半查找过程的二叉树结构。树的根节点为查找区间的中间元素,左子树对应前半部分子表,右子树对应后半部分子表,递归构造形成一棵逻辑上的二叉搜索树。
-
折半查找判定树
- 树中每个节点代表一次比较的关键字。
- 查找成功时,查找路径从根到该节点,比较次数等于该节点所在的层数(根为第1层)。
- 查找失败时,查找路径走到某个空指针为止,比较次数等于路径上经历的内部节点个数(即未命中路径上的非叶节点数)。
-
查找次数的上限
- 无论查找成功与否,最大比较次数不超过判定树的深度。
- 对于 $ n $ 个节点,其判定树的深度为:
⌊log2n⌋+1 \lfloor \log_2 n \rfloor + 1 ⌊log2n⌋+1
这也是最坏情况下所需的比较次数。
-
平均查找长度(ASL)
- 当 $ n = 2^h - 1 $,即判定树为满二叉树时,在等概率查找成功的条件下:
ASLbs=n+1nlog2(n+1)−1 ASL_{bs} = \frac{n+1}{n} \log_2(n+1) - 1 ASLbs=nn+1log2(n+1)−1 - 当 $ n $ 较大时,可近似为:
ASLbs≈log2(n+1)−1 ASL_{bs} \approx \log_2(n+1) - 1 ASLbs≈log2(n+1)−1
表明折半查找具有对数级的平均性能。
- 当 $ n = 2^h - 1 $,即判定树为满二叉树时,在等概率查找成功的条件下:
-
折半查找的适用场景
- 优点:时间复杂度为 $ O(\log n) $,远优于顺序查找的 $ O(n) $。
- 限制条件:
- 要求数据在顺序存储结构中(如数组);
- 关键字必须有序;
- 插入和删除操作代价高(需移动大量元素)。
- 典型应用:适用于静态或准静态数据集,例如只读数据库、配置表、频繁查询但极少更新的场景。
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid # 查找成功,返回索引
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1 # 查找失败
# 示例使用
arr = [1, 3, 5, 7, 9, 11, 13]
target = 7
result = binary_search(arr, target)
print(f"目标值 {target} 在索引 {result}" if result != -1 else "查找失败")
根据给定的有序数组构建折半查找判定树,本质是模拟折半查找过程中每次选取中间元素作为根节点,并递归地对左右子数组构造左、右子树的过程。最终形成的二叉树即为折半查找判定树。
构建步骤:
- 选中间元素为根:对于当前有序子数组
arr[left:right+1],取中间位置mid = (left + right) // 2,对应元素arr[mid]作为当前子树的根。 - 递归构建左右子树:
- 左子树由
arr[left:mid]构成; - 右子树由
arr[mid+1:right+1]构成。
- 左子树由
- 终止条件:当
left > right时,返回空节点。
Python 实现(构建判定树并输出结构):
class TreeNode:
def __init__(self, val=0):
self.val = val
self.left = None
self.right = None
def build_binary_search_decision_tree(arr, left=0, right=None):
if right is None:
right = len(arr) - 1
if left > right:
return None
mid = (left + right) // 2
root = TreeNode(arr[mid])
root.left = build_binary_search_decision_tree(arr, left, mid - 1)
root.right = build_binary_search_decision_tree(arr, mid + 1, right)
return root
# 中序遍历查看树结构(应保持有序)
def inorder_traversal(root):
if not root:
return []
return inorder_traversal(root.left) + [root.val] + inorder_traversal(root.right)
# 层序遍历打印树结构(更直观)
def print_level_order(root):
if not root:
print("Empty tree")
return
from collections import deque
queue = deque([root])
result = []
while queue:
node = queue.popleft()
if node:
result.append(node.val)
queue.append(node.left)
queue.append(node.right)
else:
result.append(None)
# 去掉末尾多余的 None
while result and result[-1] is None:
result.pop()
print("Level-order traversal:", result)
# 示例使用
arr = [1, 3, 5, 7, 9, 11, 13]
root = build_binary_search_decision_tree(arr)
print("Original array:", arr)
print("Inorder traversal:", inorder_traversal(root)) # 应与原数组一致
print_level_order(root)
输出示例:
Original array: [1, 3, 5, 7, 9, 11, 13]
Inorder traversal: [1, 3, 5, 7, 9, 11, 13]
Level-order traversal: [7, 3, 11, 1, 5, 9, 13]
这棵树的根是 7(中间),左子树以 3 为根包含 [1,5],右子树以 11 为根包含 [9,13],完全符合折半查找逻辑。
注意事项:
- 判定树的形状取决于数组长度和中间点选择方式(向下取整);
- 若 $ n = 2^h - 1 $,则判定树是一棵满二叉树;
- 否则为完全二叉树或近似完全二叉树。


1166

被折叠的 条评论
为什么被折叠?



