算法-快速排序和归并排序

时间复杂度为\(O(nlogn)\)的排序有:快速排序、归并排序、堆排序。

1. 快速排序

  • 时间复杂度
    • 平均时间复杂度为\(O(nlogn)\)
    • 最坏情况时间复杂度为\(O(n^2)\)
  • 空间复杂度
    • 平均空间复杂度为递归栈带来的\(O(logn)\)
    • 最坏情况会退化为\(O(n^2)\)
  • 稳定性:快速排序不是稳定排序算法。
public static void quickSort(int[] arr) {
    if(arr == null || arr.length <= 1)  
        return ;

    quickSort(arr, 0, arr.length-1);
}

private static void quickSort(int[] arr, int left, int right) {
    if (left >= right)
        return ;
    
    int pivotIndex = partition(arr, left, right);

    // 递归
    // pivot 已经被放到了正确的位置,因此左右半区不需要包含pivotIndex了
    quickSort(arr, left, pivotIndex-1);
    quickSort(arr, pivotIndex+1, right);
}


private static int partition(int[] arr, int left, int right) {
    // 选最左边的元素作为pivot
    int pivot = arr[left];

    int low = left+1;
    int high = right;
    
    //两个指针在中间某处相遇
    while(low <= high) {
        //low要找到第一个大于key的值
        while(low <= right && arr[low] <= pivot) {
            low++;
        }
        //high要找到第一个小于key的值
        while(high > left && arr[high] >= pivot) {
            high--;
        }

        if(low < high) {
            swap(arr, low, high);
        }
    }

    // 把pivot 放到两个指针相遇的位置
    swap(arr, left, high);
    return high;
}

private static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

2. 归并排序

\(T(n) = 2 * T(\frac{n}{2}) + O(n)\),其中合并两个有序数组的时间复杂度是\(O(n)\)

  • 时间复杂度:最好情况、最坏情况、平均情况都为\(O(nlogn)\)
  • 空间复杂度\(O(n)\)。归并排序不是原地排序算法,需要额外的空间来存储tmp数组。
  • 稳定性:归并排序是稳定排序算法,即相同的元素在排序后依然保持原来的顺序。
  • 适用场景:链表、外存
public static void mergeSort(int[] arr){
    if (arr == null || arr.length<=1)
        return ;
    
    int[] tmp = new int[arr.length];
    mergeSort(arr, 0, arr.length-1, tmp);
}


private static void mergeSort(int[] arr, int left, int right, int[] tmp){
    if(left >= right) 
        return;
    
    int mid = left + (right - left) / 2;    // 防止整数溢出

    // 分支递归
    mergeSort(arr, left, mid, tmp);         // 左半部分
    mergeSort(arr, mid+1, right, tmp);      // 右半部分

    // 合并两个有序数组
    merge(arr, left, mid, right, tmp);
}


private static void merge(int[] arr, int left, int mid, int right, int[] tmp) {
    int leftIndex = left;
    int rightIndex = mid+1;
    int tmpIndex = left;        // 临时数组索引

    while(leftIndex<=mid && rightIndex<=right) {
        if(arr[leftIndex] <= arr[rightIndex]) {
            tmp[tmpIndex++] = arr[leftIndex++];         
        } else {
            tmp[tmpIndex++] = arr[rightIndex++];
        }
    }

    // 将剩余元素拷贝到临时数组中
    while(leftIndex <= mid) {
        tmp[tmpIndex++] = arr[leftIndex++]; 
    }
    while(rightIndex <= right) {
        tmp[tmpIndex++] = arr[rightIndex++];
    }

    // 将临时数组的内容拷贝回原数组
    for(int i = left; i<=right; ++i) {
        arr[i] = tmp[i];
    }
}
posted @ 2025-11-13 12:15  Frank23  阅读(35)  评论(0)    收藏  举报