寻找序列中第 K 小元素(分治法)C++

该程序通过分治策略解决寻找数组内第K小元素的问题。首先定义基数并进行数组划分,然后根据K值在左右区间递归查找,当区间只剩一个元素时返回该元素。在主函数中,输入乱序数组和K值,调用算法并输出结果。
一、实验目的
掌握分治法的基本思想
二、实验内容
实现一个从数组中寻找第 K 小元素算法。
三、算法描述
对于此题目,利用分治法的思想,将复杂的问题变为多个类似的
小问题。该代码中定义一个函数在指定区间中寻找,当区间中至少有
两个元素时,我们需要定义一个基数,从前面和后面开始,将数组分
为两个区域,左边为比基数小的,右边为比基数小的。令 a[i]等于基
数,所求的第 k 小在数组中的下标为 k-1。所以当 k-1=i 时返回 a[i]
的值;若 k-1<i,在左区间递归查找;若 k-1>i 时,在右区间递归查
找。当区间中只有一个元素时,直接返回 a[k-1]
四、实验要求
本实验要求实现以下功能:
(1) 输入一个乱序的数组和 k 值。
(2) 从数组中寻找第 k 小元素。
五、实验代码
#include<iostream>
using namespace std;
int QS(int a[],int s,int t,int k)	
{
	int i=s,j=t;
	int tmp;	//基数 
	if(s<t)	//【1】区间至少两个元素 
	{
		tmp=a[s];
		while(i!=j)
		{
			while(j>i&&a[j]>=tmp)j--;
			a[i]=a[j];
			while(i<j&&a[i]<=tmp)i++;
			a[j]=a[i];
		}
		a[i]=tmp;
		if(k-1==i)return a[i];	//【2】 
		else if(k-1<i)return QS(a,s,i-1,k);	//【2】左区间递归查找 比基准小 
		else return QS(a,i+1,t,k);	//【2】右区间递归查找 
	}
	else if(s==t&&s==k-1)return a[k-1];	//【1】区间只有一个元素 
} 
int main()
{
	int n=8;
	int k;
	cin>>k;
	int a[]={2,3,1,4,5,7,8,6};
	k=QS(a,0,n-1,k);
	cout<<"NO."<<k<<":"<<k<<endl;
	return 0;
}

求解无序序列中第k小元素的常见算法有以下几种: ### 排序法 可以先对无序序列进行排序,然后直接取出第k个元素。例如使用 Java 的 `Arrays.sort` 方法,以下是代码示例: ```java import java.util.Arrays; public class FindKthSmallest { public static int findKthSmallest(int[] arr, int k) { Arrays.sort(arr); return arr[k - 1]; } public static void main(String[] args) { int[] arr = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; int k = 3; System.out.println(findKthSmallest(arr, k)); } } ``` 这种方法的时间复杂度取决于排序算法,常见的排序算法如快速排序、归并排序等平均时间复杂度为 $O(n log n)$。 ### 优先队列法 可以使用优先队列(堆)来解决该问题。以 Java 为例,使用最小堆,不断将元素加入堆中,然后弹出堆顶元素 k 次,最后弹出的元素即为第 k 小元素。在 C++ 中也有类似实现,如引用[3]中的代码: ```cpp #include<queue> #include<iostream> using namespace std; int thk(int *a, int n, int k) { int i, j = 0; priority_queue<int, vector<int>, greater<int> > pq; for (i = 0; i < n; i++) { pq.push(a[i]); } for (i = 1; i <= k; i++) { j = pq.top(); pq.pop(); } return j; } int main() { int x; // 输入的整数个数 cin >> x; int *a = new int[x]; for (int i = 0; i < x; i++) { cin >> a[i]; } int y; // 需要输出的第k=y大的数 cin >> y; int n = x; for (int k = 1; k <= n; k++) { if (k == y) { cout << thk(a, n, k); break; } else continue; } return 0; } ``` 优先队列的插入和删除操作时间复杂度为 $O(log n)$,需要进行 k 次操作,因此总的时间复杂度为 $O(k log n)$。 ### 快速选择算法算法基于快速排序的分治思想。通过选择一个基准元素,将序列分为两部分,根据基准元素的位置与 k 的大小关系,决定在左半部分或右半部分继续查找。以下是 Python 实现的示例: ```python def quick_select(arr, k): if len(arr) == 1: return arr[0] pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] if k <= len(left): return quick_select(left, k) elif k <= len(left) + len(middle): return pivot else: return quick_select(right, k - len(left) - len(middle)) arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] k = 3 print(quick_select(arr, k)) ``` 快速选择算法的平均时间复杂度为 $O(n)$,但在最坏情况下为 $O(n^2)$。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值