目录
1.直接插入排序
2.希尔排序
3.直接选择排序
4.冒泡排序
5.堆排序
6.快速排序(三种方法实现)
法1:挖坑法
法2:前后指针法
法3:左右指针法
7.归并排序
1.递归
2.非递归
8.计数排序
9.检测结果
10.排序速度检测
1.快速排序不用小区间优化
2.快速排序用小区间优化
结论
代码
未完待续(以后还会加排序)!
本次排序所使用的头文件有:
#include
#include
#include
#include
//直接插入排序---"摸牌"---升序
//最坏结果(逆序)---O(N^2)
//最好结果(顺序有序)---O(N)
//算是在O(N^2)中最好的
void InsertSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
//有序数组(数组[a, end]有序)的末尾下标---有序牌的最后一张
int end = i;
//要插入的数---要摸的牌
int tmp = a[end + 1];
while (end >= 0)
{
//比较看是否要插入牌
if (a[end] > tmp)
{
//往后挪
a[end + 1] = a[end];
//向前继续比较
end--;
}
else//符合
{
break;
}
}
//插入数据(牌)
a[end + 1] = tmp;
}
}
//希尔排序---O(N^1.3)
//1.gap > 1 进行gap组间隔为gap的序排序
//2.gap == 1 进行直接插入排序
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
//确保gap最后为1(进行直接插入排序)
gap = gap / 3 + 1;
//多组并排
for (int i = 0; i < n - gap; i++)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
//升序
if (a[end] > tmp)
{
//往后间隔gap处挪
a[end + gap] = a[end];
//往前间隔gap处找
end -= gap;
}
else
{
break;
}
}
//插入
a[end + gap] = tmp;
}
}
}
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
//直接选择排序---O(N^2)
void SelectSort(int* a, int n)
{
int begin = 0, end = n - 1;
while (begin < end)
{
int maxi = begin, mini = begin;
for (int i = begin; i <= end; i++)
{
if (a[i] > a[maxi])
maxi = i;
if (a[i] < a[mini])
mini = i;
}
Swap(&a[begin], &a[mini]);
//防止maxi在begin处被换走
if (maxi == begin)
maxi = mini;
Swap(&a[end], &a[maxi]);
begin++;
end--;
}
}
//冒泡排序---O(N^2)
void BubbleSort(int* a, int n)
{
int flag = 0;
for (int i = 0; i < n; i++)
{
int falg = 1;
for (int j = 0; j < n - 1 - i; j++)
{
if (a[j] > a[j + 1])
{
flag = 0;
int tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
if (flag)
break;
}
}
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
//向下调整--前提左右子树是堆
void AdjustDown(int* a, int n, int parent)
{
//假设最大孩子为左孩子
int child = parent * 2 + 1;
while (child < n)
{
if (child + 1 < n && a[child + 1] > a[child])
{
child++;
}
if (a[parent] < a[child])
{
Swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//堆排序---升序建大堆,反之---O(N*logN)
void HeapSort(int* a, int n)
{
//1.向下调整逆着建堆---叶子节点不用
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(a, n, i);
}
int end = n - 1;
while (end > 0)
{
//2.首尾交换---此法尽量地减少parent与child之间关系的改变
Swap(&a[0], &a[end]);
//3.不包括尾继续向下调整建堆
AdjustDown(a, end, 0);
end--;
}
}
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
//三数先其中(选出前中后中第二大的数,返回其下标)
int GetMIdIndex(int* a, int left, int right)
{
int mid = (left + right) >> 1;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
return mid;
else if (a[left] < a[right])
return right;
else
return left;
}
else
{
if (a[mid] > a[right])
return mid;
else if (a[left] > a[right])
return right;
else
return left;
}
}
//快速排序--挖坑法---O(N*logN)
void QuickSort1(int* a, int left, int right)
{
//跳出条件
if (left >= right)
return;
//三数先其中(选出前中后中第二大的数,返回其下标)---防止出现有序情况时时间复杂度为O(N^2)
int index = GetMIdIndex(a, left, right);
Swap(&a[left], &a[index]);
int begin = left;
int end = right;
int pivot = begin;
int key = a[begin];
while (begin < end)
{
//坑在左,end向左找小填坑
while (begin < end && a[end] >= key)
end--;
//填坑
a[pivot] = a[end];
//形成新坑
pivot = end;
//坑在右,begin向左找大填坑
while (begin < end && a[begin] <= key)
begin++;
//填坑
a[pivot] = a[begin];
//形成新坑
pivot = begin;
}
//相遇处为坑
pivot = begin;
//把a[keyi]填在相遇处的坑上
a[pivot] = key;
//递归
QuickSort1(a, left, pivot - 1);
QuickSort1(a, pivot + 1, right);
//小区间优化---多数据时用可以加快排序速度
//if (pivot - 1 - left > 100)
//{
// QuickSort1(a, left, pivot - 1);
//}
//else
//{
// //用直接插入排序
// InsertSort(a + left, pivot - 1 - left + 1);
//}
//if (right - (pivot + 1) > 100)
//{
// QuickSort1(a, pivot + 1, right);
//}
//else
//{
// //用直接插入排序
// InsertSort(a + pivot + 1, right - (pivot + 1) + 1);
//}
}
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
//三数先其中(选出前中后中第二大的数,返回其下标)
int GetMIdIndex(int* a, int left, int right)
{
int mid = (left + right) >> 1;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
return mid;
else if (a[left] < a[right])
return right;
else
return left;
}
else
{
if (a[mid] > a[right])
return mid;
else if (a[left] > a[right])
return right;
else
return left;
}
}
//快速排序--前后指针法---O(N*logN)
void QuickSort2(int* a, int left, int right)
{
//跳出条件
if (left >= right)
return;
//三数先其中(选出前中后中第二大的数,返回其下标)---防止出现有序情况时时间复杂度为O(N^2)
int index = GetMIdIndex(a, left, right);
Swap(&a[left], &a[index]);
//前指针
int prev = left;
//当前指针
int cur = prev + 1;
int keyi = prev;
while (cur <= right)
{
//找小
if (a[cur] < a[keyi] && ++prev < cur)
Swap(&a[prev], &a[cur]);
cur++;
}
//让a[keyi]去到适合它的位置
//使下标[left, prev - 1]的值小于下标keyi的值,下标[prev + 1, right]的值大于下标keyi的值
Swap(&a[keyi], &a[prev]);
//递归
QuickSort2(a, left, prev - 1);
QuickSort2(a, prev + 1, right);
//小区间优化---多数据时用可以加快排序速度
//if (prev - 1 - left > 100)
//{
// QuickSort2(a, left, prev - 1);
//}
//else
//{
// //用直接插入排序
// InsertSort(a + left, prev - 1 - left + 1);
//}
//if (right - (prev + 1) > 100)
//{
// QuickSort2(a, prev + 1, right);
//}
//else
//{
// //用直接插入排序
// InsertSort(a + prev + 1, right - (prev + 1) + 1);
//}
}
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
//三数先其中(选出前中后中第二大的数,返回其下标)
int GetMIdIndex(int* a, int left, int right)
{
int mid = (left + right) >> 1;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
return mid;
else if (a[left] < a[right])
return right;
else
return left;
}
else
{
if (a[mid] > a[right])
return mid;
else if (a[left] > a[right])
return right;
else
return left;
}
}
//快速排序--左右指针法---O(N*logN)
void QuickSort3(int* a, int left, int right)
{
//跳出条件
if (left >= right)
return;
//三数先其中(选出前中后中第二大的数,返回其下标)---防止出现有序情况时时间复杂度为O(N^2)
int index = GetMIdIndex(a, left, right);
Swap(&a[left], &a[index]);
//前指针
int begin = left;
//当前指针
int end = right;
int keyi = begin;
while (begin < end)
{
//找小
while (begin < end && a[end] >= a[keyi])
end--;
//找大
while (begin < end && a[begin] <= a[keyi])
begin++;
//交换
Swap(&a[begin], &a[end]);
}
//让key去到适合它的位置
//使下标[left, begin - 1]的值小于key,下标[begin + 1 right]的值大于下标key
Swap(&a[keyi], &a[begin]);
//递归
QuickSort3(a, left, begin - 1);
QuickSort3(a, begin + 1, right);
//小区间优化---多数据时用可以加快排序速度
//if (begin - 1 - left > 100)
//{
// QuickSort3(a, left, begin - 1);
//}
//else
//{
// //用直接插入排序
// InsertSort(a + left, begin - 1 - left + 1);
//}
//if (right - (begin + 1) > 100)
//{
// QuickSort3(a, begin + 1, right);
//}
//else
//{ //用直接插入排序
// InsertSort(a + begin + 1, right - (begin + 1) + 1);
//}
}
//归并排序--递归
void _MergeSort(int* a, int left, int right, int* tmp)
{
if (left == right)
return;
int mid = (left + right) / 2;
_MergeSort(a, left, mid, tmp);
_MergeSort(a, mid + 1, right, tmp);
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int k = left;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[k++] = a[begin1++];
}
else
{
tmp[k++] = a[begin2++];
}
}
//补上
while (begin1 <= end1)
{
tmp[k++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[k++] = a[begin2++];
}
//把tmp拷贝回a
memcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));
}
//归并排序--非递归
void MergeSortNonR(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
int gap = 1;
while (gap < n)
{
int k = 0;
for (int i = 0; i < n; i += gap * 2)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + gap*2 - 1;
if (end1 >= n || begin2 >= n)
{
//不归并
break;
}
if (end2 >= n)
{
//修改正确区间,以完成最后的归并
end2 = n - 1;
}
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[k++] = a[begin1++];
}
else
{
tmp[k++] = a[begin2++];
}
}
//补上
while (begin1 <= end1)
{
tmp[k++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[k++] = a[begin2++];
}
//把tmp拷贝回a
memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
}
gap *= 2;
}
free(tmp);
}
//计数排序
//计数排序---时间复杂度最好为O(n)
//缺陷1:只能排序整型
//缺陷2:主要适用于范围居中的数据
void CountSort(int* a, int n)
{
int max = a[0], min = a[0];
for (int i = 0; i < n; i++)
{
if (a[i] > max)
max = a[i];
if (a[i] < min)
min = a[i];
}
int range = max - min + 1;
int* countA = (int*)malloc(sizeof(int) * range);
//全部归零
memset(countA, 0, sizeof(int) * range);
//相对映射---减少内存的开辟
for (int i = 0; i < n; i++)
{
countA[a[i] - min]++;
}
//计数
int k = 0;
for (int i = 0; i < range; i++)
{
while (countA[i]--)
{
a[k++] = i + min;
}
}
free(countA);
}
排序结果正确
代码:
void PrintArray(int* a, int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void TestMergeSort()
{
int a[] = { 2,1,5,3,9,4,6,8,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
MergeSort(a, sz);
PrintArray(a, sz);
}
void TestQuickSort1()
{
int a[] = { 1,5,3,6,9,8,2,4,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
QuickSort1(a, 0, sz - 1);
PrintArray(a, sz);
}
void TestQuickSort2()
{
int a[] = { 1,5,3,6,9,8,2,4,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
QuickSort2(a, 0, sz - 1);
PrintArray(a, sz);
}
void TestQuickSort3()
{
int a[] = { 1,5,3,6,9,8,2,4,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
QuickSort3(a, 0, sz - 1);
PrintArray(a, sz);
}
void TestInsertSort()
{
int a[] = { 1,5,3,6,9,8,2,4,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
InsertSort(a, sz);
PrintArray(a, sz);
}
void TestSellSort()
{
int a[] = { 1,5,3,6,9,8,2,4,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
ShellSort(a, sz);
PrintArray(a, sz);
}
void TestBubbleSort()
{
int a[] = { 1,5,3,6,9,8,2,4,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
BubbleSort(a, sz);
PrintArray(a, sz);
}
void TestSelectSort()
{
int a[] = { 1,5,3,6,9,8,2,4,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
SelectSort(a, sz);
PrintArray(a, sz);
}
void TestHeapSort()
{
int a[] = { 1,5,3,6,9,8,2,4,7 };
int sz = sizeof(a) / sizeof(a[0]);
PrintArray(a, sz);
HeapSort(a, sz);
PrintArray(a, sz);
}
int main()
{
TestInsertSort();
TestSellSort();
TestBubbleSort();
TestSelectSort();
TestHeapSort();
TestQuickSort1();
TestQuickSort2();
TestQuickSort3();
TestMergeSort();
return 0;
}
十万个随机数排序,结果单位为毫秒
结果
结果
1.排序速度第一梯队:计数排序(局限性大)、希尔排序、快速排序、堆排序、归并排序
2.排序速度第二梯队:直接插入排序(在此梯队的大哥)、冒泡排序(小老弟一个)、直接选择排序
3.快排用小区间优化效果并不明显(但当数据量非常大时还是可以加快排序速度的)
void TestOP()
{
srand((unsigned int)time(NULL));
int n = 100000;
int* a1 = (int*)malloc(sizeof(int) * n);
int* a2 = (int*)malloc(sizeof(int) * n);
int* a3 = (int*)malloc(sizeof(int) * n);
int* a4 = (int*)malloc(sizeof(int) * n);
int* a5 = (int*)malloc(sizeof(int) * n);
int* a6 = (int*)malloc(sizeof(int) * n);
int* a7 = (int*)malloc(sizeof(int) * n);
int* a8 = (int*)malloc(sizeof(int) * n);
int* a9 = (int*)malloc(sizeof(int) * n);
int* a10 = (int*)malloc(sizeof(int) * n);
int* a11 = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; i++)
{
a1[i] = rand();
a2[i] = a1[i];
a3[i] = a1[i];
a4[i] = a1[i];
a5[i] = a1[i];
a6[i] = a1[i];
a7[i] = a1[i];
a8[i] = a1[i];
a9[i] = a1[i];
a10[i] = a1[i];
a11[i] = a1[i];
}
int begin1 = clock();//系统启动到这的时间点---毫秒
InsertSort(a1, n);
int end1 = clock();//系统启动到这的时间点---毫秒
int begin2 = clock();
ShellSort(a2, n);
int end2 = clock();
int begin3 = clock();
BubbleSort(a3, n);
int end3 = clock();
int begin4 = clock();
SelectSort(a4, n);
int end4 = clock();
int begin5 = clock();
HeapSort(a5, n);
int end5 = clock();
int begin6 = clock();
QuickSort1(a6, 0, n - 1);
int end6 = clock();
int begin7 = clock();
QuickSort2(a7, 0, n - 1);
int end7 = clock();
int begin8 = clock();
QuickSort3(a8, 0, n - 1);
int end8 = clock();
int begin9 = clock();
MergeSort(a9, n);
int end9 = clock();
int begin10 = clock();
MergeSortNonR(a10, n);
int end10 = clock();
int begin11 = clock();
CountSort(a11, n);
int end11 = clock();
printf("InsertSort: %d\n", end1 - begin1);
printf("ShellSort: %d\n", end2 - begin2);
printf("BubbleSort: %d\n", end3 - begin3);
printf("SelectSort: %d\n", end4 - begin4);
printf("HeapSort: %d\n", end5 - begin5);
printf("QuickSort1: %d\n", end6 - begin6);
printf("QuickSort2: %d\n", end7 - begin7);
printf("QuickSort3: %d\n", end8 - begin8);
printf("MergeSort: %d\n", end9 - begin9);
printf("MergeSortNonR: %d\n", end10 - begin10);
printf("CountSort: %d\n", end11 - begin11);
free(a1);
free(a2);
free(a3);
free(a4);
free(a5);
free(a6);
free(a7);
free(a8);
free(a9);
free(a10);
free(a11);
}
int main()
{
//TestInsertSort();
//TestSellSort();
//TestBubbleSort();
//TestSelectSort();
//TestHeapSort();
//TestQuickSort1();
//TestQuickSort2();
//TestQuickSort3();
//TestMergeSort();
//TestMergeSortNonR();
//TestCountSort();
TestOP();
return 0;
}