sort.h
#pragma once
#include<stdio.h>
void PrintArray(int* a, int n);
void InsertSort(int* a, int n);
void ShellSort(int* a, int n);
void BubbleSort(int* a, int n);
void HeapSort(int* a, int n);
void SelectSort(int* a, int n);
sort.c
准备工作
#include"Sort.h"
void PrintArray(int* a, int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void Swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
void InsertSort(int* a, int n)
{
// [0,end]有序,把end+1位置的插入到前序序列
// 控制[0,end+1]有序
for (size_t i = 0; i < n - 1; i++)
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + 1] = a[end];
}
else
{
break;
}
--end;
}
a[end + 1] = tmp;
}
}
-
插入排序
-
void InsertSort(int* a, int n)
:这是一个名为InsertSort
的函数,它接受一个整型数组指针a
和一个整数n
作为参数,表示要排序的数组和数组的长度。 -
for (size_t i = 0; i < n - 1; i++)
:使用for
循环遍历数组,从第一个元素开始直到倒数第二个元素。 -
int end = i;
:在每次循环开始时,将end
初始化为当前循环的索引i
。 -
int tmp = a[end + 1];
:将下一个位置的元素保存在tmp
变量中,用于后续的插入操作。 -
while (end >= 0)
:进入一个while
循环,该循环会从当前位置向前遍历,直到找到合适的位置插入tmp
。 -
if (tmp < a[end])
:如果tmp
比当前位置的元素小,则将当前位置的元素后移一位。 -
else
:否则,跳出循环,表示找到了tmp
应该插入的位置。 -
a[end + 1] = tmp;
:将tmp
插入到找到的位置后面,完成一次插入操作。
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
//gap = gap / 2;
gap = gap / 3 + 1;
for (int i = 0; i < n - gap; ++i)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
}
-
希尔排序
-
void ShellSort(int* a, int n)
:这是一个名为ShellSort
的函数,接受一个整型数组指针a
和一个整数n
作为参数,表示要排序的数组和数组的长度。 -
int gap = n;
:初始化间隔gap
为数组的长度n
。 -
while (gap > 1)
:进入一个while
循环,当间隔大于1时执行排序算法。 -
gap = gap / 3 + 1;
:根据希尔排序的间隔序列选择规则,更新间隔gap
。通常选择gap = gap / 3 + 1。 -
for (int i = 0; i < n - gap; ++i)
:使用for
循环遍历数组,每次以间隔gap
对数组进行分组。 -
int end = i;
:在每次循环开始时,将end
初始化为当前循环的索引i
。 -
int tmp = a[end + gap];
:将当前位置往后间隔gap
的元素保存在tmp
变量中,用于后续的插入操作。 -
while (end >= 0)
:进入一个while
循环,该循环会从当前位置向前遍历,直到找到合适的位置插入tmp
。 -
if (tmp < a[end])
:如果tmp
比当前位置的元素小,则将当前位置的元素后移一个间隔gap
。 -
else
:否则,跳出循环,表示找到了tmp
应该插入的位置。 -
a[end + gap] = tmp;
:将tmp
插入到找到的位置后面,完成一次插入操作。 -
循环结束后,缩小间隔
gap
,继续进行下一轮的排序操作,直到间隔为1时完成整个排序过程。
希尔
void BubbleSort(int* a, int n)
{
for (size_t j = 0; j < n; j++)
{
int exchange = 0;
for (size_t i = 1; i < n-j; i++)
{
if (a[i - 1] > a[i])
{
Swap(&a[i - 1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
{
break;
}
}
}
-
冒泡排序
-
void BubbleSort(int* a, int n)
:这是一个名为BubbleSort
的函数,接受一个整型数组指针a
和一个整数n
作为参数,表示要排序的数组和数组的长度。 -
for (size_t j = 0; j < n; j++)
:外层循环,控制需要进行多少轮冒泡排序,每轮将一个最大的元素移动到正确的位置。 -
int exchange = 0;
:用于标记在当前轮冒泡排序中是否发生过元素交换,若没有发生交换则表示数组已经有序,可以提前结束排序。 -
for (size_t i = 1; i < n-j; i++)
:内层循环,从第一个元素开始向后比较相邻的元素并进行交换。 -
if (a[i - 1] > a[i])
:如果前一个元素大于后一个元素,则交换它们的位置。 -
Swap(&a[i - 1], &a[i]);
:调用Swap
函数来交换两个元素的位置。 -
exchange = 1;
:标记发生了元素交换。 -
if (exchange == 0)
:如果在一轮冒泡排序中没有发生任何交换,说明数组已经有序,可以提前结束排序。 -
break;
:跳出外层循环,提前结束排序。
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[child] > a[parent])
{
Swap(&a[child], &a[parent]);
// 继续往下调整
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(int* a, int n)
{
// 向下调整建堆
// O(N)
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(a, n, i);
}
// O(N*logN)
int end = n - 1;
while (end > 0)
{
Swap(&a[0], &a[end]);
AdjustDown(a, end, 0);
--end;
}
}
-
堆排序
-
void AdjustDown(int* a, int n, int parent)
:这是一个名为AdjustDown
的函数,用于向下调整堆。接受一个整型数组指针a
,数组长度n
和父节点索引parent
作为参数。 -
int child = parent * 2 + 1;
:计算父节点parent
的左孩子节点索引。 -
while (child < n)
:进入一个while
循环,循环条件是孩子节点索引小于数组长度。 -
if (child + 1 < n && a[child + 1] > a[child])
:如果右孩子存在且比左孩子大,则选择右孩子作为较小的孩子。 -
if (a[child] > a[parent])
:如果较小的孩子比父节点大,则交换父节点和孩子节点的值,并继续向下调整。 -
Swap(&a[child], &a[parent]);
:调用Swap
函数来交换父节点和孩子节点的值。 -
parent = child;
:更新父节点为当前孩子节点。 -
child = parent * 2 + 1;
:更新孩子节点为新的父节点的左孩子。 -
else
:如果孩子节点比父节点小或相等,则跳出循环,调整结束。 -
void HeapSort(int* a, int n)
:这是一个名为HeapSort
的函数,用于实现堆排序算法。接受一个整型数组指针a
和数组长度n
作为参数。 -
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
:建立初始堆,从最后一个非叶子节点开始,向上逐个调整节点,保证每个节点都满足堆的性质。 -
AdjustDown(a, n, i);
:调用AdjustDown
函数进行向下调整。 -
int end = n - 1;
:初始化堆的末尾位置。 -
while (end > 0)
:进入一个while
循环,直到堆中只剩一个元素。 -
Swap(&a[0], &a[end]);
:将堆顶元素(最大值)与当前末尾元素交换。 -
AdjustDown(a, end, 0);
:调整交换后的堆顶元素,重新使堆满足堆的性质。 -
--end;
:缩小堆的范围,继续下一轮排序。
void SelectSort(int* a, int n)
{
int begin = 0, end = n - 1;
while (begin < end)
{
// [begin, end]
int mini = begin, maxi = begin;
for (int i = begin+1; i <= end; i++)
{
if (a[i] > a[maxi])
{
maxi = i;
}
if (a[i] < a[mini])
{
mini = i;
}
}
Swap(&a[begin], &a[mini]);
// max如果被换走了,修正一下
if (maxi == begin)
{
maxi = mini;
}
Swap(&a[end], &a[maxi]);
++begin;
--end;
}
}
-
选择排序
-
void SelectSort(int* a, int n)
:这是一个名为SelectSort
的函数,接受一个整型数组指针a
和一个整数n
作为参数,表示要排序的数组和数组的长度。 -
int begin = 0, end = n - 1;
:初始化begin
为0,end
为数组长度减1,表示当前待排序部分的起始和结束位置。 -
while (begin < end)
:进入一个while
循环,循环条件是begin
小于end
,表示还有未排序的元素。 -
int mini = begin, maxi = begin;
:初始化最小值索引mini
和最大值索引maxi
为begin
,用于记录待排序部分中的最小值和最大值。 -
for (int i = begin+1; i <= end; i++)
:遍历待排序部分,查找最小值和最大值的索引。 -
if (a[i] > a[maxi])
:如果当前元素大于最大值元素,则更新最大值索引maxi
为当前元素索引i
。 -
if (a[i] < a[mini])
:如果当前元素小于最小值元素,则更新最小值索引mini
为当前元素索引i
。 -
Swap(&a[begin], &a[mini]);
:交换最小值元素和当前待排序部分的第一个元素。 -
if (maxi == begin)
:如果最大值索引maxi
等于begin
,说明最大值元素已经被换到最小值的位置,需要更新maxi
为最小值索引mini
。 -
Swap(&a[end], &a[maxi]);
:交换最大值元素和当前待排序部分的最后一个元素。 -
++begin;
:增加begin
指向下一个待排序元素。 -
--end;
:减少end
指向下一个待排序元素,同时缩小待排序部分的范围。