#include
#include
void swap(int* a, int* b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
/*冒泡排序:时间复杂度O(N^2) 空间复杂度O(1) 稳定*/
void BubbleSort(int iarr[], int size)
{
int i, j;
// i 从0变到1后,即 j 从0到 size-i-1 后,最大数会被放到最后位置
for (i = 0; i < size - 1; i++)
{
for (j = 0; j < size - i - 1; j++)
{
if (iarr[j] > iarr[j + 1])
{
swap(&iarr[j], &iarr[j + 1]);
}
}
}
}
/*选择排序:时间复杂度O(N^2) 空间复杂度O(1) 不稳定*/
void SelectSort(int iarr[], int size)
{
int i, j, k;
for (i = 0; i < size - 1; i++)
{
k = i; //变量 k 保存数组当前位置
//从已经排序好的位置 i 开始,遍历后面未排序的
for (j = i + 1; j < size; j++)
{
if (iarr[j] < iarr[k])
k = j; //寻找最小值的位置,并将该位置赋给 k
}
//交换当前位置 i 处和未排序的最小值位置上的数
swap(&iarr[i], &iarr[k]);
}
}
/*插入排序:时间复杂度O(N^2) 空间复杂度O(1) 稳定*/
void InsertSort(int iarr[], int size)
{
int i, j, temp;
for (i = 1; i < size; i++) //从位置 i 开始,即位置 i 前面的数已经排好
{
if (iarr[i] < iarr[i - 1]) //如果当前位置数比前面一个小,就要往前插入
{
temp = iarr[i]; //将当前位置数赋给temp
//因为当前值要比前面的数小,所以要将当前值与前面的数进行比较并插入,直到比前面一个数大
//循环条件:比较到第一个数且比前面的数小
for (j = i - 1; j >= 0 && temp < iarr[j]; j--)
{
iarr[j + 1] = iarr[j]; //比当前位置数大的元素都要向后挪一位
}
iarr[j + 1] = temp; //当前位置数放到合适的位置,即比前面大且比后面小
}
}
}
/*希尔排序:时间复杂度O(NlogN) 空间复杂度O(1) 不稳定*/
void ShellSort(int iarr[], int size)
{
int i, j, temp, increment;
//插入排序的改进版,以增量increment为间隔插入,相当于分成了increment组分别排序
//该间隔每次减半,直到为1,排序完成
for (increment = size / 2; increment > 0; increment /= 2)
{
for (i = increment; i < size; i++) //
{
temp = iarr[i];
for (j = i - increment; j >= 0 && temp < iarr[j]; j -= increment)
{
iarr[j+increment] = iarr[j];
iarr[j] = temp;
}
}
}
}
/*归并排序:时间复杂度O(NlogN) 空间复杂度O(N) 稳定*/
//功能:将一个序列分成两个子序列,然后合并为一个有序的序列
//A为要排序的数组,TempA为临时存放排序好的数组
//R:右边子序列的首位置;rightEnd:右边子序列的尾部
void Merge(int A[], int TempA[], int L, int R, int rightEnd)
{
//假设两个子序列是挨着的,则左序列的尾部就是右序列首部-1
int leftEnd = R - 1;
int temp = L;
int length = rightEnd - L + 1; //求临时数组的长度
//对两个子序列进行排序,依次将子序列中较小的数放到临时数组中
//循环退出条件:其中一个序列中的数已经全部放到临时数组中
//说明另一个序列中的数都大于临时数组中的数,直接复制剩下的数到临时数组中
while (L <= leftEnd && R <= rightEnd)
{
if (A[L] <= A[R])
TempA[temp++] = A[L++];
else
TempA[temp++] = A[R++];
}
while (L <= leftEnd)
TempA[temp++] = A[L++]; //直接复制数组左边剩下的到临时数组中
while (R <= rightEnd)
TempA[temp++] = A[R++]; //直接复制数组右边剩下的到临时数组中
for (int i = 0; i < length; i++, rightEnd--)
A[rightEnd] = TempA[rightEnd]; //再把临时数组里面的数全部赋给数组A
}
//归并排序非标准接口,对整个序列进行递归划分并调用函数 Merge 进行排序
void MergeSortUnStandardInterface(int A[], int TempA[], int L, int rightEnd)
{
int center;
if (L < rightEnd) //不满足时说明子序列只剩下一个元素
{
center = (L + rightEnd) / 2;
MergeSortUnStandardInterface(A, TempA, L, center);
MergeSortUnStandardInterface(A, TempA, center + 1, rightEnd);
Merge(A, TempA, L, center + 1, rightEnd);
}
}
//使用排序统一接口int iarry[], int size
void MergeSort(int iarr[], int size)
{
int* TempA;
//申请临时数组空间,这样只需要一个临时数组
//如果在子函数中申请,会需要反复的申请空间和释放空间,浪费资源
TempA = malloc(size * sizeof(int));
if (TempA != NULL)
MergeSortUnStandardInterface(iarr, TempA, 0, size - 1);
else
printf("空间不足!");
}
/*快速排序:时间复杂度O(NlogN) 空间复杂度O(logN) 不稳定*/
//选取主元也就是基准,这里选取数组左中右的中间值
int SelectPivot(int iarr[], int left, int right)
{
int center = (left + right) / 2;
if (iarr[left] > iarr[center])
{
swap(&iarr[left], &iarr[center]);
}
if (iarr[left] > iarr[right])
{
swap(&iarr[left], &iarr[right]);
}
if (iarr[center] > iarr[right])
{
swap(&iarr[center], &iarr[right]);
}
//将主元放到(right-1)的位置上,这样只需要对(left+1)到(right-2)的元素进行比较排序
//因为通过之前的比较,位置left的元素比主元小,位置right的元素比主元大
swap(&iarr[center], &iarr[right - 1]);
return iarr[right - 1];
}
//定义阈值
#define cutoff 100
//快速排序非标准接口,将大于主元的数全放在主元的右边,小于主元的数全放在主元的左边
void QuickSortUnStandardInterface(int iarr[], int left, int right)
{
//数组长度大于所定义阈值则用快速排序,否则直接用插入排序,因为快排适合大数据
if (cutoff <= right - left)
{
//选取基准
int pivot = SelectPivot(iarr, left, right);
//定义两个“指针”i 指在左边,j 指在右边
int i = left, j = right - 1;
//一直循环,直到 i>j 时退出循环
for (;;)
{
//左边的数小于主元则指针 i 一直往右移,直到碰到大于主元的数退出
while (iarr[++i] < pivot);
//右边的数大于主元则指针 j 一直往左移,直到碰到小于主元的数退出
while (iarr[--j] > pivot);
//这时 i 停在大于主元的位置,j 停在小于主元的位置,不符合要求,则交换它们的位置
if (i < j)
swap(&iarr[i], &iarr[j]);
else
break;
}
//退出for循环时正好从位置 i 往右的数都大于主元,从 i 往前的数都小于主元
//所以交换主元位置和位置 i,主元就被放在了正确的位置
swap(&iarr[i], &iarr[right - 1]);
//依次递归对主元左右两边的序列进行排序
QuickSortUnStandardInterface(iarr, left, i - 1);
QuickSortUnStandardInterface(iarr, i + 1, right);
}
else
{
//数组长度小于所定义阈值直接用插入排序,这样效率更高
InsertSort(iarr + left, right - left + 1);
}
}
//快速排序标准接口
void QuickSort(int iarr[], int size)
{
QuickSortUnStandardInterface(iarr, 0, size - 1);
}
/*堆排序:时间复杂度O(NlogN) 空间复杂度O(1) 不稳定*/
//将N个元素的数组中以A[p]为根的子堆调整为最大堆
void PercDown(int A[], int p, int N)
{
int Parent, Child;
int X = A[p]; //取出根结点存放的值
//将父节点依次向下层比较,直到比较到最后一层退出
for (Parent = p; (Parent * 2 + 1) < N; Parent = Child)
{
//父节点从位置0开始,则位置为 i 的父节点的子节点位置分别是(2i+1)和(2i+2)
Child = Parent * 2 + 1;
//Child指向左右子结点的较大者
if ((Child != N - 1) && (A[Child] < A[Child + 1]))
Child++;
//如果父节点大于子节点则不用调整
if (X >= A[Child])
break;
//否则将子节点赋给父节点
else
A[Parent] = A[Child];
}
//最后将父节点的值放到正确的位置
A[Parent] = X;
}
void HeapSort(int A[], int size)
{
int i;
//从倒数第一个有儿子的节点开始调整,使每个节点的子树变成最大堆
for (i = size / 2 - 1; i >= 0; i--)
PercDown(A, i, size);
for (i = size - 1; i > 0; i--)
{
//交换第一个和最后一个节点的值,将最大值放到最后一个节点的位置,最大值已放到正确的位置
swap(&A[0], &A[i]);
//再调整除最后一个位置的堆,使其变成最大堆
PercDown(A, 0, i);
}
}
void main()
{
int iarry[10] = { 33,98,89,8,84,768,890,23,28,67 };
//BubbleSort(iarry, 10);
//SelectSort(iarry, 10);
//InsertSort(iarry, 10);
//ShellSort(iarry, 10);
//QuickSort(iarry, 10);
//MergeSort(iarry, 10);
HeapSort(iarry, 10);
printf("The result of sorted:\n");
for (int i= 0; i < 10; i++)
printf("%d ", iarry[i]);
}