算法作业6

该博客介绍了如何使用分治策略在给定的整数数组中有效地找到第k小的元素。通过二分归并排序和中位数查找,算法将数组划分为较小、相等和较大三个部分,并递归地解决子问题,最终达到O(n)的时间复杂度。代码示例展示了在C语言中实现这一算法的过程。
摘要由CSDN通过智能技术生成

问题:
设L是n个元素的集合,从L中选取第k小的元素,其中1<=k<=n。
这里第k小的元素是指,当L按从小到大排好序之后,排在第k个位置的元素。
利用特定分治策略选出第k小的元素。

解析:
k=|S1|+1, m’ 就是所要找的第k小的数(以m’为划分标准后, 比m’小的有|S1|个,如果恰巧k=|S1|+1, 则m’就是所要找的第k小的数)
k<=|S1|,归约为在s1,中找第k1小的子问题,k1在子问题中相对位置不变,即k1=k ;
k>|S1|+1,归约为在S,中找k2位置的子问题,k2 相对于S2子问题和k相对于S的关系,即k2= k-|S1|-1。(在S中找k,就是在S2中找k2)

设计

#include <stdio.h>
#include <stdlib.h>

void merge(int a[],int left,int mid,int right) //二分归并排序 
{
    int i,k;
    int *tmp = (int *)malloc((right-left+1)*sizeof(int));
    int left1=left;
    int left2=mid;
    int right1=mid+1;
    int right2=right;
    for(k=0;left1<=left2 && right1<=right2;k++)
	{
        if(a[left1]<=a[right1])
		{
            tmp[k]=a[left1++];
        }
		else
		{
            tmp[k]=a[right1++];
        }
    }
    if(left1<=left2)
	{
	    for(i=left1;i<=left2;i++)
	    {
	    	tmp[k++]=a[i];
		}
    }

    if(right1<=right2)
	{
        for(i=right1;i<=right2;i++)
        {
        	tmp[k++] = a[i];
		}
    }
    for(i=0;i<right-left+1;i++)
    {
    	a[left+i]=tmp[i];
	}
    free(tmp);
    return;
}
void merge_sort(int a[],int left,int right)
{
    int mid = 0;
    if(left<right)
	{
        mid = (left+right)/2;
        merge_sort(a,left,mid);
        merge_sort(a,mid+1,right);
        merge(a,left,mid,right);
    }
    return;
}


int select(int a[],int left,int right,int k) 
{
	int n=right-left;
	if (n<5)
	{
		merge_sort(a,left,right-1);
		return a[left+k-1];
	}
	int i;
	int s=n/5;
	int *m = new int[s];//中位数数组
	for (i=0;i<s;i++) 
	{
		merge_sort(a,left+i*5,left+i*5+5-1);
		m[i] = a[left+i*5+2];
	}
	merge_sort(m,0,i-1);
	int mid=m[i/2];
	int *a1=new int[n];
	int *a2=new int[n];
	int *a3=new int[n];
	int num1=0,num2=0,num3=0;
	for(int i=left;i<right;i++)
	{
		if(a[i]<mid)
		{
			a1[num1++]=a[i];
		}
		else if(a[i]==mid)
		{
			a2[num2++]=a[i];
		}
		else
			a3[num3++]=a[i];
	}
	if(num1>=k)
	{
		return select(a1,0,num1,k);
	}
	if (num1+num2>=k)
	{
		return mid;
	}
	else
		return select(a3,0,num3,k-num1-num2);
}
 
int main()
{
    int n;
    printf("数组大小:");
    scanf("%d",&n);
    int a[n];
    printf("数据:");
    for(int i=0;i<n;i++)
    {
    	scanf("%d",&a[i]);
	}
	int k;
	printf("第几小:");
	scanf("%d",&k);
	printf("第%d小元素:",k);
	printf("%d\n", select(a,0,n,k));
    return 0;
}

分析:
时间复杂度为O(n)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值