算法设计与分析第二章作业

一.请用自然语言或伪代码描述找第k小的数的分治算法

1.题目

设计一个平均时间为O(n)的算法,在n(1<=n<=1000)个无序的整数中找出第k小的数。

提示:函数int partition(int a[],int left,int right)的功能是根据a[left]~a[right]中的某个元素x(如a[left])对a[left]~a[right]进行划分,划分后的x所在位置的左段全小于等于x,右段全大于等于x,同时利用x所在的位置还可以计算出x是这批数据按升非降序排列的第几个数。因此可以编制int find(int a[],int left,int right,int k)函数,通过调用partition函数获得划分点,判断划分点是否第k小,若不是,递归调用find函数继续在左段或右段查找。

输入格式:

输入有两行:

第一行是n和k,0<k<=n<=10000

第二行是n个整数

输出格式:

输出第k小的数

输入样例:

在这里给出一组输入。例如:

10 4
2 8 9 0 1 3 6 7 8 2

输出样例:

在这里给出相应的输出。例如:

2

2.代码

#include<bits/stdc++.h>
using namespace std;
int a[100005];

void merg(int *a,int left,int mid,int right){
    int* b = new int[right - left + 1];    //建立辅助空间,方便输出最终结果
    int i=left;
    int j=mid+1;
    int k=0;
    while(i <= mid && j <= right){
    if(a[i]<=a[j]){
        b[k++]=a[i++];
    }
    else{
        b[k++]=a[j++];
    }
}
    
    while (i <= mid)  
    {
        b[k++] = a[i++];
    }
    while (j <= right)
    {
        b[k++] = a[j++];
    }
    
    k = 0;  
    for (int i = left; i <= right; i++)  
    {
        a[i] = b[k++];
    }
    delete[]b; 

}

void mergsort(int *a,int left,int right){
    if(left<right){
        int mid=(left+right)/2;
        mergsort(a,left,mid);
        mergsort(a,mid+1,right);    //不断划分为几个子问题
        merg(a,left,mid,right);   //单独处理子问题
    }
}

int main(){
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++) cin>>a[i];
    mergsort(a,0,n-1);
    cout<<a[k-1];
}

3.运行结果

4.知识点

4.1分治法

将问题分解为更小的子问题,然后递归地解决这些子问题,最后将子问题的结果合并以得到原问题的解。

4.2归并排序法

(1)选基准 

从数组中选一个元素作为基准。这个选择可以随便。

 (2)分区

根据基准元素将数组重新排列,使得所有小于基准的元素都位于基准的左侧,所有大于或等于基准的元素都位于基准的右侧。

(3)递归

根据分区结果,确定基准元素的位置。

如果基准元素的位置正好是k-1,则基准元素就是第k小的数。

如果基准元素的位置小于k-1,则第k小的数位于基准元素的右侧子数组中,继续在右侧子数组中递归查找。

如果基准元素的位置大于k-1,则第k小的数位于基准元素的左侧子数组中,继续在左侧子数组中递归查找,并且k值要减去左侧子数组的大小加1。

二.分析该算法的最好时间复杂度和最坏时间复杂度

1.最好时间复杂度

在最好的情况下,每次选择的基准都是当前子数组中的最小值或最大值,这样每次划分都能将数组分成两个几乎相等的部分。在这种情况下,算法的时间复杂度接近于线性,即 O(n)。

2.最坏时间复杂度

在最坏的情况下,每次选择的基准都是当前子数组中的最小值或最大值,这样每次划分只能将数组分成一个元素和其余元素两部分。在这种情况下,算法的时间复杂度退化为 O(n^2)。

三.结合本章的学习,谈谈你对分治法的体会和思考

分治法是一种广泛应用的算法设计范式,其核心在于将复杂问题拆解为更小的、更易于管理的子问题。这些子问题随后会递归地被解决,而它们的解最终会被整合起来,形成原问题的完整解答。分治法直观易懂,能够广泛应用于多种场景,有效地简化问题并找到解决方案。由于分治法通常需要递归调用,这可能会增加算法实现的复杂度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值
>