1.插入排序
直接插入排序(Straight Insertion Sort)的基本思想是:
把n个待排序的元素看成为一个有序表和一个无序表。
开始时有序表中只包含1个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。
//插入排序 稳定
void insertSort(int *arr, int len){
int temp = 0;
for (int i = 0; i < len; i++){
temp = arr[i];
int j = i;
for (j; j >= 0 && arr[j - 1] > temp; j--){//向前交换找到比temp小的那个插入点
arr[j] = arr[j - 1];
}
arr[j] = temp;//插入
}
}
时间复杂度 | 稳定性 |
---|---|
O(N2) | 稳定 |
算法稳定性 – 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!
希尔排序
希尔排序实质上是一种分组插入方法。它的基本思想是:对于n个待排序的数列,取一个小于n的整数gap(gap被称为步长)将待排序元素分成若干个组子序列,所有距离为gap的倍数的记录放在同一个组中;然后,对各组内的元素进行直接插入排序。 这一趟排序完成之后,每一个组的元素都是有序的。然后减小gap的值,并重复执行上述的分组和排序。重复这样的操作,当gap=1时,整个数列就是有序的。
void shellSort(int *arr, int len){
int gap = len;
do{
gap = gap / 3 + 1;//不断减小的增量
for (int i = gap; i<len; i++){
if (arr[i]<arr[i - gap]){
int temp = arr[i];
arr[i] = arr[i - gap];
arr[i - gap] = temp;
}
}
} while (gap > 1);
}
时间复杂度 | 稳定性 |
---|---|
增量的选取有关 | 不稳定 |
选择排序
选择排序(Selection sort)是一种简单直观的排序算法。
基本思想:首先在未排序的数列中找到最小(or最大)元素,然后将其存放到数列的起始位置;接着,再从剩余未排序的元素中继续寻找最小(or最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
void selectSort(int *arr, int len){
int min = 0,j=0;
for (int i = 0; i < len - 1; i++){
min = i;
for (j = i; j < len; j++){ //找出最小值
if (arr[j] < arr[min]){
min = j;
}
}
if (min != i){ //交换位置
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
}
时间复杂度 | 稳定性 |
---|---|
O(N2) | 稳定 |
冒泡排序 稳定
void bubbleSort(int *arr, int len){
for (int i = 0; i < len; i++){
for (int j = i+1; j < len; j++){
if (arr[j] < arr[i]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
快速排序 不稳定
/* 参数说明:
* a -- 待排序的数组
* l -- 数组的左边界(例如,从起始位置开始排序,则l=0)
* r -- 数组的右边界(例如,排序截至到数组末尾,则r=a.length-1)
*/
void quick_sort(int a[], int l, int r)
{
if (l < r)
{
int i,j,x;
i = l;
j = r;
x = a[i];
while (i < j)
{
while(i < j && a[j] > x)
j--; // 从右向左找第一个小于x的数
if(i < j)
a[i++] = a[j];
while(i < j && a[i] < x)
i++; // 从左向右找第一个大于x的数
if(i < j)
a[j--] = a[i];
}
a[i] = x;
quick_sort(a, l, i-1); /* 递归调用 */
quick_sort(a, i+1, r); /* 递归调用 */
}
}