1、冒泡排序
冒泡排序思想:冒泡排序是一种简单直观的排序算法,它需要重复循环遍历,每次两两比较,最后确定一个最大值,直到全部元素都被有序化,这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
算法步骤:
Step1:相邻元素进行比较,若前一个比后一个大,则进行交换。
Step2:对每一对相邻元素都进行比较,从第一对到最后一对,一次下来确定一个最大的元素。
Step3:针对所有元素重复以上步骤。
代码实现:
#include<stdio.h>
//冒泡排序
void bubble_sort(int arr[], int len)
{
int i, j, temp;
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - i - 1; j++)
//循环完一次末尾都会确定一个最大的数字,已经排序好的末尾的数字不参与比较
{
if (arr[j]>arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main()
{
int arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70 };
int len = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, len);
for (int i = 0; i < len; i++)
{
printf("%d->", arr[i]);
}
printf("\n");
return 0;
}
2、选择排序
选择排序思想: 选择排序也是一种简单的排序算法,它也是循环遍历数组,每次只确定未排序元素中的一个最小(大)值。
算法步骤:(假如排好后为升序数组)
Step1:在未排序数组中先选出一个最小值放到排序序列的起始位置
Step2:再从未排序序列中寻找最小元素放到已排序序列的末尾
Step3:重复第二步直到所有元素排序完毕
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = *a;
}
void select_sort(int arr[], int len)
{
int i, j, min;
for (int i = 0; i < len; i++)
{
min = i;
for (int j = i + 1; j < len - i; j++)
{
if (arr[j] < arr[min])
{
min = j;
}
swap(&arr[j], &arr[min]);
}
}
}
3、插入排序
插入排序思想: 插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动
算法步骤:
1.将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
2.从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
代码:
void Insert_sort(int arr[], int len)
{
int i, j, key;
for (int i = 1; i < len; i++)
{
key = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > key)
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
4、希尔排序
希尔排序思想: 希尔排序也叫做缩小增量排序,它通过先设置一个增量n,大小为数组长度的一半,将间隔为n的元素视作一个组,然后对每个组内部的元素进行从小到大进行插入排序;然后再将增量n缩小一半,再次进行分组插入排序,直到增量n为1,因为增量为1的时候,所有的元素都为同一个组了
算法步骤:
Step1:选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
Step2:按增量序列个数 k,对序列进行 k 趟排序;
Step3:每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直 接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度 。
void shellsort(int *ar, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 2;
int i = 0;
for (i = 0; i < n - gap; ++i)
{
int end = i;
int tmp = ar[end + gap];
while (end >= 0)
{
if (tmp < ar[end])
{
ar[end + gap] = ar[end];
end -= gap;
}
else
break;
}
ar[end + gap] = tmp;
}
}
}
5、归并排序
**归并排序思想:**归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采 用分治法(Divide and Conquer)的一个非常典型的应用。
Step 1:将n个元素分成两个含n/2元素的子序列
Step 2:用MS将两个子序列递归排序(最后可以将整个原序列分解成n个子序列)
Step 3:合并两个已排序好的序列
void merge(int *arr, int L, int M, int R){
int left_size = M-L;
int right_size = R-M+1;
int *L_arr = new int [left_size];
int *R_arr = new int [right_size];
for(int i=L; i<M; i++)
L_arr[i-L] = arr[i];
for(int i=M; i<=R; i++)
R_arr[i-M] = arr[i];
int i = 0, j = 0, k = L;
while(i < left_size && j < right_size)
if(L_arr[i]<R_arr[j])
arr[k++] = L_arr[i++];
else
arr[k++] = R_arr[j++];
while(i < left_size)
arr[k++] = L_arr[i++];
while(j < right_size)
arr[k++] = R_arr[j++];
}
void merge_sort(int *arr, int L, int R){
if(L == R)
return;
else
{
int M = (L+R)/2;
merge_sort(arr, L, M);
merge_sort(arr, M+1, R);
merge(arr, L, M+1, R);
}
}
6、堆排序
堆排序思想: 是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
算法步骤:
Step1:最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
Step2:创建最大堆(Build Max Heap):将堆中的所有数据重新排序
Step3:堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算
void swap(int arr[], int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void heapify(int tree[], int n,int i) //n代表有多少节点,i表示对哪一个节点进行操作
{
if (i >= n)
return;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
int max = i;
//找出最大值
if (c1<n && tree[c1] > tree[max])
max = c1;
if (c2<n && tree[c2] > tree[max])
max = c2;
//拿最大值和i做交换
if (max != i)
{
swap(tree, max, i);
heapify(tree, n, max);
}
}
void build_heap(int tree[], int n)
{
int last_node = n - 1;
int parent = (last_node - 1) / 2;
int i;
for (i = parent; i >= 0; --i)
{
heapify(tree, n, i);
}
}
void heap_sort(int tree[], int n)
{
build_heap(tree, n);
int i;
for (i = n - 1; i >= 0; --i)
{
swap(tree, i, 0);//把建好的大堆做交换堆顶与最后一个元素交换
heapify(tree, i, 0);
}
}
7、快速排序
快速排序思想::快速排序算法是冒泡排序的一次改进,通过多次比较和交换来实现排序。
算法步骤:
Step1:首先在数组中选取一个分界值key,通过key将数组分成两部分。
Step2:将数组中大于等于key的元素集中到key的右边,将小于key的元素集中到key的左边
Step3:然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理
代码实现:
int _Partition(int *ar, int left, int right)
{
int low = left, high = right;
int key = ar[low];
while (low < high)
{
while (low < high&&ar[high] > key)
high--;
swap(&ar[high], &ar[low]);
while (low < high&&ar[low] <= key)
low++;
swap(&ar[low], &ar[high]);
}
return low;
}
void Quicksort(int ar[], int left, int right)
{
if (left < right)
return;
int Pos = _Partition(ar, left, right);
Quicksort(ar, left, Pos - 1);
Quicksort(ar, Pos + 1, right);
}