1.插入排序
插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
算法描述:
1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果该元素(已排序)大于新元素,将该元素移到下一位置
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
6.重复步骤2~5
动画演示:
实现代码:
#include<iostream>
using namespace std;
#include<cassert>
void InsertSort(int array[], int len)
{
assert(array && len > 0);
for(int i = 1; i < len ;++i) //只有一个元素的时候有序,所以这里从1开始
{
int temp = array[i]; //记录当前待插入的元素
int end = i-1; //最后一个有序元素的下标
while(end >=0 && array[end]>temp) //找要插入的位置
{
array[end+1] = array[end];
end--;
}
array[end+1] = temp;
}
}
//改良版:上面那个版本排一个元素就需要从尾开始比较,比较次数太多了,我们可以先用二分法找出待插入的位置,整体搬移元素
void InsertSort2(int array[], int len)
{
assert(array && len > 0);
for(int i = 1; i < len; ++i)
{
int temp = array[i];
int end = i-1;
int left = 0;
int right = end;
while(left <= right)
{
int mid = (left+right)/2;
if(array[mid] > temp)
right = mid-1;
else
left = mid+1;
}//left就是我们要找的位置
//搬移元素
while(end >=0 && end >=left )
{
array[end+1] = array[end];
end--;
}
array[left] = temp;
}
}
void Print(int array[], int size)
{
for(int i = 0; i < size; ++i)
{
cout << array[i] << " ";
}
cout <<endl;
}
int main()
{
int array[] = {12,54,32,82,41,9,30,56};
int size = sizeof(array)/sizeof(array[0]);
//InsertSort(array, size);
InsertSort2(array, size);
Print(array, size);
cout << "hello..."<<endl;
return 0;
}
插入排序:
最好的情况下:正序有序(从小到大),这样只需要比较n次,不需要移动。因此时间复杂度为O(n)
最坏的情况下:逆序有序,这样每一个元素就需要比较n次,共有n个元素,因此实际复杂度为O(n*n)
平均情况下:O(n*n)
稳定的算法
适用场景:插入排序对于部分有序的数组十分高效,也很适合小规模的数组。
折半查找只是减少了比较次数,但是元素的移动次数不变,所以时间复杂度为O(n^2)是正确的 二分插入排序与序列初始状态无关。
- 希尔排序
希尔排序,也称为递减增量排序算法,是插入排序的一种高效的改进版本
算法描述:
1.先取一个正整数 d1(d1 < n),把全部记录分成 d1 个组,所有距离为 d1 的倍数的记录看成一组,然后在各组内进行插入排序
2.然后取 d2(d2 < d1)
3.重复上述分组和排序操作;直到取 di = 1(i >= 1) 位置,即所有记录成为一个组,最后对这个组进行插入排序。一般选 d1 约为 n/2,d2 为 d1 /2, d3 为 d2/2 ,…, di = 1。
动画演示:
代码实现:
#include<iostream>
using namespace std;
#include<cassert>
//希尔排序其实就是分组排序,但是每一组排序原理还是插入排序。
void ShellSort(int array[], int len)
{
assert(array && len > 0);
int gap = len;
while(gap > 1)
{
gap = gap / 3 +1; //分组间距。
for(int i = gap; i < len; ++i)
{
int temp = array[i];
int end = i-gap;
while(end >= 0 && array[end] > temp)
{
array[end+gap] = array[end];
end = end -gap;
}
array[end+gap] = temp;
}
}
}
void Print(int array[], int size)
{
for(int i = 0; i < size; ++i)
{
cout << array[i] << " ";
}
cout <<endl;
}
int main()
{
int array[] = {12,54,32,82,41,9,30,56};
int size = sizeof(array)/sizeof(array[0]);
ShellSort(array, size);
Print(array, size);
cout << "hello..."<<endl;
return 0;
}
希尔排序是插入排序的一个改良,它其实是一个分组排序, 不稳定的算法
最好情况 O(n),最坏情况o(n*n) 平均情况o(n^1.3~n^1.6)