软件工程2303 雷穗辉 分治法找第k小的数

model_s3xy 2024-10-13 21:16:00

软件工程2303 雷穗辉

 

算法概述

我们可以使用一种分治法来寻找数组中第k小的元素。该算法主要思路是使用一个“划分”操作(类似快速排序中的分区过程),通过不断缩小搜索范围来找到目标元素。

伪代码描述

 

  1. 选择一个基准值:从数组中选择一个元素作为基准值(pivot),通常选择最后一个元素。
  2. 分区操作:重新排列数组,所有比基准值小的元素都移动到基准值的左边,所有比基准值大的元素都移动到基准值的右边。分区结束后,基准值就处于其最终位置。
  3. 确定基准值的位置:分区后,基准值的索引就是它在排序后数组中的位置。
  4. 比较基准值的位置与k
    • 如果基准值的位置正好是k-1(因为数组索引从0开始),那么基准值就是第k小的数,返回它。
    • 如果基准值的位置大于k-1,那么第k小的数在基准值的左边,递归地在左边的子数组中查找第k小的数。
    • 如果基准值的位置小于k-1,那么第k小的数在基准值的右边,递归地在右边的子数组中查找第k小的数,并且调整k的值,因为基准值右边的子数组中的元素个数比原数组少一个。
function partition(nums, left, right):
    pivot = nums[right]  // 选择最后一个元素作为基准
    slow = left         // 左指针
    fast = left         // 快指针

    while fast < right:
        if nums[fast] < pivot:
            swap(nums[slow], nums[fast])  // 把小于基准的元素放到左边
            slow++
        fast++

    swap(nums[slow], nums[right])  // 把基准元素放到它的正确位置
    return slow  // 返回基准元素的位置

function find(nums, left, right, k):
    if left >= right: 
        return nums[left]  // 递归基

    slow = partition(nums, left, right)  // 进行划分

    // 计算基准元素在左侧的元素数量
    count = slow - left + 1

    if k == count:  // 找到第k小的元素
        return nums[slow]
    else if k < count:  // 在左边部分继续查找
        return find(nums, left, slow - 1, k)
    else:  // 在右边部分继续查找
        return find(nums, slow + 1, right, k - count)

main:
    input n, k
    input nums[n]  // 输入数组
    result = find(nums, 0, n - 1, k)  // 查找第k小的元素
    output result

时间复杂度分析

  1. 最好情况:在每次划分时,基准元素正好把数组分为两个相等的部分。每次递归时,问题规模减半。

    • 复杂度为 O(nlog⁡n)O(nlogn),因为在每一层递归中,我们都要遍历数组。
  2. 最坏情况:在每次划分时,基准元素是数组中最小或最大元素,导致每次只缩小一个元素的范围。此时,我们需要遍历整个数组。

    • 复杂度为 O(n2)O(n2),这种情况可能在输入数组是已排序的情况下发生。
  3. 平均情况:在随机情况下,每次划分大约将数组分成两部分,复杂度为 O(n)O(n)。

对分治法的体会和思考

       分治法是一种非常强大的算法设计策略,其基本思想是将一个复杂的问题分解成多个相似的子问题,解决这些子问题后再将其结果合并,从而解决原问题。

...全文
75 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

434

社区成员

发帖
与我相关
我的任务
社区描述
广东外语外贸大学信息科学与技术学院
算法 高校
社区管理员
  • brisksea
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧