1.常见的排序算法
关于排序的应用这里就不详细赘述了,直接上干货。本文将实现插入排序、希尔排序、选择排序、堆排序、冒泡排序、快排(QuikeSort)、归并排序以及计数排序。
2.各种排序算法的实现
2.1插入排序
2.1.1基本思想:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
2.1.2代码实现:
//插入排序
void InsertSort(int* a, int n)
{
//假设{a[0],a[end]}这个区间是有序的
for (int i = 0; i < n - 1; i++)
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
//当tmp<a[end]时将a[end]向后挪一位,直到tmp不再小于a[end]
if (tmp < a[end])
{
a[end + 1] = a[end];
end--;
}
//当tmp>=当前a[end]时跳出循环
else
{
break;
}
}
//将tmp插入,使{a[0],a[end+1]}有序
a[end + 1] = tmp;
}
}
2.2希尔排序
2.2.1基本思想:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。(当gap>1时先进行预排序,为gap=1提供排序有利条件)
2.2.2代码实现:
//希尔排序
void ShellSort(int* a, int n)
{
//gap一般选择3,循环完后递减
int gap = 3;
while (gap--)
{
for (int j = 0; j < gap; j++)
{
for (int i = j; i < n - gap; i += gap)
{
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;
}
}
}
}
}
2.3选择排序
2.3.1基本思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
2.3.2代码实现:
//交换
void Swap(int* a1, int* a2)
{
int tmp = *a1;
*a1 = *a2;
*a2 = tmp;
}
//选择排序
void SelectSort(int* a, int n)
{
int end = 0;
while (end < n)
{
int little = end;
for (int i = end; i < n; i++)
{
if (a[i] < a[little])
{
little = i;
}
}
Swap(&a[end],&a[little]);
end++;
}
}
2.4堆排序
2.4.1基本思想:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
2.4.2代码实现:
//交换
void Swap(int* a1, int* a2)
{
int tmp = *a1;
*a1 = *a2;
*a2 = tmp;
}
//向下调整
void AdjustDown(int* a, int n, int root)
{
int child = root * 2 + 1;
while (child < n)
{
if (child + 1 < n && a[child + 1] > a[child])
{
child ++;
}
if (a[child] > a[root])
{
Swap(&a[child], &a[root]);
root = child;
child = root * 2 + 1;
}
else
{
break;
}
}
}
// 堆排序
void HeapSort(int* a, int n)
{
//建大堆
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(a, n, i);
}
int end = n - 1;
while (end > 0)
{
Swap(&a[end], &a[0]);
//调整之后,重新建大堆
AdjustDown(a, end, 0);
end--;
}
}
2.5冒泡排序
冒泡排序就很简单了,类似于打擂台的方式层层选择出最大或最小的数进行排序。
2.5.1代码实现:
//交换
void Swap(int* a1, int* a2)
{
int tmp = *a1;
*a1 = *a2;
*a2 = tmp;
}
// 冒泡排序
void BubbleSort(int* a, int n)
{
for (int j = n-1; j > 0; j--)
{
for (int i = 0; i < j; i++)
{
if (a[i] > a[i + 1])
{
Swap(&a[i], &a[i + 1]);
}
}
}
}
2.6快速排序
2.6.1基本思想:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
2.6.2代码实现:
// 快速排序递归实现
// 快速排序hoare版本
int PartSort1(int* a, int left, int right)
{
int begin = left;
int end = right;
int keyi = left;
while (begin < end)
{
while (begin < end && a[end] >= a[keyi])
{
end--;
}
while (begin < end && a[begin] <= a[keyi])
{
begin++;
}
Swap(&a[begin], &a[end]);
}
if (a[keyi] > a[begin])
{
Swap(&a[keyi], &a[begin]);
}
return begin;
}
// 快速排序挖坑法
int PartSort2(int* a, int left, int right)
{
int begin = left;
int end = right;
int dig = left;
int key = a[left];
while (begin < end)
{
while (begin<end && a[end] >= key)
{
end--;
}
if (a[end] < key)
{
a[dig] = a[end];
dig = end;
}
while (begin < end && a[begin] <= key)
{
begin++;
}
if (a[begin] > key)
{
a[dig] = a[begin];
dig = begin;
}
}
a[dig] = key;
return dig;
}
// 快速排序前后指针法
int PartSort3(int* a, int left, int right)
{
int prev = left;
int cur = prev + 1;
int key = a[left];
int keyi = left;
while (cur <= right)
{
if (a[cur] <= key && ++prev != cur)
{
Swap(&a[prev], &a[cur]);
}
cur++;
}
Swap(&a[keyi], &a[prev]);
return prev;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
{
return;
}
//int key = PartSort1(a, left, right);
//int key = PartSort2(a, left, right);
int key = PartSort3(a, left, right);
QuickSort(a, left, key - 1);
QuickSort(a, key + 1,right);
}
// 快速排序 非递归实现
#include"Stack.h"
void QuickSortNonR(int* a, int left, int right)
{
ST s;
StackInit(&s);
STPush(&s, right);
STPush(&s, left);
while (!StackEmpty(&s))
{
int begin = StackTop(&s);
STPop(&s);
int end = StackTop(&s);
STPop(&s);
int key = PartSort1(a, begin, end);
if (key + 1 < end)
{
STPush(&s, end);
STPush(&s, key + 1);
}
if (begin < key - 1)
{
STPush(&s, key - 1);
STPush(&s, begin);
}
}
StackDestroy(&s);
}
2.7归并排序
2.7.1代码实现:
// 归并排序递归实现
void MergeSort(int* a, int n)
{
int* arr = (int*)malloc(sizeof(int) * n);
if (arr == NULL)
{
perror("malloc fail");
return;
}
_MergeSort(a, arr, 0, n - 1);
}
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
int* arr = (int*)malloc(sizeof(int) * n);
if (arr == NULL)
{
perror("malloc fail");
return;
}
int gap = 1;
while (gap < n)
{
for (int i = 0; i < n; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
if (begin2 > n)
{
break;
}
if (end2 > n)
{
end2 = n-1;
}
int j = i;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])
{
arr[j++] = a[begin1++];
}
else
{
arr[j++] = a[begin2++];
}
}
while (begin1 <= end1)
{
arr[j++] = a[begin1++];
}
while (begin2 <= end2)
{
arr[j++] = a[begin2++];
}
memcpy(a + i, arr + i, sizeof(int) * (end2 - i + 1));
}
gap *= 2;
}
free(arr);
arr = NULL;
}
2.8计数排序
代码实现:
// 计数排序
void CountSort(int* a, int n)
{
int little = a[0];
int big = a[0];
for (int i = 0; i < n; i++)
{
if (a[i] < little)
{
little = a[i];
}
if (a[i] > big)
{
big = a[i];
}
}
int m = big - little;
int* arr = (int*)calloc(m+1,sizeof(int));
if (arr == NULL)
{
perror("malloc fail");
return;
}
for (int i = 0; i < n; i++)
{
arr[a[i] - little]++;
}
int j = 0;
for (int i = 0; i < m+1; i++)
{
while (arr[i]--)
{
a[j++] = i + little;
}
}
}