前言:排序的定义
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序,若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。内部排序的过程是一个逐步扩大记录的有序序列长度的过程
各种排序的时间复杂度
排序方法 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
---|
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
简单选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 稳定 |
直接插入排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(nlogn)~O(n^2) | O(n^1.3) | O(n^2) | O(1) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(n^2) | O(logn)~O(n) | 不稳定 |
各种排序的时间测试
排序方法 | 5万数据 | 50万数据 | 100 万数据 |
---|
优化冒泡排序 | 8.183984s | 太慢 | 太慢 |
简单选择排序 | 2.682234s | 太慢 | 太慢 |
直接插入排序 | 1.496184s | 太慢 | 太慢 |
希尔插入排序 | 0.008725s | 0.120478s | 0.256040s |
顶堆选择排序 | 0.007705s | 0.097579s | 0.204354s |
递归归并排序 | 0.006827s | 栈溢出 | 栈溢出 |
非递归并排序 | 0.006666s | 0.080683s | 0.148987s |
普通快速排序 | 0.007767s | 0.086778s | 0.188957s |
优化快速排序 | 0.007215s | 0.087385s | 0.182627s |
冒泡排序
- 冒泡排序,通过两两比较相邻记录,依次浮出最小或者最大值
- 优化方案:增加标志位判断是否已经有序,而不继续冒泡
实现代码
int BubbleSort1(SqList * L)
{
int i, j;
int flag = 1;
for (i = 0; i < MAXSIZE - 1 && flag; i++) {
flag = 0;
for (j = MAXSIZE - 1; j > i; j--) {
if (L->r[j] < L->r[j - 1]) {
swap(L, j, j - 1);
flag = 1;
}
}
}
return 0;
}
简单选择排序
- 简单选择排序,通过n-i次关键字的比较,从n-i+1个记录中选出关键字最小的记录,然后与第i的位置替换
- 通俗的讲就是,循环比较出后面最小的值依次放在前面去,就是从小到大了
实现代码
int SelectSort(SqList * L)
{
int i, j, min;
for (i = 0; i < MAXSIZE - 1; i++) {
min = i;
for (j = i + 1; j < MAXSIZE; j++) {
if (L->r[min] > L->r[j]) {
min = j;
}
}
if (i != min) {
swap(L, i, min);
}
}
return 0;
}
直接插入排序
- 直接插入排序,从第二个数开始循环,将当前数拿出来,依次将左边大于当前值的数向后移动一位,直到不大于当前值停止,然后将当前值插入空档
实现代码
int InsertSort(SqList * L)
{
int i, j, flag;
for (i = 1; i < MAXSIZE; i++) {
if (L->r[i] < L->r[i - 1]) {
flag = L->r[i];
for (j = i - 1; j >= 0 && L->r[j] > flag; j--) {
L->r[j + 1] = L->r[j];
}
L->r[j + 1] = flag;
}
}
return 0;
}
希尔排序
- 希尔排序,直接插入排序的高效版,先使整个序列基本有序,然后再进行插入排序,大突破,打破O[n^2]
- 使基本有序的方法就是把顺序循环变成跳跃方式的间隔循环,例如a[i]和a[i+1]比较变成a[i]和a[i+4]比较,然后慢慢缩小a[i]和a[i+2]比较,最后为1的时候就是插入排序了,这个过程在逐渐把排序变成基本有序
实现代码
int ShellSort(SqList * L)
{
int i, j, flag;
int increment = MAXSIZE;
while (increment > 1) {
increment = increment / 3 + 1;
for (i = increment; i < MAXSIZE; i++) {
if (L->r[i] < L->r[i - increment]) {
flag = L->r[i];
for (j = i - increment; j >= 0 && L->r[j] > flag; j -= increment) {
L->r[j + increment] = L->r[j];
}
L->r[j + increment] = flag;
}
}
}
return 0;
}
堆排序,归并排序
- 不做仔细讲解,这两个略麻烦
- 堆排序利用二叉树构建大顶堆取根节点
- 归并排序采用拆分比较,再归并的方式实现排序
实现代码
快速排序
- 王者段位的排序,冒泡排序的升级版
- 中心思想就是递归不断的把小的放左边,大的放右边,最后实现排序
实现代码
int QuickSort(SqList * L)
{
QSort(L, 0, MAXSIZE - 1);
return 0;
}
int QSort(SqList * L, int low, int high)
{
int pivot;
if (low < high) {
pivot = Partition(L, low, high);
QSort(L, low, pivot - 1);
QSort(L, pivot + 1, high);
}
return 0;
}
int Partition(SqList * L, int low, int high)
{
int pivotkey;
pivotkey = L->r[low];
while (low < high) {
while (low < high && L->r[high] >= pivotkey) {
high--;
}
swap(L, low, high);
while (low < high && L->r[low] <= pivotkey) {
low++;
}
swap(L, low, high);
}
return low;
}
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#define MAXSIZE 50000
#define IsPrintf 0
typedef struct {
int r[MAXSIZE + 1];
} SqList;
void Init(SqList * L);
void Print(SqList * L);
void swap(SqList * L, int i, int j);
double GetTime(void);
int BubbleSort0(SqList * L);
int BubbleSort(SqList * L);
int BubbleSort1(SqList * L);
int SelectSort(SqList * L);
int InsertSort(SqList * L);
int ShellSort(SqList * L);
int HeapAdjust(SqList * L, int s, int m);
int HeapSort(SqList * L);
int MSort(int SR[], int TR1[], int s, int t);
int Merge(int SR[], int TR[], int i, int m, int n);
int MergeSort(SqList * L);
int MergePass(int SR[], int TR[], int s, int n);
int MergeSort1(SqList * L);
int Partition(SqList * L, int low, int high);
int QSort(SqList * L, int low, int high);
int QuickSort(SqList * L);
int Partition1(SqList * L, int low, int high);
int QSort1(SqList * L, int low, int high);
int QuickSort1(SqList * L);
int main(void)
{
double start, end;
SqList H;
SqList L;
printf("数据量: %d\n\n", MAXSIZE);
Init(&H);
if (MAXSIZE <= 50000) {
L = H;
start = GetTime();
BubbleSort1(&L);
end = GetTime();
printf("优化冒泡排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
L = H;
start = GetTime();
SelectSort(&L);
end = GetTime();
printf("简单选择排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
L = H;
start = GetTime();
InsertSort(&L);
end = GetTime();
printf("直接插入排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
}
L = H;
start = GetTime();
ShellSort(&L);
end = GetTime();
printf("希尔插入排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
L = H;
start = GetTime();
HeapSort(&L);
end = GetTime();
printf("顶堆选择排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
if (MAXSIZE <= 100000) {
L = H;
start = GetTime();
MergeSort(&L);
end = GetTime();
printf("递归归并排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
}
L = H;
start = GetTime();
MergeSort1(&L);
end = GetTime();
printf("非递归并排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
L = H;
start = GetTime();
QuickSort(&L);
end = GetTime();
printf("普通快速排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
L = H;
start = GetTime();
QuickSort1(&L);
end = GetTime();
printf("优化快速排序: \n");
Print(&L);
printf("运行时间: %lfs\n\n", end - start);
return 0;
}
void Print(SqList * L)
{
if (IsPrintf) {
int i;
for (i = 0; i < MAXSIZE; i++) {
printf("%d ", L->r[i]);
}
printf("\n");
}
}
void Init(SqList * L)
{
int i;
srand((unsigned)time(NULL));
for (i = 0; i < MAXSIZE; i++) {
L->r[i] = rand() % MAXSIZE;
}
}
void swap(SqList * L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
int BubbleSort1(SqList * L)
{
int i, j;
int flag = 1;
for (i = 0; i < MAXSIZE - 1 && flag; i++) {
flag = 0;
for (j = MAXSIZE - 1; j > i; j--) {
if (L->r[j] < L->r[j - 1]) {
swap(L, j, j - 1);
flag = 1;
}
}
}
return 0;
}
int BubbleSort(SqList * L)
{
int i, j;
for (i = 0; i < MAXSIZE - 1; i++) {
for (j = MAXSIZE - 1; j > i; j--) {
if (L->r[j] < L->r[j - 1]) {
swap(L, j, j - 1);
}
}
}
return 0;
}
int BubbleSort0(SqList * L)
{
int i, j;
for (i = 0; i < MAXSIZE - 1; i++) {
for (j = i + 1; j < MAXSIZE; j++) {
if (L->r[i] > L->r[j]) {
swap(L, i, j);
}
}
}
return 0;
}
int InsertSort(SqList * L)
{
int i, j, flag;
for (i = 1; i < MAXSIZE; i++) {
if (L->r[i] < L->r[i - 1]) {
flag = L->r[i];
for (j = i - 1; j >= 0 && L->r[j] > flag; j--) {
L->r[j + 1] = L->r[j];
}
L->r[j + 1] = flag;
}
}
return 0;
}
int ShellSort(SqList * L)
{
int i, j, flag;
int increment = MAXSIZE;
while (increment > 1) {
increment = increment / 3 + 1;
for (i = increment; i < MAXSIZE; i++) {
if (L->r[i] < L->r[i - increment]) {
flag = L->r[i];
for (j = i - increment; j >= 0 && L->r[j] > flag; j -= increment) {
L->r[j + increment] = L->r[j];
}
L->r[j + increment] = flag;
}
}
}
return 0;
}
int SelectSort(SqList * L)
{
int i, j, min;
for (i = 0; i < MAXSIZE - 1; i++) {
min = i;
for (j = i + 1; j < MAXSIZE; j++) {
if (L->r[min] > L->r[j]) {
min = j;
}
}
if (i != min) {
swap(L, i, min);
}
}
return 0;
}
double GetTime(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + (double)tv.tv_usec / 1000000;
}
int HeapAdjust(SqList * L, int s, int m)
{
int temp, j;
temp = L->r[s];
for (j = 2 * s; j <= m; j *= 2) {
if (j < m && L->r[j] < L->r[j + 1]) {
++j;
}
if (temp >= L->r[j]) {
break;
}
L->r[s] = L->r[j];
s = j;
}
L->r[s] = temp;
return 0;
}
int HeapSort(SqList * L)
{
int i;
for (i = (MAXSIZE - 1) / 2; i >= 0; i--) {
HeapAdjust(L, i, MAXSIZE - 1);
}
for (i = MAXSIZE - 1; i >= 1; i--) {
swap(L, 0, i);
HeapAdjust(L, 0, i - 1);
}
return 0;
}
int MergeSort1(SqList * L)
{
int *TR = (int *)malloc(MAXSIZE * sizeof(int));
int k = 1;
while (k < MAXSIZE) {
MergePass(L->r, TR, k, MAXSIZE);
k = 2 * k;
MergePass(TR, L->r, k, MAXSIZE);
k = 2 * k;
}
return 0;
}
int MergePass(int SR[], int TR[], int s, int n)
{
int i = 1;
int j;
while (i <= n - 2 * s + 1) {
Merge(SR, TR, i - 1, i + s - 1 - 1, i + 2 * s - 1 - 1);
i = i + 2 * s;
}
if (i < n - s + 1) {
Merge(SR, TR, i - 1, i + s - 1 - 1, n - 1);
} else {
for (j = i; j <= n; j++) {
TR[j - 1] = SR[j - 1];
}
}
return 0;
}
int MergeSort(SqList * L)
{
MSort(L->r, L->r, 0, MAXSIZE - 1);
return 0;
}
int MSort(int SR[], int TR1[], int s, int t)
{
int m;
int TR2[MAXSIZE + 1];
if (s == t) {
TR1[s] = SR[s];
} else {
m = (s + t) / 2;
MSort(SR, TR2, s, m);
MSort(SR, TR2, m + 1, t);
Merge(TR2, TR1, s, m, t);
}
return 0;
}
int Merge(int SR[], int TR[], int i, int m, int n)
{
int j, k, l;
for (j = m + 1, k = i; i <= m && j <= n; k++) {
if (SR[i] < SR[j]) {
TR[k] = SR[i++];
} else {
TR[k] = SR[j++];
}
}
if (i <= m) {
for (l = 0; l <= m - i; l++) {
TR[k + l] = SR[i + l];
}
}
if (i <= n) {
for (l = 0; l <= n - j; l++) {
TR[k + l] = SR[j + l];
}
}
return 0;
}
int Partition(SqList * L, int low, int high)
{
int pivotkey;
pivotkey = L->r[low];
while (low < high) {
while (low < high && L->r[high] >= pivotkey) {
high--;
}
swap(L, low, high);
while (low < high && L->r[low] <= pivotkey) {
low++;
}
swap(L, low, high);
}
return low;
}
int Partition1(SqList * L, int low, int high)
{
int pivotkey;
int m = low + (high - low) / 2;
if (L->r[low] > L->r[high]) {
swap(L, low, high);
}
if (L->r[m] > L->r[high]) {
swap(L, high, m);
}
if (L->r[m] > L->r[low]) {
swap(L, m, low);
}
pivotkey = L->r[low];
L->r[MAXSIZE] = pivotkey;
while (low < high) {
while (low < high && L->r[high] >= pivotkey) {
high--;
}
L->r[low] = L->r[high];
while (low < high && L->r[low] <= pivotkey) {
low++;
}
L->r[high] = L->r[low];
}
L->r[low] = L->r[MAXSIZE];
return low;
}
int QSort(SqList * L, int low, int high)
{
int pivot;
if (low < high) {
pivot = Partition(L, low, high);
QSort(L, low, pivot - 1);
QSort(L, pivot + 1, high);
}
return 0;
}
int QSort1(SqList * L, int low, int high)
{
int pivot;
if (low < high) {
pivot = Partition1(L, low, high);
QSort(L, low, pivot - 1);
QSort(L, pivot + 1, high);
}
return 0;
}
int QuickSort(SqList * L)
{
QSort(L, 0, MAXSIZE - 1);
return 0;
}
int QuickSort1(SqList * L)
{
QSort1(L, 0, MAXSIZE - 1);
return 0;
}