排序算法
冒泡排序
O(n^2)
通过比较来交换相邻的两个数,每一次遍历一定会将当前范围内最大的移动到最后(如果是最大的,每一比较相邻的两个元素它都是最大值,逃不掉的)。
称做冒泡的原因:越小的元素会经由交换慢慢“浮”到数列的首端,就如同水中的气泡最终会上浮到顶端一样。
//Increase
void bubble_sort(int a[],int l,int r)
{
for(int i = l;i < r;++i)
{
for(int j = i;j <= r;++j)
{
if(a[i] > a[j]) swap(a[i],a[j]);
}
}
}
选择排序
对每一个元素,找到在它之后的位置比它大的元素中最大的,并进行交换(降序,如果是升序就找比它小的)
//Decrease
void select_sort(int a[],int l,int r)
{
for(int i = l;i < r;++i)
{
int k = a[i],t = i;
for(int j = i;j <= r;++j)
{
if(a[j] > k)
{
k = a[j];
t = j;
}
}
swap(a[i],a[t]);
}
}
插入排序
类似于打扑克牌时将一张牌插入已经有序的牌里面
//Increase
void insert_sort(int a[],int l,int r)
{
for(int i = l + 1;i <= r;++i){
int k = a[i], p = i - 1;
while (p >= l && k < a[p]) {
a[p + 1] = a[p];
p--;
}
a[p + 1] = k;
//令后面的每一个元素等于前面的元素,最后把k(原来的a[i])覆盖到自己应该在的地方
}
}
归并排序
O(nlogn)
采用分治的思想,将一个序列分成两个子序列分别进行排序,在两个子序列分别有序后进行合并
首先最简单的情况:对于分别只有一个元素的两个序列,由于只有一个元素,所以已经是是有序的了。
当两个子序列已经分别排好序后,再将其进行合并。合并的过程只需取出两个序列的第一个元素进行比较,放到新的序列里,再对剩下的元素重复上述操作。
举个栗子:
分治:[4 3 2 1] -> [4 3] [2 1] -> [4][3] [2][1]
归并:[3 4] [1 2] -> [1 ]([3 4] [2]) -> [1 2]([3 4]) -> [1 2 3]( [4 ] ) -> [1 2 3 4]
//Increase
void merge_sort(int a[],int tmp[],int l,int r)
{
if(l < r)
{
int mid = (l + r)/2;
merge_sort(a,tmp,l,mid);
merge_sort(a,tmp,mid+1,r);
for(int i = l;i <= r;++i)
{
tmp[i] = a[i];
}
int ln = l,rn = mid + 1,k = l;
while (ln <= mid && rn <= r)
{
if(tmp[ln] < tmp[rn])
{
a[k++] = tmp[ln++];
}else{
a[k++] = tmp[rn++];
}
}
while (ln <= mid)
{
a[k++] = tmp[ln++];
}
while (rn <= r)
{
a[k++] = tmp[rn++];
}
}
}
快速排序
#include<algorithm>
sort(a+1,a+1+n,cmp);
以一个元素为基准,分别从左右两边找比它大的元素和比它小的元素并并行交换,直到从左右两边到了中间某位置,此时左边的元素都小于它,右边的元素都大于它,再分别处理两边的序列(分治)
O(nlogn) 为了改进冒泡,但对于极端情况如果是降序的,则时间复杂度会退化成O(n^2)
//Increase
void quick_sort(int a[],int l,int r)
{
if(l <= r)
{
int i = l,j = r;
while (i != j)
{
//以a[l]为基准,从左向右找比它大的,从右往左找比它小的(递增)
//j一定要在i之前
while (a[j] >= a[l] && j > i)
{
j--;
}
while (a[i] <= a[l] && j > i)
{
i++;
}
if(j > i)
{
swap(a[i], a[j]);
}
}
swap(a[i],a[l]);
quick_sort(a, l, i - 1);
quick_sort(a, i+1, r);
}
}