本题要求实现一个函数,求N个集合元素A[ ]的中位数,即序列中第⌊N/2+1⌋大的元素。因为本题当N很大时,一些排序算法的运行时间过长,导致超时,所以我实验了三种算法包含:选择排序、直接插入排序、希尔排序。最终选择:希尔排序。
1. 选择排序 -> O(n^2)
/*
*-----------选择排序---------
*基本思想:假设长度为N的数组A,要按照从小到大排序,
*那么先从N个数字中找到最小值min1,
*如果最小值min1的位置不在数组的最左端(也就是min1不等于A[0]),
*则将最小值min1和A[0]交换,接着在剩下的n-1个数字中找到最小值min2,
*如果最小值min2不等于A[1],则交换这两个数字,
*依次类推,直到数组A有序排列。
*--->算法的时间复杂度为O(n^2)<---
*/
ElementType Median(ElementType A[], int N)
{
for (int i = 0; i < N; i++)
{
int index = i; //标记待排序列最左端
for (int j = i+1; j < N; j++)
{
if (A[j] < A[index])
{
index = j; //遍历待排序列最小值,并标记位置
}
}
if (index == i) //如果待排序列最小值为左端点,继续循环
continue;
else
{
float temp; //,否则,将最小值交换至最左端
temp = A[index];
A[index] = A[i];
A[i] = temp;
}
}
return A[N/2];
}
2. 直接插入排序 -> O(n^2)
/*
*--------直接插入排序---------
*基本思想:设数组为a[0…n-1]。
*1.初始时,a[0]自成1个有序区,无序区为a[1..n-1],令i从1开始计数。
*2.将a[i]并入当前的有序区a[0…i-1]中形成a[0…i]的有序区间。
*3.i++并重复第二步直到i==n-1。排序完成。
*--->算法的时间复杂度为O(n^2)<---
*/
ElementType Median(ElementType A[], int N)
{
int i, j;
for (i = 1; i < N; i++)
if (A[i] < A[i - 1])
{
float temp = A[i];
for (j = i - 1; j >= 0 && A[j] > temp; j--) //定插入位置,并元素后移
A[j + 1] = A[j];
A[j + 1] = temp; //即A[j]=3 < A[i]=4时。如:3 5 4。4插入3和5之间。
}
return A[N/2];
}
3. 希尔排序 -> O(n^(1.3~2))
/*
*-----------希尔排序-----------
*基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)
*分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)
*再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),
*效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
*--->算法的时间复杂度为O(n^(1.3—2))<---
*/
ElementType Median(ElementType A[], int N)
{
int j, gap; //gap是步长,常规i++步长为1.
for (gap = N / 2; gap > 0; gap /= 2)
{
for (j = gap; j < N; j++) //从数组第gap个元素开始
{
if (A[j] < A[j - gap]) //每个元素与自己组内的数据进行直接插入排序
{
float temp = A[j];
int k = j - gap;
while (k >= 0 && A[k] > temp) //定插入位置,并且数组元素后移
{
A[k + gap] = A[k];
k -= gap;
}
A[k + gap] = temp; //元素插入
}
}
}
return A[N/2];
}
4. 参考来源
选择排序:https://blog.csdn.net/weixin_43728713/article/details/89145655
直接插入排序:https://blog.csdn.net/morewindows/article/details/6665714
希尔排序:https://blog.csdn.net/MoreWindows/article/details/6668714