2.分治-找第k大数

问题描述

 Find the ith largest number of n numbers. (Use divide-and-conquer method)

翻译

找第k大数

思路
//* 1.首先将数组分为五五一组,并且进行排序
//* 2.将每个组a[2]也就是中位数,挪到a[0]-a[(r-p-4)/5],也就是数组前几个,(r-p-4)/5代表五个组的个数
//* 3.递归找到中位数的中位数
//* 4.对整个数组进行排序,使中位数的中位数左边<中位数的中位数,右边>中位数的中位数,参考快排
//* 5.定位中位数的中位数的索引,分情况递归。
 

代码

#define  _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <stdlib.h>
//思路
/*
* 1.首先将数组分为五五一组,并且进行排序
* 2.将每个组a[2]也就是中位数,挪到a[0]-a[(r-p-4)/5],也就是数组前几个,(r-p-4)/5代表五个组的个数
* 3.递归找到中位数的中位数
* 4.对整个数组进行排序,使中位数的中位数左边<中位数的中位数,右边>中位数的中位数,参考快排
* 5.定位中位数的中位数的索引,分情况递归。
*/
using namespace std;
int n;
const int N = 1e6 + 10;
int ans[N]; int k1 = 0;//mergeSort
void quickSort(int a[], int l, int r)
{
	int i = l-1, j = r+1, mid = (l + r) / 2;
	int tem = a[mid];
	if (l >=r) return;
	while (i < j)
	{
		do i++; while (a[i] > tem);
		do j--; while (a[j] < tem);
		if (i <=j)swap(a[i], a[j]);
	}
	quickSort(a, l, j);
	quickSort(a, j + 1, r);

}
void mergeSort(int a[], int l, int r)
{
	if (l >=r) return;
	int mid = (l + r) / 2;
	mergeSort(a, l, mid );
	mergeSort(a, mid + 1, r);
	int k1=0, i = l, j = mid+1;
	while (i <=mid&& j<=r)
	{
		if (a[i] >=a[j])
			ans[k1++] = a[i++];
		else
			ans[k1++] = a[j++];
	}
	while(i<=mid)
		ans[k1++] = a[i++];
	while (j <= r)
		ans[k1++] = a[j++];
	for (int i = l, j=0; i <=r; i++,j++)
	{
		a[i] = ans[j];
	}
}
int partition(int a[], int l, int r,int x)//返回中位数索引,并且将数组排成小于中位数的中位数x
{
	
	int i = l - 1, j = r + 1, tem = x;
	while (i < j)
	{
		do i++;
		while (a[i] > tem);
		do j--;
		while (a[j] < tem);
		if (i < j)
			swap(a[i], a[j]);

	}
	return i;
}//ith最大改为最小只需要将这个函数里面><以及快排的><反过来
int find(int a[], int l, int r, int k)
{
	if (r - l < 75)
	{
	
		mergeSort(a,l,r);
		return a[l+k - 1];//if n<75 O(n)=C
	}
	for (int i = 0; i < r; i+=5)
	{
		

		mergeSort(a, i, i + 4);//每五个一排序
	}

	for (int i = 0; i < (r - l - 4) / 5; i++)
	{
		swap(a[i+l], a[l + 5 * i+2]);//i表示第i组,将每组中位数换到数组前几位
		//l+5*i+2和r-l-4搭配确保数组不越界
	}
	int x = find(a, l, (r - l - 4) / 5, (r - l - 4) / 10);//找出中位数的中位数,用x表示
	int  i = partition(a, l, r,x);//使i左边都<x,右边都>x;
	int j = i-l+1;//左边一共j个数,k<j时从左边找,否则从右边找
	if (k > j)
		return find(a, i+1, r, k - j);
	else
		return find(a, l, i, k);

}
int main()
{
	int k = 0;
	cout << "Please enter the number of the array" << endl;
	scanf("%d", &n);
	int a[N];
	cout << "Please enter which maximum number to look for" << endl;
	cin >> k;
	cout << "Please enter the array" << endl;
	for (int i = 0; i < n; i++)
	{
		a[i]=rand();
		cout << a[i] << " ";
	}
	cout << endl;
	int mid=find(a, 0, n - 1,k);
	cout << "The ith largest number is" << mid << endl;
	return 0;
}

测试案例

运行结果

时间复杂度分析

速记

见思路 随时更新

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

熟人看不到

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

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

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

打赏作者

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

抵扣说明:

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

余额充值