一、什么是排序
1、概念
排序就是将一组杂乱无章的数据按照一定的规律(升序或者降序)组织起来
2、分类
3、各排序之间的时间复杂度&空间复杂度&稳定性
二、插入排序
1、直接插入排序
基本思想:
当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好 序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移。
元素集合越接近有序,直接插入排序算法的时间效率越高,其时间效率在O(n)与O(n^2)之间。直 接插入排序的空间复杂度为O(1),它是一种稳定的排序算法。
数组:{2 ,5 ,4 ,9 ,3 ,6 ,8 ,7 ,1 ,0}
void InsertSort(int* a, size_t n)
{
for (int i = 1; i < n; i++)
{
// 若第i个元素大于第i-1个元素,则直接插入,否则需要挪动
int end = i - 1; //end指向有序区间的结束为最后一个元素
int tmp = a[i]; //tmp指向你要插入的数字
// 开始比较大小搬移元素
while (end >= 0 && tmp < a[end])
{
a[end + 1] = a[end];
end--;
}
a[end + 1] = tmp;
}
}
2、直接插入演变之折半插入(俗称二分查找似插入)
折半插入排序(binary insertion
sort)是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
折半插入排序算法是一种稳定的排序算法,比直接插入算法明显减少了关键字之间比较的次数,因此速度比直接插入排序算法快,但记录移动的次数没有变,所以折半插入排序算法的时间复杂度仍然为O(n^2),与直接插入排序算法相同。
基本思想:
定义出left和right给出一段区间,求出mid,看要插入的数tmp和mid比较的大小 ,若tmp>mid,则left=mid-1;tmp小于mid,则right=mid+1;当left的值都比right大时,此时就需要搬移元素,调整排序了
void BInsertSort(int* a, size_t n)
{
for (int i = 1; i < n; i++)
{
int left = 0;
int right = i - 1;
int tmp = a[i];
// 查找插入的位置
while (left <= right)
{
int mid = right + ((left - right) >> 1);
if (a[mid] > tmp)
right = mid - 1;
else
left = mid + 1;
}
int end = i - 1;
// 搬移元素
while (end >= left)
{
a[end + 1] = a[end];
end--;
}
a[left] = tmp;
}
}
3、希尔排序:一种优化的插入排序
因为插入排序在数据有序时,时间复杂度是趋于O(n),在数据逆序时,时间复杂度是趋于O(n^2)
(1)概念
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
(2)基本思想
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。(也就是预排序:1、期望是让序列基本有序;之后在进行插入排序) 步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。
gap的选择:
1、为了让大的数更快地走到后面去,选用比较大的间隔
2、为了让数据更接近有序,选择比较小的间隔(gap)
所以选择gap的大小时,我们可以综合一下:动态的去选则间隔,让间隔不断的变化
void shellSort(int *a, size_t n)
{
int i, j;
int key;
int gap = n;
// 当gap==1的时候;就是插入排序
while (gap > 1)
{
gap = gap / 3 + 1; //一般取素数
for (i = gap; i < n; i++)
{
key = a[i];
for (j = i - gap; j >= 0; j -= gap)
{
if (a[j] <= key)
break;
else
a[j + gap] = a[j];
}
a[j + gap] = key;
}
}
}