次序选择问题
问题描述
查找数组中第k小的值,(中位数)。
算法思路
执行一次快排,然后查找下标即可,所需要的时间复杂度接近\(O(n\log n)\)
通过观察发现子问题不需要合并,只需要分解,跟快速排序的思想一致。
-
选取标志,使用快速排序的方法,将大于数据的放右,小于放左。
-
取标志的坐标,跟k比较,有如下三种情况。
如果这个数据前有s个数据,根据如下表达式可计算第k小的数
\[f(array, k) =\left\{ \begin{matrix}
array[s],\quad k = s\\
f(array[s:end], k-s),\quad k < s\\
f(array[start:s],k),\quad k > s
\end{matrix}\right.
\]
- 对于不同情况继续递归
算法的时间复杂度接近于\(O(n)\)
python伪代码表示
def findKMaxNum(array: [] as a, start: int, end: int, k: int):
# 这里start和end都是计算机从0开始的索引
pivot = randChooseIndex(array) # 随机选取一个下标
quickSortSub(a, pivot, start, end) # 以主元进行一个快速排序的子程序,把大于主元的放前面,小于的放后面
if k > pivot - start + 1:
return findKMaxNum(a, pivot + 1, end, k-(mid-start+1))
elif k < pivot - start + 1:
return findKMaxNum(a, start, pivot - 1, k)
else: return array[pivot]
实际代码演示(以C++为例)
/// @brief 随机选取坐标,然后进行初次排序
/// @param a 数组
/// @param start 开始
/// @param end 结束位置
/// @return 排序后的标志位置
int randon_choose(int array[], int start, int end)
{
if(start == end)
return start;
int pivot_pos = rand() % (end - start) + start;
swap(array[end], array[pivot_pos]);
int left = start;
int right = end;
int pivot_value = array[end];
while (left < right)
{
while (left < right && array[left] < pivot_value)
{
left++;
}
array[right] = array[left];
while (left < right && array[right] > pivot_value)
{
right--;
}
array[left] = array[right];
}
array[right] = pivot_value;
return right;
}
/// @brief 随机选择, 找到第k个小的元素
/// @param array 数组
/// @param start 开始位置
/// @param end 结束位置
/// @return 第k个小的元素
int randon_selection(int array[], int start, int end, int k)
{
int pivot_index = 0;
int mid = randon_choose(array, start, end);
if (k == (mid - start + 1))
{
return array[mid];
}
else if (k < (mid - start + 1))
{
return randon_selection(array, start, mid - 1, k);
}
else if (k > (mid - start + 1))
{
return randon_selection(array, mid + 1, end, k - (mid - start + 1));
}
return -1;
}
int main()
{
int a[9] = {1, 5, 4, 2, 3, 9, 10, 22, 11};
for (int i = 0; i < 9; i++)
{
printf("其中第%d个小的元素为%d\n", i, randon_selection(a, 0, 8, i));
}
return 0;
}
代码运行的结果为
其中第0个大的元素为1
其中第1个大的元素为2
其中第2个大的元素为3
其中第3个大的元素为4
其中第4个大的元素为5
其中第5个大的元素为9
其中第6个大的元素为10
其中第7个大的元素为11
其中第8个大的元素为22
注:这段代码每次运行的结果不同,因为每次运行的时候,计算过快,会导致部分数据值没有计算出来,为了效率直接打印结果,所以需要在每次循环结束后加上
system("pause"),但是这样会导致程序运行时间变长,所以这里就不加了。
部分可能的结果如下
其中第0个大的元素为1
其中第1个大的元素为-1500844437
其中第2个大的元素为2
其中第3个大的元素为3
其中第4个大的元素为4
其中第5个大的元素为5
其中第6个大的元素为9
其中第7个大的元素为10
其中第8个大的元素为11
本文来自博客园,作者:doctordragon666,转载请注明原文链接:https://www.cnblogs.com/riverstream/p/-/findKMaxNum

浙公网安备 33010602011771号