写在开头的话
学习了快速排序算法后让我们来连一点题目吧。(题目是别的地方扒来的)【文末还有对于求第k小数的代码分析】
第一题------排序

第二题------补全代码(第k小数)

源代码
C
cs
#include <stdio.h>
int quick_select(int a[], int l, int r, int k) {
int p = rand() % (r - l + 1) + l;
int x = a[p];
{int t = a[p]; a[p] = a[r]; a[r] = t;}
int i = l, j = r;
while(i < j) {
while(i < j && a[i] < x) i++;
if(i < j) {
a[j] = a[i];
j--;
}
while(i < j && a[j] > x) j--;
if(i < j) {
a[i] = a[j];
i++;
}
}
a[i] = x;
p = i;
if(i - l + 1 == k) return a[i];
if(i - l + 1 < k) return quick_select( _____________________________ ); //填空
else return quick_select(a, l, i - 1, k);
}
int main()
{
int a[100];
int n;
scanf("%d %d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
printf("%d\n", quick_select(a, 0, n-1, 5));
return 0;
}
Java
java
import java.util.Scanner;
import java.util.Random;
public class Main{
public static int quickSelect(int a[], int l, int r, int k) {
Random rand = new Random();
int p = rand.nextInt(r - l + 1) + l;
int x = a[p];
int tmp = a[p]; a[p] = a[r]; a[r] = tmp;
int i = l, j = r;
while(i < j) {
while(i < j && a[i] < x) i++;
if(i < j) {
a[j] = a[i];
j--;
}
while(i < j && a[j] > x) j--;
if(i < j) {
a[i] = a[j];
i++;
}
}
a[i] = x;
p = i;
if(i - l + 1 == k) return a[i];
if(i - l + 1 < k) return quickSelect( _________________________________ ); //填空
else return quickSelect(a, l, i - 1, k);
}
public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int a[]=new int[110];
for(int i=0;i<n;i++)
{
a[i]=scan.nextInt();
}
System.out.println(quickSelect(a, 0, n-1, 5));
}
}
第一题参考答案(Python版)
python
import sys
import random
def partition(arr, left, right):
"""三路分区,返回小于区边界和大于区边界"""
# 随机选择基准值
pivot_idx = random.randint(left, right)
pivot = arr[pivot_idx]
# 初始化三个区域的指针
lt = left # 小于基准值的区域的右边界
gt = right # 大于基准值的区域的左边界
i = left # 当前元素指针
while i <= gt:
if arr[i] < pivot:
arr[lt], arr[i] = arr[i], arr[lt]
lt += 1
i += 1
elif arr[i] > pivot:
arr[gt], arr[i] = arr[i], arr[gt]
gt -= 1
else:
i += 1
return lt, gt
def quick_sort(arr, left, right):
"""迭代快速排序,使用栈实现"""
if left >= right:
return
stack = [(left, right)]
while stack:
left, right = stack.pop()
if left >= right:
continue
# 当区间较小时,使用插入排序
if right - left + 1 < 20:
insertion_sort(arr, left, right)
continue
lt, gt = partition(arr, left, right)
# 先处理较小的子区间,减少栈深度
left_len = lt - left
right_len = right - gt
if left_len < right_len:
if left < lt - 1:
stack.append((left, lt - 1))
if gt + 1 < right:
stack.append((gt + 1, right))
else:
if gt + 1 < right:
stack.append((gt + 1, right))
if left < lt - 1:
stack.append((left, lt - 1))
def insertion_sort(arr, left, right):
"""插入排序,用于小数组优化"""
for i in range(left + 1, right + 1):
key = arr[i]
j = i - 1
while j >= left and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
def main():
# 读取输入
data = sys.stdin.read().strip().split()
if not data:
return
n = int(data[0])
arr = list(map(int, data[1:1+n]))
# 特殊情况处理
if n == 0:
print()
print()
return
if n == 1:
print(arr[0])
print(arr[0])
return
# 使用优化后的快速排序
quick_sort(arr, 0, n - 1)
# 输出结果
print(' '.join(map(str, arr)))
print(' '.join(map(str, arr[::-1])))
if __name__ == "__main__":
main()
第二题参考答案(C版)
java
#include <stdio.h>
#include <stdlib.h> // 需要包含stdlib.h以使用rand()
int quick_select(int a[], int l, int r, int k) {
int p = rand() % (r - l + 1) + l;
int x = a[p];
{int t = a[p]; a[p] = a[r]; a[r] = t;}
int i = l, j = r;
while(i < j) {
while(i < j && a[i] < x) i++;
if(i < j) {
a[j] = a[i];
j--;
}
while(i < j && a[j] > x) j--;
if(i < j) {
a[i] = a[j];
i++;
}
}
a[i] = x;
p = i;
if(i - l + 1 == k) return a[i];
if(i - l + 1 < k) return quick_select(a, i + 1, r, k - (i - l + 1)); // 填空补全
else return quick_select(a, l, i - 1, k);
}
int main()
{
int a[100];
int n;
scanf("%d", &n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
printf("%d\n", quick_select(a, 0, n-1, 5));
return 0;
}
第二题第k小数的解题思路
算法介绍
使用快速排序的思想,可以高效地找到数组中的第 k 小元素。这种方法被称为 "快速选择"(Quickselect),它是快速排序的一种变种,时间复杂度为 O(n),在平均情况下比完整的快速排序更快,因为它只关注一部分数据。
题目分析
在这个快速选择算法中,填空部分需要调用 quick_select 函数,在右半部分递归查找第 k 小的元素。如果当前的 pivot 位置 p 处的元素不是第 k 小的元素,而它左边的元素数目少于 k 个,那么 k 小的元素一定在右边部分。在这种情况下,我们需要递归查找右半部分,并且 k 的值要减去左半部分的元素数目。
填空部分应该填写:

递归过程:
- 如果分区点正好是第
k个元素的位置,那么这个元素就是我们要找的第k小元素。 - 如果分区点在第
k个元素之后,我们在左边的子区间继续查找。 - 如果分区点在第
k个元素之前,我们在右边的子区间继续查找。
复杂度分析
- 时间复杂度 :平均时间复杂度为 O
(n)。虽然最坏情况下时间复杂度为 O(),但平均情况下,该算法要比 O(n log n)的排序方法更高效。 - 空间复杂度 :O
(1),快速选择是原地算法,不需要额外的空间。
适用场景
快速选择算法适用于需要高效查找数组中第 k 小或第 k 大元素的情况,尤其是在处理大数据集时表现尤为出色。