PTA 求自定類型元素序列的中位數 (25分) 【排序】

6-11 求自定類型元素序列的中位數 (25分)

本題要求實現一個函數,求N個集合元素A[]的中位數,即序列中⌊(N+1)/2⌋的元素。其中集合元素的類型爲自定義的ElementType
函數接口定義:

ElementType Median( ElementType A[], int N );

其中給定集合元素存放在數組A[]中,正整數N是數組元素個數。該函數須返回N個A[]元素的中位數,其值也必須是ElementType類型。
裁判測試程序樣例:

#include <stdio.h>

#define MAXN 10
typedef float ElementType;

ElementType Median( ElementType A[], int N );

int main ()
{
    ElementType A[MAXN];
    int N, i;

    scanf("%d", &N);
    for ( i=0; i<N; i++ )
        scanf("%f", &A[i]);
    printf("%.2f\n", Median(A, N));

    return 0;
}

/* 你的代碼將被嵌在這裏 */
  • 輸入樣例:
    3
    12.3 34 -5
    
  • 輸出樣例:
    12.30
    

思路:我試了很多種排序方法。而且也有疑惑,看其他人做的題,都是取序列中第⌊N/2+1⌋大的元素,而非序列中⌊(N+1)/2⌋的元素,難道題目改錯了嗎?

在C中,序列從小到大排序,⌊N/2+1⌋大對應位序爲N/2的元素,⌊(N+1)/2⌋對應(N+1)/2-1位序的元素,兩者幾乎總是不同,N爲奇數時相等,偶數時N/2 > (N+1)/2-1結果 大1。

從後面的實驗來看,符合第幾大的應該是(N+1)/2-1。

// 最初級的冒泡排序
void SimpleSort(ElementType A[], int N) {
    for (int i = 0; i < N - 1; ++i) {
        for (int j = i + 1; j < N; ++j) {
            if (A[j] < A[i]) { // 從小到大 N/2
                ElementType t = A[j]; 
                A[j] = A[i];
                A[i] = t;
            }
        }
    }
}
ElementType Median(ElementType A[], int N) {
    SimpleSort(A, N); 
    return A[N/2];
}

在這裏插入圖片描述改爲從小到大 (N+1)/2-1:
在這裏插入圖片描述
因此,N/2 從大到小,偶數個時1,4測試點出現錯誤,從小到大則不出。
而(N+1)/2-1則相反,從小到大,偶數個時1,4測試點出現錯誤,從大到小則不出。
即偶數個時,該結果位於從大到小的中間偏左,從小到大的中間偏右。


// 冒泡排序
void BubbleSort(ElementType A[], int N) {
    for (int i = 0; i < N - 1; ++i) {
        for (int j = N - 1; j > i; --j) {
            if (A[j] > A[j - 1]) { // 從大到小
                ElementType t = A[j]; 
                A[j] = A[j - 1];
                A[j - 1] = t;
            }
        }
    }
}
ElementType Median(ElementType A[], int N) {
    BubbleSort(A, N);  
    return A[N / 2];
}

在這裏插入圖片描述
改爲(N+1)/2-1後:
在這裏插入圖片描述


// 插入排序
void InsertionSort(ElementType* A, int N) {
    for (int i = 1; i < N; ++i) {
        ElementType temp = A[i];
        int j;
        for (j = i; j > 0 && A[j - 1] > temp; --j) A[j] = A[j - 1]; // 從小到大
        A[j] = temp;
    }
} 
ElementType Median(ElementType A[], int N) {
    InsertionSort(A, N); 
    return A[N / 2];
}

在這裏插入圖片描述

void InsertionSort(ElementType* A, int N) {
    for (int i = 1; i < N; ++i) {
        ElementType temp = A[i];
        int j;
        for (j = i; j > 0 && A[j - 1] < temp; --j) A[j] = A[j - 1]; // 從大到小
        A[j] = temp;
    }
}  
int cmp(const void *a, const void *b) {
    return (*(ElementType*)b - *(ElementType*)a);
}
ElementType Median(ElementType A[], int N) {
    InsertionSort(A, N);  
    return A[(N + 1) / 2 - 1];
}

在這裏插入圖片描述


// 手寫快排
int Partition(ElementType* A, int lo, int hi) {
	if (lo >= hi) return lo;  // 只有1個
	ElementType t = A[lo];
	while (lo < hi) { // 夾出一個位置
		while (lo < hi && A[hi] <= t) --hi; // 從大到小排序
		A[lo] = A[hi];
		while (lo < hi && A[lo] > t) ++lo; // 從大到小排序
		A[hi] = A[lo];
	}
	A[lo] = t;  // 從while中退出時,lo等於hi,lo的元素已經使用過了 
    return lo;
}
void QSort(ElementType* A, int lo, int hi) {
	if (lo < hi) {
		int mid = Partition(A, lo, hi);
		QSort(A, lo, mid);
		QSort(A, mid + 1, hi);
	}
}
void QuickSort(ElementType* A, int N) {
	QSort(A, 0, N - 1);
}
ElementType Median(ElementType A[], int N) { 
    QuickSort(A, N); 
    return A[(N + 1) / 2 - 1]; 
} 

在這裏插入圖片描述

// 引用C庫裏的快排
// 不知道爲什麼這裏也會錯,不能理解
#include <stdlib.h>
int cmp(const void *a, const void *b) {
	return (*(ElementType*)b - *(ElementType*)a); // 從大到小
}
ElementType Median(ElementType A[], int N) {  
    qsort(A, N, sizeof(ElementType), cmp); // (N + 1) / 2 - 1
    return A[(N + 1) / 2 - 1];
}

在這裏插入圖片描述

// 引用C庫裏的快排
// 不知道爲什麼這裏也會錯,不能理解
#include <stdlib.h>
int cmp(const void *a, const void *b) {
    return (*(ElementType*)a - *(ElementType*)b); // 從小到大
}
ElementType Median(ElementType A[], int N) {  
    qsort(A, N, sizeof(ElementType), cmp); // (N + 1) / 2 - 1
    return A[N / 2];
}

在這裏插入圖片描述

真正的答案是用希爾排序,堆排序沒試過:

ElementType Median(ElementType A[], int N) { 
    // gap是每次排序分組的間隔,每次間隔縮小兩倍(其他縮小辦法也可以) 
    for (int gap = N / 2; gap > 0; gap /= 2) { 
        for (int i = gap; i < N; ++i) { // 相當於在同一組內採用直接插入排序
            int j = i;
            ElementType t = A[i];
            for (; j >= gap && t > A[j - gap]; j -= gap) // 從大到小
                A[j] = A[j - gap];
            A[j] = t;
        }
    }
    return A[(N + 1) / 2 - 1];
}

在這裏插入圖片描述

ElementType Median(ElementType A[], int N) { 
    for (int gap = N / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < N; ++i) {
            int j = i - gap;
            ElementType t = A[i];
            for (; j >= 0 && t < A[j]; j -= gap) // 從小到大
                A[j + gap] = A[j];
            A[j + gap] = t;
        }
    }
    return A[N / 2];
}

在這裏插入圖片描述

發佈了166 篇原創文章 · 獲贊 59 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章