PTA 5-12 排序 (25分)


給定NN個(長整型范圍內的)整數,要求輸出從小到大排序后的結果。

本題旨在測試各種不同的排序算法在各種數據情況下的表現。各組測試數據特點如下:

 

  • 數據1:只有1個元素;

     

     

  • 數據2:11個不相同的整數,測試基本正確性;

     

     

  • 數據3:103個隨機整數;

     

     

  • 數據4:104個隨機整數;

     

     

  • 數據5:105個隨機整數;

     

     

  • 數據6:105個順序整數;

     

     

  • 數據7:105個逆序整數;

     

     

  • 數據8:105個基本有序的整數;

     

     

  • 數據9:105個隨機正整數,每個數字不超過1000。

     

    輸入格式:

    輸入第一行給出正整數NN(\le 10^5105​​),隨后一行給出NN個(長整型范圍內的)整數,其間以空格分隔。

    輸出格式:

    在一行中輸出從小到大排序后的結果,數字間以1個空格分隔,行末不得有多余空格。

    輸入樣例:

    11
    4 981 10 -17 0 -20 29 50 8 43 -5
    

    輸出樣例:

    -20 -17 -5 0 4 8 10 29 43 50 981
  • 下面試驗了各種排序算法的的表現
  • 算法/時間復雜度

    10^3的隨機整數

    10^4個隨機整數

    10^5個隨機整數

    10^5個順序整數

    10^5個逆序整數

    10^5個基本有序的整數

    10^5個隨機正整數,每個數不超過1000

    冒泡排序

    4ms

    228ms

    >10s

    88ms

    >10s

    650ms

    >10s

    插入排序

    3ms

    35ms

    4784ms

    82ms

    9206ms

    115ms

    4499ms

    選擇排序

    5ms

    332ms

    >10s

    >10s

    >10s

    >10s

    >10s

    歸並排序(遞歸版本)

    4ms

    12ms

    131ms

    82ms

    127ms

    83ms

    75ms

    堆排序

    3ms

    10ms

    103ms

    89ms

    102ms

    126ms

    94ms

    希爾排序

    3ms

    25ms

    128ms

    119ms

    125ms

    117ms

    116ms

    歸並排序(循環版本)

    3ms

    24ms

    125ms

    78ms

    99ms

    77ms

    93ms

    快速排序(pivot取中位數)

    3ms

    10ms

    122ms

    76ms

    112ms

    76ms

    69ms

/* 冒泡排序
 * 1.最好情況 已經有序了O(n) 
 * 2.最壞情況 逆序 O(n^2)
 * 3.平均情況 O(n^2)
 */
void bubble_sort(int a[],int n) {
    for (int i = n - 1; i > 0; i--) {
        int flag = 0;
        for (int j = 0; j < i; j++) {
            if (a[j] > a[j + 1]) {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
                flag = 1;
            }
        }
        if (flag == 0)
            break;
    }
}
/* 
 * 插入排序(對於基本有序的數組排序有較好的表現)
 * 1.最好情況  有序  O(n)
 * 2.最壞情況  逆序  o(n^2)
 * 3.平均情況 O(n^2)
 */
void insertion_sort(int a[],int n) {
    int i, j;
    for (i = 1; i < n; i++) {
        int temp = a[i]; /* 當前要插入的數 */
        for (j = i - 1; j >= 0; j--) {
            if (temp >= a[j])
                break;
            a[j + 1] = a[j];
        }
        a[j + 1] = temp;
    }
}
/*
 * 希爾排序(不穩定) 
 * 1.時間復雜度跟取得序列有關系
 * 2.取 n/2,n/2^2,...,1序列時 最壞情況下時間復雜度為O(n^2)
 * 3.sedgewick序列時 最壞: O(n^3/2) 平均:O(n^5/4)
 */
void shell_sort(int a[],int n) {
    int i, j;
    int sedgewick[] = { 929,505,209,41,19,5,1,0 };
    for (i = 0; sedgewick[i] >= n; i++);
    for(int d=sedgewick[i];d>0;d=sedgewick[++i])
        for (int p = d; p < n; p++) {
            int temp = a[p];
            for (j = p; j >= d&&a[j - d] > temp; j -= d)
                a[j] = a[j - d];
            a[j] = temp;
        }
}
/* 
 * 選擇排序(不穩定 應該是最差的排序算法了吧) 
 * 最好 最壞  平均 時間復雜度都是O(n^2) 
 */
void  selection_sort(int a[],int n) {
    for (int i = 0; i < n-1; i++) {
        int min = i;
        for (int j = i + 1; j < n; j++) {
            if (a[j] < a[min]) {
                min = j;
            }
        }
        if (min != i) {
            int temp = a[min];
            a[min] = a[i];
            a[i] = temp;
        }
    }
}
/* 
 * 歸並排序(遞歸版本) 在外排序中使用較多
 * 1.時間復雜度 最好  最壞 平均 都是O(n*log n).
 * 2.空間復雜度 是 O(n). 
 */
void merge1(int a[],int temp[],int left,int right,int rightEnd) {
    int l = left;
    int leftEnd = right -1;
    int r = right;
    int index = rightEnd - left + 1;
    int x = left;
    while (l <= leftEnd && r <= rightEnd) {
        if (a[l] <= a[r]) {
            temp[x++] = a[l++];
        }
        else
            temp[x++] = a[r++];
    }
    while (l <= leftEnd)
        temp[x++] = a[l++];
    while (r <= rightEnd)
        temp[x++] = a[r++];
    for (int i=rightEnd; index > 0; index--,i--)
        a[i] = temp[i];
}

void mSort1(int a[],int temp[],int left,int right) {
    if (left < right) {
        int mid = (left + right) / 2;
        mSort1(a, temp, left, mid);
        mSort1(a, temp, mid + 1, right);
        merge1(a, temp, left, mid + 1, right);
    }

}
void merge_sort1(int a[],int n) { 
    int* temp = (int*)malloc(sizeof(int)*n);
    if (temp != NULL ) {
        mSort1(a, temp, 0, n-1);
        free(temp);
    }
    else {
        cout << "內存不足" << endl;
    }
}
/*
 * 歸並排序循環版本
 * 1. 時間復雜度  最好 最壞 平均 都為O(n * log n)
 * 2. 空間復雜度O(n)
*/
void merge2(int a[], int temp[], int left, int right, int rightEnd) {
    int l = left;
    int leftEnd = right - 1;
    int r = right;
    int index = rightEnd - left + 1;
    int x = left;
    while (l <= leftEnd && r <= rightEnd) {
        if (a[l] <= a[r]) {
            temp[x++] = a[l++];
        }
        else
            temp[x++] = a[r++];
    }
    while (l <= leftEnd)
        temp[x++] = a[l++];
    while (r <= rightEnd)
        temp[x++] = a[r++];
}

void mergePass(int a[],int temp[],int n,int length) {
    int i;
    for (i = 0; i + 2 * length <= n; i += 2 * length) {
        merge2(a, temp, i, i + length, i + 2 * length - 1);
    }
    if (i + length < n) {
        merge2(a, temp, i, i + length, n - 1);
    }
    else
        for (int j = i; j < n; j++)
            temp[j] = a[j];
}
void merge_sort2(int a[],int n) {
    int* temp = (int*)malloc(n * sizeof(int));
    if (temp != NULL) {
        int length = 1;
        while (length < n) {
            mergePass(a, temp, n, length);
            length *= 2;
            mergePass(temp, a, n, length);
            length *= 2;
        }
        free(temp);
    }
    else {
        cout << "內存不足" << endl;
    }
}
/*
 * 堆排序(不穩定) 
 * 最好 最壞 平均 時間復雜度 O(n*log n).
 */
void adjust(int a[],int i, int n) { 
    int parent, child;
    int temp = a[i];
    for (parent = i; parent * 2 < n - 1; parent = child) {
        child = parent * 2 + 1; /* 先指向左孩子 */
        if (child != n - 1 && a[child+1] > a[child]) {
            child++; /* 右孩子較大則指向右孩子 */
        }
        if (temp >= a[child])
            break;
        else
            a[parent] = a[child];
    }
    a[parent] = temp;
}
void heap_sort(int a[], int n) {
    for (int i = (n-1) / 2; i >= 0; i--)
        adjust(a,i,n);  /* 構建最大堆 */
    for (int i = n - 1; i > 0; i--) {
        int temp = a[i];
        a[i] = a[0];
        a[0] = temp;
        adjust(a, 0, i);
    }
}
/*
 * 快速排序 (不穩定)
 * 1.最壞情況和主元的選取有一定的關系 如果選首位為主元O(n^2) 
 * 2.最好 平均 O(n * log n)  
 * 3.當待排元素較少時  快排效率會急速下降  此時可采用插入排序
 */
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
int median3(int a[],int left,int right) {
    int center = (left + right) / 2;
    if (a[left] > a[center]) {
        swap(&a[left], &a[center]);
    }
    if (a[left] > a[right]) {
        swap(&a[left], &a[right]);
    }
    if (a[center] > a[right]) {
        swap(&a[center], &a[right]);
    }
    swap(&a[center], &a[right-1]); /* 將基准放在數組右端 */
    return a[right-1];
}
void qSort(int a[],int left,int right) {
    int cutoff = 100;
    int low, high, pivot;
    if (right - left >= cutoff) {
        pivot = median3(a, left, right);
        low = left;
        high = right - 1;
        while (1) {
            while (a[++low] < pivot);
            while (a[--high] > pivot);
            if (low < high)
                swap(&a[low], &a[high]);
            else
                break;
        }
        swap(&a[low], &a[right - 1]);
        qSort(a, left, low - 1);
        qSort(a, low + 1, right);
    }
    else
        insertion_sort(a+left,right-left+1);
}

void quick_sort(int a[],int n) {
    qSort(a,0,n-1);
}

 

算法/時間復雜度

10^3的隨機整數

10^4個隨機整數

10^5個隨機整數

10^5個順序整數

10^5個逆序整數

10^5個基本有序的整數

10^5個隨機正整數,每個數不超過1000

冒泡排序

4ms

228ms

>10s

88ms

>10s

650ms

>10s

插入排序

3ms

35ms

4784ms

82ms

9206ms

115ms

4499ms

選擇排序

5ms

332ms

>10s

>10s

>10s

>10s

>10s

歸並排序(遞歸版本)

4ms

12ms

131ms

82ms

127ms

83ms

75ms

堆排序

3ms

10ms

103ms

89ms

102ms

126ms

94ms

希爾排序

3ms

25ms

128ms

119ms

125ms

117ms

116ms

歸並排序(循環版本)

3ms

24ms

125ms

78ms

99ms

77ms

93ms

快速排序(pivot取中位數)

3ms

10ms

122ms

76ms

112ms

76ms

69ms

基數排序

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM