【算法】插入类排序
简介
插入类排序的基本思想是在一个已排好序的记录子集基础上,每一步将下一个待排序的几步有序插入已排好的记录子集,直到将所有待排记录全部插入为止。
1:直接插入排序
例子
对于序列{14, 62, 35, 77, 55, 14, 35, 95}而言,其顺序如下
{48} 62 35 77 55 14 *35* 98
{48 62} 35 77 55 14 *35* 98
{35 48 62} 77 55 14 *35* 98
{35 48 62 77} 55 14 *35* 98
{35 48 55 62 77} 14 *35* 98
{14 35 48 55 62 77} *35* 98
{14 35 *35* 48 55 62 77} 98
{14 35 *35* 48 55 62 77 98}
为了提高效率,附设一个监视哨data[0],使得data[0]始终存放待插入得记录。
该监视哨作用有二:
-
备份待插入记录,以便前面关键字较大得记录后移
-
防止越界
算法实现
void InsertSortion::directInsertionSort(TargetType *data, int length)
{
int j;
for (size_t i = 2; i <= length; i++)
{
data[0] = data[i]; // 将待插入数据记录到监视哨data[0]
j = i - 1;
while (data[0] < data[j]) // 寻找插入位置,同时移动元素位置
{
data[j + 1] = data[j];
j--;
}
data[j + 1] = data[0]; // 将待插入数据插入已排序的序列
}
}
在插入排序中:
-
最坏情况为逆序,每一趟比较移动次数均为\(i-1\),此时总比较次数为\(\frac{(n+2)(n-1)}{2}\),即\(\sum_{i=2}^{n}i\),记录次数也达到最大,为
\(\frac{(n+4)(n-1)}{2}\),即\(\sum_{i=2}^{n}(i+1)\) 。
-
最好情况为顺序,此时需比较\(n-1\)次,记录移动\(2(n-1)\)次。
由于排序记录大概率随机,出现各种排列概率相同,故取平均值。时间复杂度\(T(n)=O(n^2)\)
2:折半插入排序
折半插入排序主要是将查找过程利用二分查找进行优化,使其查找复杂度达到了\(O(n\log_{2}{n})\),但由于其移动元素的时间消耗不变,时间复杂度仍然是\(O(n^2)\)
算法实现
void InsertSortion::halfInsertionSort(TargetType *data, int length)
{
int temp, low, high, mid;
for (size_t i = 2; i <= length; i++)
{
temp = data[i];
low = 1;
high = i - 1;
while (low <= high) // 确定插入位置
{
mid = (low + high) / 2;
if (temp < mid)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
for (size_t j = i - 1; j >= low; j++) // 开始移动
{
data[j + 1] = data[j];
}
data[low] = temp;
}
}
3:希尔排序
希尔排序又称缩小增量排序,是一张基于插入思想的排序方法。
算法思想
先将待排序记录序列分割为若干个较稀疏的子序列,分别进行插入排序。经过上述粗略调整后,再对全部记录进行一次直接插入排序。
- 选定记录间的距离\(d_i(i=1)\),在整个待排序记录序列中,将所有间隔为\(d_1\)的记录分为一组,进行组内直接插入排序
- 取\(i=i+1\),记录间的距离为\(d_i(d_i<d_{i-1})\),在整个待排序记录序列中,将所有间隔为\(d_i\)的记录分为一组,进行组内直接插入排序。
重复步骤2多次,直到\(d_i=1\),此时只有一个子序列,对该序列进行直接插入排序即可。
例子
初始关键字序列:{46, 55, 13, 42, 94, 17, 05, 70}
取\(d_i=4\),则分为4个间隔为4的子序列:
对其每一个子序列进行插入排序,得:
再取\(d_i=2\),分为两个间隔为2的子序列:
对其两个子序列进行插入排序:
取\(d_i=1\),对整体进行插入排序,得到结果:
算法实现
void InsertSortion::shellInsert(TargetType *data, int length, int delta)
{
/* 对记录数字data做一趟希尔排序*/
for (int i = 1 + delta; i <= length; i++)
{
if (data[i] < data[i - delta])
{
data[0] = data[i]; // 备份data[i],不做监视哨
int j = i - delta;
for (j = i - delta; (j > 0) && (data[0] < data[j]); j -= delta)
{
data[j + delta] = data[j];
}
data[j + delta] = data[0];
}
}
}
/**
* @description: 希尔排序
* @param {TargetType*} 待记录数组
* @param {int} n 数组长度
* @param {int} *dalta 增量数组
* @param {int} m 增量数组长度
* @return {*}
*/
void InsertSortion::shellSort(TargetType *data, int n, int *dalta, int m)
{
for (int i = 0; i < m - 1; i++)
{
shellInsert(data, n, dalta[i]);
}
}
一般认为希尔排序的复杂度为\(O(n^{1.5})\)。且希尔排序不是稳定的排序算法。

浙公网安备 33010602011771号