从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 大元素的情况,尤其是在处理大数据集时表现尤为出色。

相关推荐
MicroTech20251 小时前
MLGO微算法科技 D-S融合算法技术发布,助力脑机接口迈向实用化
大数据·科技·算法
摇滚侠1 小时前
2025最新 SpringCloud 教程,Gateway 路由-规则配置,笔记53
笔记·spring cloud·gateway
Q741_1471 小时前
C++ 栈 模拟 力扣 844. 比较含退格的字符串 题解 每日一题
c++·算法·leetcode·模拟·
CoderYanger1 小时前
动态规划算法-简单多状态dp问题:14.粉刷房子
开发语言·算法·leetcode·动态规划·1024程序员节
张张努力变强1 小时前
二叉树——精选题目,体验递归的暴力美学!
c语言·数据结构·算法
老王熬夜敲代码1 小时前
万能引用、完美转发
c++·笔记
FMRbpm1 小时前
栈练习--------(LeetCode 739-每日温度)
数据结构·c++·算法·leetcode·新手入门
子一!!1 小时前
数据结构==二叉平衡树,AVL树 ===
数据结构·算法
Mr_Oak1 小时前
【multi-model】DINOv2(包含iBOT)& 问答
图像处理·人工智能·深度学习·算法·多模态·对比学习·视觉大模型