Quicksort不适用于排序数组

时间:2018-04-29 19:30:03

标签: c++ sorting quicksort

我正在做一个比较Bubblesort和Quicksort算法的项目。一切正常,直到我想对已经使用Quicksort方法排序的数据进行排序。它在大型阵列(50k,100k)上崩溃。

在我的情况下,我首先按降序对数据进行排序,然后尝试按升序排序然后崩溃。

        read();  // just creates an array with random integers
        quickSortDSC(0, length - 1); //Here is the problem! (works if commented)
        t1 = clock();
        quickSortASC(0, length - 1);
        t2 = clock();
        cout << "Quick Sort\t: " << (t2 - t1)/CLK_TCK << " sec\n";

完整代码:

    #include <iostream>
#include <fstream>
#include <cstdlib>
#include <ctime>

using namespace std;

long length = 1000;
const long max_length = 100000;

int list[max_length];

void read()
{
    ifstream fin("random.dat", ios::binary);
    for (long i = 0; i < length; i++)
    {
        fin.read((char*)&list[i], sizeof(int));
    }
    fin.close();
}

void bubbleSort()
{
    int temp;
    for(long i = 0; i < length; i++)
    {
        for(long j = 0; j < length-i-1; j++)
        {
            if (list[j] > list[j+1])
            {
                temp        = list[j];
                list[j]     = list[j+1];
                list[j+1]   = temp;
            }
        }
    }
}


long partitionASC(long left, long right)
{
    int pivot_element = list[left];
    int lb = left, ub = right;
    int temp;

    while (left < right)
    {
        while(list[left] <= pivot_element)
            left++;
        while(list[right] > pivot_element)
            right--;
        if (left < right)
        {
            temp        = list[left];
            list[left]  = list[right];
            list[right] = temp;
        }
    }
    list[lb] = list[right];
    list[right] = pivot_element;
    return right;
}

long partitionDSC(long left, long right)
{
    int pivot_element = list[left];
    int lb = left, ub = right;
    int temp;

    while (left < right)
    {
        while(list[left] >= pivot_element)
            left++;
        while(list[right] < pivot_element)
            right--;
        if (left < right)
        {
            temp        = list[left];
            list[left]  = list[right];
            list[right] = temp;
        }
    }
    list[lb] = list[right];
    list[right] = pivot_element;
    return right;
}
//ascending order
void quickSortASC(long left, long right)
{
    long pivot;
    if (left < right)
    {
        pivot = partitionASC(left, right);
        quickSortASC(left, pivot-1);
        quickSortASC(pivot+1, right);
    }
}

//descending order
void quickSortDSC(long left, long right)
{
    long pivot;
    if (left < right)
    {
        pivot = partitionDSC(left, right);
        quickSortDSC(left, pivot-1);
        quickSortDSC(pivot+1, right);
    }
}

int main()
{
    double t1, t2;

    for (length = 1000; length <= max_length; )
    {
        cout << "\nLength\t: " << length << '\n';

        read();
        t1 = clock();
        bubbleSort();
        t2 = clock();
        cout << "Bubble Sort\t: " << (t2 - t1)/CLK_TCK << " sec\n";


        read();
        quickSortDSC(0, length - 1); //Here is the problem!
        t1 = clock();
        quickSortASC(0, length - 1);
        t2 = clock();
        cout << "Quick Sort\t: " << (t2 - t1)/CLK_TCK << " sec\n";

        if(length == max_length)
            break;

        switch (length)
        {
        case 1000 :
            length = 10000;
            break;
        case 10000 :
            length = 50000;
            break;
        case 50000 :
            length = 100000;
            break;
        }
    }

    return 0;
}

2 个答案:

答案 0 :(得分:2)

通过选择数组的第一个元素作为数据透视表,当数组已经排序时,您会遇到快速排序最坏情况的行为。所以你得到O(n 2 )行为(更糟糕的是,O(n)堆栈空间,这可能会给你一个堆栈溢出)。

为避免这种情况,请选择其他枢轴。通常会选择中间元素作为轴:

int pivot_element = list[(left+right)/2];

或随机元素:

int pivot_element = list[left + random()%(right+1-left)];

答案 1 :(得分:0)

例如。假设情况为{3,6,4,7}。 无论您选择“单枢轴”还是“双枢轴” QuickSort,如果始终将第一个元素作为枢轴,那么对于排序后的数组,很有可能会面临堆栈溢出或O(n2)。

因此,在每个递归循环中将枢轴/秒随机化可以防止在最坏的情况下进入O(n2)或无限循环。

下面的例子将很好地解释最坏的情况。

package algo.sorting.rev;

import java.util.Arrays;

公共类DualPivotQuickSort {

public static void main(String[] args) {
    int[] input = new int[] { 8, 6, 2, 4, 17,    3, 10, 19, 21, 13,   9, 19, 14, 13, 7,   17 };
    quicksort(input, 0, input.length - 1);
    System.out.println(Arrays.toString(input));
}

/**
 * 3 segments are as below.
 * 
 * | item < pivotL | pivotL <= item <= pivotR | item > pivotR |
 * 
 * |pivotLPos . . . j-1|j . . . k|k+1 . . . pivotRPos|
 * 
 * 
 * @param a
 * @param pivotLPos
 * @param pivotRPos
 */
private static void quicksort(int [] a, int pivotLPos, int pivotRPos){
    int size  = pivotRPos - pivotLPos + 1;

    if(size < 3)
        return;

    int pivotL = a[pivotLPos];
    int pivotR = a[pivotRPos];

    if(pivotL > pivotR)
        swapContent(a, pivotLPos, pivotRPos);

    int i = pivotLPos + 1;
    int j = pivotRPos - 1;
    int k = pivotRPos;

    while(i <= j){

        while(i < pivotRPos && a[i] < pivotL)
            i++;

        while(j >= pivotLPos && a[j] >= pivotL){
            if(a[j] <= pivotR)
                j--;
            else{  
                // adding to segment3
                swapContent(a, j, k);
                j--;
                k--;
            }
        }

        if(i < j){
            swapContent(a, i, j);
            i++;

            if(a[j] > pivotR){
                // adding to segment3
                swapContent(a, j, k);
                k--;
            }
            j--;
        }
    }

    swapContent(a, j, pivotLPos);

    if(size > 3){
        if(j - pivotLPos >= 3)
            quicksort(a, pivotLPos, j-1);  // recursion on seg1
        if(k - j >= 3)
            quicksort(a, j, k);  // recursion on seg2
        if(j - pivotRPos >= 3)
            quicksort(a, k+1, pivotRPos);  // recursion on seg3
    }
}

private static void swapContent(int [] a, int pos1, int pos2){
    int b = a[pos1];
    int c = a[pos2];

    b ^= c;
    c ^= b;
    b ^= c;

    a[pos1] = b;
    a[pos2] = c;
}

}