从0开始学算法——第七天(快速排序算法练习)

写在开头的话

学习了快速排序算法后让我们来连一点题目吧。(题目是别的地方扒来的)【文末还有对于求第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 大元素的情况,尤其是在处理大数据集时表现尤为出色。

相关推荐
守护安静星空8 分钟前
live555学习笔记
笔记·学习
航Hang*22 分钟前
第1章:初识Linux系统——第13节:总复习②
linux·笔记·学习·centos
王老师青少年编程35 分钟前
2025年12月GESP(C++二级): 环保能量球
c++·算法·gesp·csp·信奥赛·二级·环保能量球
weixin_4334176741 分钟前
Canny边缘检测算法原理与实现
python·opencv·算法
CoderCodingNo1 小时前
【GESP】C++五级真题(贪心思想考点) luogu-P11960 [GESP202503 五级] 平均分配
开发语言·c++·算法
日更嵌入式的打工仔1 小时前
Ehercat代码解析中文摘录<2>
笔记·ethercat
YJlio1 小时前
PsPing 学习笔记(14.1):ICMP Ping 进阶——替代系统 ping 的正确姿势
windows·笔记·学习
阿豪只会阿巴1 小时前
【多喝热水系列】从零开始的ROS2之旅——Day3
linux·笔记·ubuntu·ros2
BMS小旭1 小时前
CubeMx-GPIO学习
单片机·学习
POLITE31 小时前
Leetcode 76.最小覆盖子串 JavaScript (Day 6)
javascript·算法·leetcode