【程式設計師面試演算法】快速排序,9種主流程式語言實現!

Newton爱编程發表於2024-11-22

快速排序是一種高效的排序演算法,基於分治策略。是面試中頻繁考察的重點之一。
原理:它選擇一個基準元素,透過一趟排序將待排序序列分割成兩部分。其中一部分的所有元素都比基準元素小,另一部分則比基準元素大。然後,對這兩部分分別進行快速排序,整個序列就逐步變得有序。
實現思路:

  1. 首先,在序列中選擇一個基準元素,常見的是選擇第一個或最後一個元素。
  2. 接著,從序列的兩端開始設定兩個指標,一個從左向右,一個從右向左。左指標尋找大於基準的元素,右指標尋找小於基準的元素,當找到後交換這兩個元素。
  3. 持續這個過程,直到兩個指標相遇,此時將基準元素與相遇位置的元素交換,這樣就完成了一次劃分。
  4. 遞迴地對劃分後的兩個子序列重複上述操作,直到子序列的長度為 1 或 0,此時整個序列排序完成。它的平均時間複雜度為O(n log n) ,但在最壞情況下可能退化為 O(n2)。
    本文使用 C、C++ 、Python、Java、Kotlin、Swift、JavaScript、Rust 和 Go 9 種主流程式語言實現快速排序演算法。

1. C語言

#include <stdio.h>

// 交換兩個元素的值
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 核心程式碼,理解了這個函式就理解了整個演算法。
// 劃分函式1,以最後一個元素為基準,將小於基準的元素放在左邊,大於基準的元素放在右邊
int partition(int arr[], int low, int high) {
    int pivot = arr[low];
    int start = low;
    while (low < high) {
        while (low < high && arr[high] >= pivot) {
            high--;
        }
        while (low < high && arr[low] <= pivot) {
            low++;
        }
        swap(&arr[low], &arr[high]);
    }
    swap(&arr[start], &arr[low]);
    return low;
}

// 劃分函式2,其它語言參考該方法即可
int partition(int arr[], int low, int high) {
    int pivot = arr[high];    // 選擇最後一個元素作為基準
    int i = low - 1;    // i 是小於基準的元素的索引
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[high]); // 關鍵,將基準元素放到正確位置
    return i + 1;
}

// 快速排序函式
void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1); // 遞迴排序左半部分
        quickSort(arr, pi + 1, high); // 遞迴排序右半部分
    }
}

// 列印陣列
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
}

int main() {
    int arr[] = {10, 7, 8, 9, 1, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("原始陣列:\n");
    printArray(arr, n);
    quickSort(arr, 0, n - 1);
    printf("排序後的陣列:\n");
    printArray(arr, n);
    return 0;
}

2. C++

#include <iostream>
using namespace std;

// 劃分函式1
int partition(vector<int>& nums, int low, int high) {
    int pivot = nums[low];
    int start = low;
    while (low < high) {
        while (low < high && nums[high] >= pivot) high--;
        while (low < high && nums[low] <= pivot) low++;
        if (low >= high) {
            break;
        }
        swap(nums[low], nums[high]);
    }
    swap(nums[start], nums[low]);
    return low;
}

// 劃分函式2
int partition(vector<int>& arr, int low, int high) {
    int pivot = arr[high];
    int i = low - 1;
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(arr[i], arr[j]);
        }
    }
    swap(arr[i + 1], arr[high]);
    return i + 1;
}

// 快速排序函式
void quickSort(vector<int>& arr, int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

int main() {
    vector<int> arr = {10, 7, 8, 9, 1, 5};
    cout << "原始陣列:";
    for (int num : arr) cout << num << " ";
    cout << endl;
    quickSort(arr, 0, arr.size() - 1);
    cout << "排序後的陣列:";
    for (int num : arr) cout << num << " ";
    cout << endl;
    return 0;
}

3. Python

def swap(arr, i, j):
    arr[i], arr[j] = arr[j], arr[i]

# 劃分函式1
def partition(arr, low, high):
    pivot = arr[low]
    start = low
    while low < high:
        while low < high and arr[high] >= pivot:
            high -= 1
        while low < high and arr[low] <= pivot:
            low += 1
        if low >= high:
            break
        swap(arr, low, high)
    swap(arr, start, low)
    return low

# 劃分函式2
def partition(arr, low, high):
    pivot = arr[high]
    i = low - 1
    for j in range(low, high):
        if arr[j] < pivot:
            i += 1
            swap(arr, i, j)
    swap(arr, i + 1, high)
    return i + 1

def quick_sort(arr):
    low, high = 0, len(arr) - 1
    while low < high:
        pivot = partition(arr, low, high)
        quick_sort(arr[low:pivot])
        quick_sort(arr[pivot + 1:high + 1])

arr = [10, 7, 8, 9, 1, 5]
print("原始陣列:", arr)
quick_sort(arr)
print("排序後的陣列:", arr)

4. Java

遞迴

public class QuickSortJava {
    static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    // 劃分函式1
    static int partition(int[] nums, int low, int high) {
        int pivot = nums[low]; // 選定陣列第一個元素作為基準值
        int start = low; // 記錄基準值的初始位置

        while (low < high) {
            // 從右向左找第一個小於基準值的元素
            while (low < high && nums[high] >= pivot) {
                high--;
            }
                // 從左向右找第一個大於基準值的元素
            while (low < high && nums[low] <= pivot) {
                low++;
            }
            // 如果low和high沒有交錯,交換它們找到的元素
            if (low >= high) {
                break;
            }
            swap(nums, low, high);
        }
        // 基準值歸位:將基準值放到low(或high,此時它們相等)的位置上
        swap(nums, start, low);
        // 返回基準值的最終位置
        return low;
    }

    // 劃分函式2
    static int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = low - 1;
        for (int j = low; j < high; j++) {
            if (arr[j] < pivot) {
                i++;
                swap(arr, i, j);
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;
        return i + 1;
    }

    static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pi = partition(arr, low, high);
            quickSort(arr, low, pi - 1);
            quickSort(arr, pi + 1, high);
        }
    }

    static void main(String[] args) {
        int[] arr = {10, 7, 8, 9, 1, 5};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }
}

非遞迴

import java.util.Stack;

class Solution {

    public int[] quickSort(int[] nums) {
        Stack<Integer> stack = new Stack<>();
        stack.push(nums.length - 1);
        stack.push(0);

        while (!stack.isEmpty()) {
            int low = stack.pop();
            int high = stack.pop();

            if (low < high) {
                int index = partition(nums, low, high);

                // Push right, middle, and left indices in correct order
                stack.push(index - 1);
                stack.push(low);
                stack.push(high);
                stack.push(index + 1);
            }
        }

        return nums;
    }

    private int partition(int[] nums, int low, int high) {
        int pivot = nums[low];
        int start = low;

        while (low < high) {
            while (low < high && nums[high] >= pivot) {
                high--;
            }
            while (low < high && nums[low] <= pivot) {
                low++;
            }
            if (low >= high) {
                break;
            }
            swap(nums, low, high);
        }

        swap(nums, start, low); // 關鍵,將基準元素放到正確位置
        return low;
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

5. Kotlin

fun swap(arr: IntArray, i: Int, j: Int) {
    val temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}

// 劃分函式1
fun partition(nums: IntArray, low: Int, high: Int): Int {
    val pivot = nums[low]
    var start = low
    while (low < high) {
        while (low < high && nums[high] >= pivot) {
            high--
        }
        while (low < high && nums[low] <= pivot) {
            low++
        }
        if (low >= high) { 
            break
        }
        swap(nums, low, high)
    }
    swap(nums, start, low)
    return low
}

// 劃分函式2
fun partition(arr: IntArray, low: Int, high: Int): Int {
    val pivot = arr[high]
    var i = low - 1
    for (j in low until high) {
        if (arr[j] < pivot) {
            i++
            swap(arr, i, j)
        }
    }
    swap(arr, i + 1, high)
    return i + 1
}

fun quickSort(arr: IntArray) {
    var low = 0
    var high = arr.size - 1

    while (low < high) {
        val pivot = partition(arr, low, high)
        quickSort(arr.copyOfRange(low, pivot))
        quickSort(arr.copyOfRange(pivot + 1, high + 1))
    }
}

fun main() {
    val arr = intArrayOf(10, 7, 8, 9, 1, 5)
    println("原始陣列: ${arr.joinToString()}")
    quickSort(arr)
    println("排序後的陣列: ${arr.joinToString()}")
}

6. Swift

func partition(_ nums: inout [Int], low: Int, high: Int) -> Int {
    let pivot = nums[low]
    var start = low
    while low < high {
        while low < high && nums[high] >= pivot {
            high -= 1
        }
        while low < high && nums[low] <= pivot {
            low += 1
        }
        if low >= high {
            break
        }
        swap(&nums, low, high)
    }
    swap(&nums, start, low)
    return low
}

func partition(_ arr: inout [Int], low: Int, high: Int) -> Int {
    let pivot = arr[high]
    var i = low - 1
    for j in low..<high {
        if arr[j] < pivot {
            i += 1
            swap(&arr, i, j)
        }
    }
    swap(&arr, i + 1, high)
    return i + 1
}

func quickSort(_ arr: inout [Int]) {
    var low = 0
    var high = arr.count - 1

    while low < high {
        let pivot = partition(&arr, low: low, high: high)
        if pivot - low < high - pivot {
            quickSort(&arr[low..<pivot])
            low = pivot + 1
        } else {
            quickSort(&arr[(pivot + 1)...high])
            high = pivot - 1
        }
    }
}

var arr = [10, 7, 8, 9, 1, 5]
print("原始陣列: \(arr)")
quickSort(&arr)
print("排序後的陣列: \(arr)")

7. JavaScript

function swap(arr, i, j) {
    [arr[i], arr[j]] = [arr[j], arr[i]];
}

function partition(nums, low, high) {
    let pivot = nums[low];
    let start = low;
    while (low < high) {
        while (low < high && nums[high] >= pivot) {
            high--;
        }
        while (low < high && nums[low] <= pivot) {
            low++;
        }
        if (low >= high) {
            break;
        }
        swap(nums, low, high);
    }
    swap(nums, start, low);
    return low;
}

function partition(arr, low, high) {
    const pivot = arr[high];
    let i = low - 1;
    for (let j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(arr, i, j);
        }
    }
    swap(arr, i + 1, high);
    return i + 1;
}

function quickSort(arr) {
    let low = 0;
    let high = arr.length - 1;

    while (low < high) {
        const pivot = partition(arr, low, high);
        if (pivot - low < high - pivot) {
            quickSort(arr.slice(low, pivot));
            low = pivot + 1;
        } else {
            quickSort(arr.slice(pivot + 1, high + 1));
            high = pivot - 1;
        }
    }
}

const arr = [10, 7, 8, 9, 1, 5];
console.log("原始陣列:", arr);
quickSort(arr);
console.log("排序後的陣列:", arr);

8. Rust

fn swap(arr: &mut Vec<i32>, i: usize, j: usize) {
    arr.swap(i, j);
}

fn partition(nums: &mut [i32], low: usize, high: usize) -> usize {
    let pivot = nums[low];
    let mut start = low;
    let mut low = low;
    let mut high = high;
    while low < high {
        while low < high && nums[high] >= pivot {
            high -= 1;
        }
        while low < high && nums[low] <= pivot {
            low += 1;
        }
        if low >= high {
            break;
        }
        nums.swap(low, high);
    }
    nums.swap(start, low);
    low
}

fn partition(arr: &mut Vec<i32>, low: usize, high: usize) -> usize {
    let pivot = arr[high];
    let mut i = low as isize - 1;

    for j in low..high {
        if arr[j] < pivot {
            i += 1;
            swap(arr, i as usize, j);
        }
    }
    swap(arr, (i + 1) as usize, high);
    (i + 1) as usize
}

fn quick_sort(arr: &mut Vec<i32>) {
    let mut low = 0;
    let mut high = arr.len() - 1;

    while low < high {
        let pivot = partition(arr, low, high);
        quick_sort(&mut arr[low..pivot].to_vec());
        quick_sort(&mut arr[(pivot + 1)..=high].to_vec());
    }
}

fn main() {
    let mut arr = vec![10, 7, 8, 9, 1, 5];
    println!("原始陣列: {:?}", arr);
    quick_sort(&mut arr);
    println!("排序後的陣列: {:?}", arr);
}

9. Go

package main

import (
        "fmt"
)

func swap(arr []int, i, j int) {
      arr[i], arr[j] = arr[j], arr[i]
}

func partition(nums []int, low, high int) int {
    pivot := nums[low]
    start := low
    for low < high {
        for low < high && nums[high] >= pivot {
            high--
        }
        for low < high && nums[low] <= pivot {
            low++
        }
        if low >= high {
            break
        }
        swap(nums, low, high)
    }
    swap(nums, start, low)
    return low
}

func partition(arr []int, low, high int) int {
    pivot := arr[high]
    i := low - 1
    for j := low; j < high; j++ {
        if arr[j] < pivot {
            i++
            swap(arr, i, j)
        }
    }
    swap(arr, i+1, high)
    return i + 1
}

func quickSort(arr []int) {
    low := 0
    high := len(arr) - 1

    for low < high {
        pivot := partition(arr, low, high)
        quickSort(arr[low:pivot])
        quickSort(arr[pivot+1 : high+1])
    }
}

func main() {
    arr := []int{10, 7, 8, 9, 1, 5}
    fmt.Println("原始陣列:", arr)
    quickSort(arr)
    fmt.Println("排序後的陣列:", arr)
}

以上程式碼分別展示了不同程式語言實現非遞迴的快速排序演算法。希望這篇文章能對你有所幫助,記得收藏起來哦,方便隨時查閱和複習。

相關文章