目录
1.冒泡排序
思路:从N,N-1,···,2个数中找到最大值,放在当前数组的末尾。
优化版:当一趟比较中没有发生任何交换时,说明数组已经有序。
void bubbleSort(int arr[]) {
int cnt = 0;
for (int i = N; i > 0; --i) {
for (int j = 0; j < i - 1; ++j) {
if (arr[j] > arr[j + 1]) {
SWAP(arr[j], arr[j + 1]);
++cnt;
}
if(cnt == 0) return;
}
}
}
2.选择排序
① 从N,N-1,···,2个数中找到最小值;
② minPos记录了最小值的下标,找到minPos之后和未排好序部分最开始元素交换。
void selectSort(int arr[]) {
for (int i = 0; i < N - 1; ++i) {
int minPos = i;
for (int j = i + 1; j < N; ++j) {
if (arr[j] < arr[minPos]) {
minPos = j;
}
}
SWAP(arr[i], arr[minPos]);
}
}
3.插入排序
思路:将未排序的元素拷贝一份,当成是新元素插入到原有序数组中;
① i表示新来元素下标;j表示探查元素的下标;
② 如果arr[ j ] > arr[ i ],后移;反之则插入到arr[ j ]后面。
void insertSort(int arr[]) {
for (int i = 1; i < N; ++i) {
int insertVal = arr[i];
int j;
//找到插入位置后插入,然后退出循环,所以在循环条件中直接加入arr[j] > insertVal
for (j = i - 1; j >= 0 && arr[j] > insertVal; --j) {
arr[j + 1] = arr[j];
}
arr[j + 1] = insertVal;
}
}
4.希尔排序
思路:改变插入排序中的步长,将数组分组排序,每趟趟得到比原来更有序的数组
原因:插入排序下,原数据越有序,速度越快
① 将步长d设置为N/2,把数组分为N/2个组排序;
② 将步长设置为d/2,···
③ 知道步长为1时,变为插入排序。
void shellSort(int arr[]) {
for (int d = N / 2; d > 0; d >>= 1) {
for (int i = d; i < N; i+=d) {
int insertVal = arr[i];
int j;
for (j = i - d; j >= 0 && arr[j] > insertVal; j -= d) {
arr[j + d] = arr[j];
}
arr[j + d] = insertVal;
}
}
}
5.快速排序
递归版:分治+递归
① 找到一个枢纽元素pivot,把比pivot小的元素放在左边,把比pivot大的元素放在右边;
② 递归排序左边,递归排序右边;
③ 当只有0或1个元素时,数组天然有序。
注意:
① 当数组中元素个数大于等于二才有排序的必要;
② 考虑两种极端情况:所有的数都大于/小于pivot。
int partition(int arr[], int left, int right) {
int i, j;
for (i = left, j = left; i < right; ++i) {
//i:探查比pivot小的值换到左边 j:比pivot大的第一个值
if (arr[i] < arr[right]) {
SWAP(arr[i], arr[j]);
++j;
}
}
SWAP(arr[j], arr[right]);
return j;
}
void quickSort(int arr[], int left, int right) {
if (left < right) { //缺少条件会导致溢出
int pivot = partition(arr, left, right);
quickSort(arr, left, pivot - 1);
quickSort(arr, pivot + 1, right);
}
}
非递归版:qsort
#include <stdlib>
void qsort(void *buf, size_t num, size_t size, int (*compare)(const void*, const void*));
① num 数组中元素个数;
② size 元素大小;
③ int (*compare)(const void*, const void*) 函数指针,回调函数;
④ const void* 将参数强制转换为以元素类型为基类型的指针。
//自定义比较函数
int MyCompare(const void* p1, const void* p2) {
int* pLeft = (int *)p1;
int* pRight = (int*)p2;
return *pLeft - *pRight;
}
//调用qsort
qsort(arr, N, sizeof(int), MyCompare);
6.堆排序
① 对N个无序元素建大根堆。
自底向下,从最后一个双亲结点向前遍历直到根,按照兄弟结点,双亲结点的顺序比较,找到最大元素放在根。
② 调整堆。
将根和最后一个结点交换,此时的最后一个结点脱离堆,堆的规模-1。从根出发重新调整为大根堆。
③ 重复②直到堆的规模为1。
void adjustMaxHeap(int arr[], int pos, int len) {
//pos 要调整的结点;len 堆的当前规模
//pos左孩子=2*(pos+1) 下标 = 2*pos+1
//pos右孩子下标 = 2*pos+2
int parent = pos;
int child = 2 * pos + 1;
//保证孩子在堆内
while (child < len) {
if (child + 1 < len && arr[child] < arr[child + 1]) { //兄弟比较
++child;
}
if (arr[child] > arr[parent]) { //孩子和双亲比较
SWAP(arr[child], arr[parent]);
parent = child;
child = 2 * parent + 1;
}
else {
break;
}
}
}
void heapSort(int arr[]) {
//从最后一个双亲结点自底向上建立大根堆
for (int i = N / 2 - 1; i >= 0; --i) {
adjustMaxHeap(arr, i, N);
}
//交换堆顶和末尾元素,堆规模-1
SWAP(arr[0], arr[N - 1]);
//自顶向下调整大根堆
for (int i = N - 1; i >= 2; --i) {
adjustMaxHeap(arr, 0, i);
SWAP(arr[0], arr[i - 1]);
}
}
7.归并排序
思路:分治 + 递归
① 先排序左边,再排序右边,最后合并左右两边;
② 当数组中只有0/1个元素时自然有序。
排序方法:将原来的数据从arr拷贝到brr,用i来遍历左边,j遍历右边,k指向结果。
取brr[i]和brr[j]中较小的作为结果,指针后移。
当有一边遍历结束,直接把另一边剩余部分加入。
注意:当left=right时排序结束。
void merge(int arr[], int brr[], int left, int mid, int right) {
memcpy(brr + left, arr + left, (right - left + 1) * sizeof(int));
//i指向左半边,j指向右半边,k指向结果
int i, j, k;
for (i = left, j = mid + 1, k = left; i <= mid && j <= right; ++k) {
if (brr[i] < brr[j]) {
arr[k] = brr[i];
++i;
}
else {
arr[k] = brr[j];
++j;
}
}
while (i <= mid) {
arr[k++] = brr[i];
++i;
}
while (j <= right) {
arr[k++] = brr[j];
++j;
}
}
void mergeSort(int arr[], int brr[], int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, brr, left, mid);
mergeSort(arr, brr, mid + 1, right);
merge(arr, brr, left, mid, right);
}
}
8.计数排序
① 创建一个辅助数组count[M]并初始化;
② 遍历arr数组,根据arr[i]修改count数组下标为arr[i]的值;
③ 从头到尾遍历count,重建arr数组。
void countSort(int arr[]) {
int count[M] = { 0 };
for (int i = 0; i < N; ++i) {
++count[arr[i]];
}
int k = 0;
for (int j = 0; j < M; ++j) {
while (count[j]-- > 0) {
arr[k++] = j;
}
}
}