1、冒泡排序
冒泡排序英文名是Bubble Sort,是一种最基础的交换排序。思想:每次寻找一组数据中最大的元素,两两比较,找到后放到最后一位。
#include<stdio.h>
void BubbleSort(int arr[], int len)
{
for(int i = 0; i < len-1; i++)
{
for(int j = 0; j < len-1-i; j++)
{
if(arr[j] > arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
int main()
{
int arr[] = {3,44,38,5,47};
int len = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, len);
return 0;
}
2、选择排序
2.1 直接选择排序
选择排序:每一次从无序区间选出最大(或最小)的一个元素,存放到无序区间的最后(或最前),直到所有待排序列的数据元素排完。每轮都找到一组数据中最小的数依次放在数组前面。
与冒泡排序不同,冒泡排序在找3数的时候,每次比较都需要进行数据交换,而选择排序是两两对比,记录数据的索引,找到数据后只进行一次交换。
#include<stdio.h>
void SelectionSort(int arr[], int len)
{
int temp = 0;
for(int i = 0; i < len-1; i++)
{
int index = 1;
for(int j = i+1; j < len; j++)
{
if(arr[j] < arr[index])
{
index = j;
}
}
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
}
int main()
{
int arr[] = {3,44,38,5,47};
int len = sizeof(arr) / sizeof(arr[0]);
SelectionSort(arr, len);
return 0;
}
2.2 双向选择排序
每次从无序区间中选出最小和最大的元素,放在无序区间的最前和最后,直到全部待排序的数组元素排完。
3、插入排序
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。
void InsertionSort(int *arr, int len)
{
int i, j, temp;
for (i = 1; i < len; i++){
if (arr[i] < arr[i-1]){
temp = arr[i];
for (j = i - 1; j >= 0 && arr[j] > temp; j--){
arr[j+1] = arr[j];
}
arr[j+1] = temp;
}
}
}
4、希尔排序
1959年Shell发明,第一个突破O(n^2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
void ShellSort(int *arr, int len)
{
int i, j, temp, increment;
for (increment = len/ 2; increment > 0; increment /= 2) {
for (i = increment; i < len; i++) {
temp = arr[i];
for (j = i - increment; j >= 0 && temp < arr[j]; j -= increment) {
arr[j + increment] = arr[j];
}
arr[j + increment] = temp;
}
}
}
5、归并排序
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
#define MAXSIZE 100
void Merge(int *SR, int *TR, int i, int middle, int rightend)
{
int j, k, l;
for (k = i, j = middle + 1; i <= middle && j <= rightend; k++) {
if (SR[i] < SR[j]) {
TR[k] = SR[i++];
} else {
TR[k] = SR[j++];
}
}
if (i <= middle) {
for (l = 0; l <= middle - i; l++) {
TR[k + l] = SR[i + l];
}
}
if (j <= rightend) {
for (l = 0; l <= rightend - j; l++) {
TR[k + l] = SR[j + l];
}
}
}
void MergeSort(int *SR, int *TR1, int s, int t)
{
int middle;
int TR2[MAXSIZE + 1];
if (s == t) {
TR1[s] = SR[s];
} else {
middle = (s + t) / 2;
MergeSort(SR, TR2, s, middle);
MergeSort(SR, TR2, middle + 1, t);
Merge(TR2, TR1, s, middle, t);
}
}
6、快速排序
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
void QuickSort(int *arr, int maxlen, int begin, int end)
{
int i, j;
if (begin < end) {
i = begin + 1;
j = end;
while (i < j) {
if(arr[i] > arr[begin]) {
swap(&arr[i], &arr[j]);
j--;
} else {
i++;
}
}
if (arr[i] >= arr[begin]) {
i--;
}
swap(&arr[begin], &arr[i]);
QuickSort(arr, maxlen, begin, i);
QuickSort(arr, maxlen, j, end);
}
}
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
7、堆排序
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
void Heapify(int *arr, int m, int len)
{
int i, temp;
temp = arr[m];
for (i = 2 * m; i <= len; i *= 2) {
if (i + 1 <= size && arr[i] < arr[i+1]) {
i++;
}
if (arr[i] < tmp) {
break;
}
arr[m] = arr[i];
m = i;
}
arr[m] = temp;
}
void BulidHeap(int *arr, int len)
{
int i;
for (i = n / 2; i > 0; i--) {
Heapify(arr, i, len);
}
}
void swap(int *arr, int i, int j)
{
int temp;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void HeapSort(int *arr, int len)
{
int i;
BulidHeap(arr, len);
for (i = len; i > 1; i--) {
swap(arr, 1, i);
Heapify(arr, 1, i - 1);
}
}
8、计数排序
计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
void CountingSort(int *A, int *B, int n, int k)
{
int *C = (int *)malloc(sizeof(int) * (k + 1));
int i;
for (i = 0; i <= k; i++) {
C[i] = 0;
}
for (i = 0; i < n; i++) {
C[A[i]]++;
}
for (i = 1; i <= k; i++) {
C[i] = C[i] + C[i - 1];
}
for (i = n - 1; i >= 0; i--) {
B[C[A[i]] - 1] = A[i];
C[A[i]]--;
}
}
9、桶排序
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。
void bucketSort(int *arr, int len, int max)
{
int i,j;
int buckets[max];
memset(buckets, 0, max * sizeof(int));
for (i = 0; i < len; i++) {
buckets[arr[i]]++;
}
for (i = 0, j = 0; i < max; i++) {
while((buckets[i]--) >0)
arr[j++] = i;
}
}
10、基数排序
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。
int get_index(int num, int dec, int order)
{
int i, j, n;
int index;
int div;
for (i = dec; i > order; i--) {
n = 1;
for (j = 0; j < dec - 1; j++)
n *= 10;
div = num / n;
num -= div * n;
dec--;
}
n = 1;
for (i = 0; i < order - 1; i++)
n *= 10;
index = num / n;
return index;
}
void RadixSort(int *arr, int len, int dec, int order)
{
int i, j;
int index;
int temp[len];
int num[10];
memset(num, 0, 10 * sizeof(int));
memset(temp, 0, len * sizeof(int));
if (dec < order) {
return;
}
for (i = 0; i < len; i++) {
index = get_index(arr[i], dec, order);
num[index]++;
}
for (i = 1; i < 10; i++) {
num[i] += num[i-1];
}
for (i = len - 1; i >= 0; i--) {
index = get_index(arr[i], dec, order);
j = --num[index];
temp[j] = arr[i];
}
for (i = 0; i < len; i++) {
arr[i] = temp[i];
}
RadixSort(arr, len, dec, order+1);
}