1.插入排序(稳定,O(n²))
数组前半部分为有序区,将ai和前面i个数依次比较,插入到合适的位置。
void insert_sort(int *a, int n)
{
for (int i = 1; i < n; i++) // a[0]-a[i-1]为当前有序区
{
int j = i - 1; //记录比较停止的位置,将当前数插入到它前面
int pos = a[i]; //这里一定要用一个变量存储比较值,否则a[i]的值会被a[i-1]覆盖掉
for (j; j >= 0&&a[j]>pos; j--)
{
a[j + 1] = a[j];
}
a[j + 1] = pos;
}
}
2.冒泡排序(稳定,O(n²))
数组后半部分为有序区,每次将ai之前的i个数(无序区)中的最值“冒泡”到有序区的前面,直到整个数组均为有序区。
void bubble_sort(int *a, int n)
{
for (int i = n-1; i >= 0; i--) //a[i]-a[n-1]为当前有序区,每经过一轮“冒泡”,有序区就增大一位,直到整个序列都是有序区
{
for (int j = 0; j < i; j++) //每次从无序区开始位置,将无序区的最大值“冒泡”到有序区的前面
{
if (a[j] > a[j + 1]) //将较大的数挤到右边,最后最大数肯定在无序区最右边。
{
int t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
}
3.选择排序(不稳定,O(n²))
数组前半部分为有序区,每次选择ai之后的数中优先级最大的数,与当前位置交换,扩大有序区。
void bubble_sort(int *a, int n)
{
for (int i = n-1; i >= 0; i--) //a[i]-a[n-1]为当前有序区,每经过一轮“冒泡”,有序区就增大一位,直到整个序列都是有序区
{
for (int j = 0; j < i; j++) //每次从无序区开始位置,将无序区的最大值“冒泡”到有序区的前面
{
if (a[j] > a[j + 1]) //将较大的数挤到右边,最后最大数肯定在无序区最右边。
{
int t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
}
4.快速排序(不稳定,O(nlogn))
①快排是对冒泡排序的一种改进,其思想为:通过一趟排序将序列分隔为两部分,这两部分整体有序,局部无序(即一部分数据均比另一部分小)。
②快排需要选择一个驱轴元素(一般为当前序列第一个),用两个指针low和high代表整个序列的第一个元素和最后一个元素,然后开始比较。
③比较方式为:
low和high指针整体看起来不断逼近,先比较high指针指向元素和驱轴元素,若不小于驱轴元素,则high指针后退,直到找到第一个小于驱轴元素的值,将其和low指向元素元素交换;
然后从low开始继续比较,若low指针指向元素不大于驱轴元素,则low指针前进,直到找到第一个大于驱轴元素的值,将其和high指向元素交换;
重复以上两步,直到low和high两指针相遇。
整个比较交换过程结束以后,相当于将小于驱轴元素的值全部移动到前半部分,大于驱轴元素的值全部移动到后半部分,low/high指针指向的元素就是两部分的分界点
④快速排序应用了分治的思想,递归进行步骤③,直到序列整体有序。
void quick_sort(int *a, int low,int high)
{
if (low < high)
{
int pivot = separate(a, low, high);
quick_sort(a, low, pivot - 1);
quick_sort(a, pivot+1, high);
}
}
int separate(int *a, int low, int high)
{
int pivot_key = a[low]; //序列的第一个元素作为驱轴
while (low < high) //从表的两端交替向中间扫描,直到两端指针相遇,结束循环
{
int temp;
while (low < high&&a[high] >= pivot_key) --high; //从右开始扫描,找到第一个小于驱轴的值
temp = a[high];
a[high] = a[low];
a[low] = temp;
while (low < high&&a[low] <= pivot_key) ++low; //从左开始扫描,找到第一个大于驱轴的值
temp = a[high];
a[high] = a[low];
a[low] = temp;
}
//返回驱轴点的索引值
return low;
}
5.希尔排序(不稳定,O(nlogn))
基于直接插入排序,也称为缩小增量排序,先将整个序列分隔为若干子序列,(子序列由相隔某个增量的记录组成,而增量是人为定义的),对子序列分别进行直接插入排序,然后缩小增量,重复操作,直到整体基本有序时,对整体序列进行一次直接插入排序。
6.归并排序(稳定,O(nlogn))
将两个或两个以上的有序表组合成一个新的有序表。如2路归并排序等。
7.堆排序(不稳定,O(nlogn))
将n个元素组成的序列看成一颗完全二叉树,且满足,每一个结点的值均小于(大于)其左右子树根节点的值,则堆顶元素的值即为整个序列的最小(大)值。
8.其他非选择类排序
一般需要借助辅助空间,包括有基数排序、桶排序、计数排序等。