排序算法——快排,归并

快速排序:

从数组中随机选一个数,比这个数大的放右边,比这个数小的放左边。

快排中的一个细节:如果一个数等于P的时候,既可以在左边又可以在右边。这么做是为了避免如果数组中所有的数都一样,则会造成数据的不平衡。快排的目的是能够使得左边和右边的数都差不多,这样的话时间复杂度就不会退化到O(N^2),而是O(N * logN)。

这里是用递归实现的。但是这里并不需要回头。那么为什么需要递归呢?原因是循环的时候需要一个参数,这个参数你一开始是不确定的,需要做完这一层之后才能确定接下来循环的参数。但是你又不能等每次循环结束之后再自己去添加参数。所以只能用递归来解决。

还有一个细节是,每次left 和 right进行比较的时候以,要用 <= 而不是 < 。但是当做A[left]/A[right]和 pivot比较的时候,应该用< 而不是 <=。因为单纯用 < 会造成死循环。在最左端只剩下两个数的时候,会造成一个死循环。有交集就会出现问题。只要是左右比较的时候,用 <= 而不用 <;当与中心点做比较的时候,用 < 而不用 <= 。

代码如下所示:

public void quicksort(int[] A, int left, int right){
    if (left > right) {
        return;
    }
    int mid = (left + right) /2
    int target = A[mid];
    while (left <= right) {
        while (left <= right && A[left] < target) {
            left++;
        }
        while (left <= right && A[right] > target) {
            right--;
        }
        if (left <= right) {
            int tmp = A[left];
            A[left] = A[right];
            A[right] = tmp;
        }
    }
quicksort(int[] A, 0, mid);
quicksort(int[] A, mid + 1, A.length - 1);
}

归并排序:

先局部有序,再全局有序。但是由于需要合并两个数组,所以需要额外空间。由于开辟空间和回收空间需要时间消耗,所以归并排序在实际应用上没有快排好。

Merge sort 采用分治的方法,但也是递归。 用双指针方法比较两个排序好的数组。代码的重点在于merge的过程。需要注意的点是当循环结束之后,left 或者 right中有一个可能是没有全部放进去的,这时候要再分别循环一次以保证所有数都放进去了。代码如下:

public void Sort(int[] A) {
    int[] result = new int[A.length];
    mergeSort(A, 0, A.length - 1, result);
    }

public void mergeSort(int[] A, int start, int end, int[] result) {
    if (start > end) {
        return;
    }
    int mid = (start + end) / 2;
    mergeSort(A, start, mid, result);
    mergeSort(A, mid + 1, end, result);
    merge(A, start, end, result);
}

public void merge(int[] A, int start, int end, int[] result) {
    int mid = (start + end) / 2;
    int leftIndex = start;
    int rightIndex = mid + 1;
    int tmp = 0;
    while (leftIndex <= mid && righIndex <= end) {
        if (A[leftIndex] <= A[rightIndex]) {
            result[tmp] = A[leftIndex];
            tmp++;
            leftIndex++;
        }
        else {
            result[tmp] = A[rightIndex];
            tmp++;
            rightIndex++;
        }
        while(leftIndex <= mid) {
            result[tmp] = A[leftIndex];
            tmp++;
            leftIndex++;
        }
        while(rightIndex <= end) {
            result[tmp] = A[rightIndex];
            tmp++;
            rightIndex++;
        }
    for(int i = 0; i <= end; i++){
        A[i] = result[i];
    }
}

时间复杂度的比较:

quick sort的平均时间复杂度是O(N * logN) 。最坏情况是O(N^2) ,这种最坏情况是:这个数组已经是排好序的,而且每次选择的时候都是选最小的(从小到大排)或者是最大的(从大到小排)。

Merge sort 不管怎么说,都是O(N * logN)。

quick sort 空间复杂度是O(1)

Merge sort 额外空间是O(n)

只有Merge sort是稳定排序,quick sort 是不稳定排序。(稳定性:重复的数会保证他们之间的相对顺序)

这两种算法都是分治法。差别在于:quick sort 是先整体有序,再局部有序。 Merge sort是:先局部有序,再整体有序。

快速选择法:quick select。实际上就是快排中间的一个部分。

Kth Largest ELement:利用快速排序的原理,时间复杂度是O(N)。这里指的是平均时间复杂度。

Heap sort: 

猜你喜欢

转载自blog.csdn.net/chichiply/article/details/80660092