数据结构与算法06----查找

二分查找(折半查找)

  • 在长度为n的 有序 顺序表List中顺序查找一个目标值 => O(n)

  • 很慢,为什么慢?

  • 因为每次比较判断只排除了一个元素,完全没有利用表的有序性

  • 二分查找:在比较失效时,利用表的有序性排除 待查找元素 的一半

  • 每次排除一半 => O(lg(n))
    在这里插入图片描述

  • 算法流程:

    • 用 l 和 r 表示待查找范围的左右边界,初始时 l = 0,r = n - 1
    • 循环以下操作直至 l > r
      • 找当前搜索范围的正中间: mid = (l + r) / 2
      • 判断 target 和 List[mid] 的关系:
        • ==:找到了结果,返回mid
        • < :target只可能在mid位置左边,排除mid及其右侧所有元素 => 即更新 r = mid - 1
        • > :target只可能在mid位置右边,排除mid及其左侧所有元素 => 即更新 l = mid + 1
    • 循环能结束说明数组中不存在target,返回-1

    Key 1:二分查找只能用于 有序数组,需要通过下标直接访问元素
    Key 2:二分(折半)查找过程:①找中 ②折半
    Key 3:二分查找每次排除一半,至多log₂(n) + 1次后结束 => 复杂度为O(lg(n))

AVL

二叉搜索树 / 二叉查找树 / 二叉排序树

  • 二叉查找树中的任何一个结点都满足:
    • 左子树如果不空,则左子树所有结点都 < 本结点
    • 右子树如果不空,则右子树所有结点都 > 本结点
    • 其左右子树都是二叉查找树
  • 左小右大
  • 查找目标值:
    • 如果target < 当前结点,进入左子树
    • 如果target >当前结点,进入右子树
    • 如果进入空结点表明树中无target
      在这里插入图片描述

给定序列构造二叉查找树

  • 给定一个序列{31, 25, 57, 11, 44, 78, 2, 49, 19},将其依次插入一颗二叉查找树
  • 方法:
    • 第一个元素为根
    • 从第二个元素开始,逐个按照 小往左大往右 的原则插至叶子结点
    • 每次新插入的元素一定位于叶子
      在这里插入图片描述

AVL树(平衡二叉查找树)

  • 思考:从序列{1,2,3,4,5… n}依次插入构造出的二叉查找树长什么样?
    在这里插入图片描述
  • 退化成一个单链表,查找目标值的时间复杂度为O(n)
  • AVL树:尽量保持一棵二叉查找树的 平衡性
    • 每一个结点的左右子树的高度差 <= 1
  • 方法:
    • 如果插入一个结点导致树不平衡,通过 旋转 调整回平衡
      在这里插入图片描述

Key 1:二叉查找树中任意结点:>左子树 所有结点 ,<右子树 所有结点(not左孩子,右孩子)
Key 2:二叉查找树查找: 左小右大
Key 3:二叉查找树插入: 小往左,大往右
Key 4:AVL树:任意结点左右子树高度差 <= 1
Key 5:当插入或删除导致AVL树不平衡则需要进行 旋转 使其重新平衡
Key 6:二叉查找树的 中序 遍历就是其所有元素的有序序列

哈希表

哈希表(散列表)

  • 前面介绍的两种查找都需要维护元素的有序性
  • 但我们只是单纯地想知道:有 or 没有
  • 所以可以建立 元素值 -> 数组下标映射,直接判断目标值是否存在结构中
  • 例:元素为{22,6,19,18,2},通过 h(x) = x % 7 的映射关系将其映射到数组对应位置上(-1表示空值)
    在这里插入图片描述
  • 查找19:直接计算19 % 7 = 5,访问nums[5] => 判断查找成功
  • 查找24:直接计算24 % 7 = 3,访问nums[3] => 判断查找失败
  • 这种映射关系就叫做哈希,这个结构就叫做哈希表, h(x) = x % 7 就是哈希函数,经过哈希函数算出来的值就叫做哈希值就是上图中的数组下标

哈希冲突

  • 假设哈希函数 h(x) = x % 7
  • 元素为{22,6,19,18,2},构造了哈希表:
    在这里插入图片描述
  • 现在插入元素29:
    • 计算哈希值h(29) = 29 % 7 = 1
    • 试图将29放入nums[1],发现nums[1]已经放了22 => 产生了 冲突

哈希表冲突解决方案1:开放地址法

  • 假设哈希函数 h(x) = x % 7
  • 元素为{22,6,19,18,2},构造了哈希表:
    在这里插入图片描述
  • 现在插入元素29,哈希值为1,产生了冲突
  • 继续下一级哈希:h₁ = (1 + 1) % 7
  • 仍然冲突?再哈希:h₂ = (1 + 2) % 7
  • 直至哈希至:h₆ = (1 + 6) % 7
  • 29经过3次哈希,放入nums[3]
  • 以上方法称为 线性探测法:H + 1 -> H + 2 -> … -> H + k (k <= m - 1,m为哈希表内置长度,也叫底层数组的长度,此处m = 7)
  • 还有一种方法叫做 二次探测法:1² -> -1² -> 2² -> -2² -> … -> k² -> -k² (k <= m / 2) 了解即可,考试考试考得少,考到题目一般都会给介绍
  • 开放地址法:产生冲突时使用增量di继续哈希,直至有空位或发现表满了
  • hi = (H + di) % m
    • 线性探测:di = 1, 2, 3, 4, 5 … k ( k <= m - 1)
      (看似复杂,其实就是冲突时向后挪直至有空位,到末尾了就回到开头继续试)
    • 二次探测:di = 1², -1², 2², -2², 3², -3² … , k², -k² (k <= m / 2)

哈希表冲突解决方法2:链地址法

  • 链地址法:将哈希值相同的元素存放在同一个 单链表
  • h(x) = x % 7,依次插入22,6,19,18,2,29,30,42,10,54,50
  • 查找x:①根据 h(x) 找到链表头 ②然后在链表上顺序查找

哈希表查找时间复杂度

  • 最理想情况下:哈希函数特别牛逼,没有冲突,所有目标值只需要1次哈希 => O(1)
  • 一般情况下:取决于数据元素的分布,哈希函数的设计和冲突解决方法

Key 1:哈希函数是一个映射:元素值 -> 哈希值
Key 2:不同的元素拥有相同的哈希值:冲突
Key 3:哈希函数应尽量能较为均匀地映射元素 => 降低冲突概率
Key 4:冲突解决方法:①开放地址法 ②链地址法
Key 5:线性探测法就是向后逐个位置试

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Len1Mi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值