函数声明
#include <iostream>
#include <cstdlib>
#define random(x) (rand()%x) // 产生0~x的随机数,用于打乱数组
using namespace std;
const int length = 10; // 数组大小
typedef int T;
static T spt[length];
bool less1(T v, T w); // 比较两元素大小,如果v<w,返回true,反之返回false
void exch(T* a, int i, int j); // 交换数组中两个元素
void show(T* a, int l); // 打印数组
bool isSorted(T* a, int l); // 判断数组元素是否有序
void selectSort(T* a, int l); // 选择排序
void insertSort(T* a, int l); // 插入排序
void shellSort(T* a, int l); // 希尔排序
void mergeSort(T* a, int l); // 归并排序
/* merge函数将子数组a[low...mid]和a[mid+1...high]归并成
一个有序的数组,并将结果存放在a[low...high]中 */
void merge(T* a, int low, int mid, int high);
void mergeSort(T* a, int low, int high);
void shuffle(T* a, int l); // 打乱数组
int partition(T* a, int low, int high); // 快速排序的切分
void quickSort_S(T* a, int low, int high);// 快速排序的内部行为
void quickSort(T* a, int l); // 快速排序
辅助函数如下:(函数的功能如其名字所示)
bool less1(T v, T w) {
return v < w;
}
void exch(T* a, int i, int j) {
T t = *(a+i);
*(a+i) = *(a+j);
*(a+j) = t;
}
void show(T* a, int l) {
for (int i = 0; i < l; i++)
cout << *(a+i) << " ";
cout << endl;
}
bool isSorted(T* a, int l) {
for (int i = 0; i < l; i++)
if (less1(*(a+i), *(a+i-1))) return false;
return true;
}
选择排序的算法思想是这样的:
首先,找到数组中最小的那个元素,然后将它和数组的第一个元素交换位置。接着再在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置,如此往复直到将整个数组排序。
void selectSort(T* a, int l) {
for (int i = 0; i < l; i++) {
// 将a[]按升序排序
int min = i; // 最小元素索引
for (int j = i+1; j < l; j++)
if (less1(*(a+j), *(a+min))) min = j;
exch(a, i, min);
}
}
插入排序:
将每一个元素插入到其他已经有序的元素中的适当位置,为了要给插入的元素腾出空间,需要将其余所有元素在插入之前都向右移动一位。
(对于随机排列的长度为N且主键不重复的数组,平均情况下插入排序需要N2/4次比较以及N2/4次交换。最坏情况下需要N2/2次比较和N2/2次交换,最好情况下需要N-1次比较和0次交换)
void insertSort(T* a, int l) {
// 将a[]按升序排列
for (int i = 0; i < l; i++) {
// 将a[i]插入到a[i-1],a[i-2],a[i-3]...之中
for (int j = i; j > 0 && less1(*(a+j), *(a+j-1));j--)
exch(a, j, j-1);
}
}
希尔排序:
希尔排序是一种基于插入排序的排序算法。即交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。
希尔排序的思想是使数组中任意间隔为h的元素都是有序的,这样的数组被称为h有序数组。在进行排序时,如果h很大,就能将元素移动到很远的地方。
下面的这个算法使用了1/2(3h-1),从N/3开始递减至1
void shellSort(T* a, int l) {
// 将a[]按升序排列
int h = 1;
while (h < l/3) h = 3*h + 1; // 1, 4, 13, 40, 121, 364, 1093...
while (h >= 1) {
// 将数组变为h有序
for (int i = h; i < l; i++) {
for (int j = i; j >= h && less1(*(a+j), *(a+j-h)); j -= h)
exch(a, j, j-h);
}
h = h/3;
}
}
归并排序:
递归地将它分成两半分别排序,然后将结果归并起来。
归并排序地性质是能够保证将任意长度为N地数组排序所需时间为NlogN(以2为底),它的主要缺点是它所需的额外空间和N成正比
void merge(T* a, int low, int mid, int high) {
// 将数组a[low...mid] 和 a[mid+1...high]归并
int i = low, j = mid+1;
for (int k = low; k <= high; k++)
spt[k] = *(a+k); // 将a[low...high]复制到spt中
for (int k = low; k <= high; k++) // 归并回到a[low...high]
if (i > mid) *(a+k) = spt[j++];
else if (j > high) *(a+k) = spt[i++];
else if (less1(spt[j], spt[i])) *(a+k) = spt[j++];
else *(a+k) = spt[i++];
}
void mergeSort(T* a, int low, int high) {
// 将数组a[low...high]排序
if (high <= low) return;
int mid = low + (high - low) / 2;
mergeSort(a, low, mid);
mergeSort(a, mid+1, high);
merge(a, low, mid, high);
}
void mergeSort(T* a, int l) {
mergeSort(a, 0, l-1);
}
快速排序:
快速排序是一种分治的排序算法。它将一个数组分成两个子数组,将两部分独立地排序。递归调用发生在处理整个数组之后,因此和归并排序是互补的。在快速排序中,切分(partition)的位置取决于数组的内容。
void shuffle(T* a, int l) {
for (int i = 0; i < l; i++) {
int local = (int)random(l);
T temp = *(a+i);
*(a+i) = *(a + local);
*(a+local) = temp;
}
}
int partition(T* a, int low, int high) {
int i = low, j = high+1;
T v = *(a+low);
while (1) {
// 扫描左右,检查扫描是否结束并交换元素
while (less1(*(a+(++i)), v)) if (i == high) break;
while (less1(v, *(a+(--j)))) if (j == low) break;
if (i >= j) break;
exch(a, i, j);
}
exch(a, low, j); // 将v = a[j]放入正确的位置
return j; // a[low...j-1] <= a[j] <= a[j+1...high]
}
void quickSort_S(T* a, int low, int high) {
if (high <= low) return;
int j = partition(a, low, high);
quickSort_S(a, low, j-1);
quickSort_S(a, j+1, high);
}
void quickSort(T* a, int l) {
shuffle(a, l);
quickSort_S(a, 0, l-1);
}