插入排序的基本思想是:每步将一个待排序的对象,按其关键字大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。
简言之,边插入边排序,保证子序列中随时都是排好序的。
直接插入排序
新元素插入到哪里?在已形成的有序表中线性查找,并在适当位置插入,把原来位置上的元素向后顺移。
关键字序列T=(13,6,3,31,9,27,5,11),请写出直接插入排序的中间过程序列。
关键字序列T= (21,25,49,25*,16,08),请写出直接插入排序的具体实现过程。*表示后一个25
假设该序列已存入一维数组V[7]中,将V[0]作为缓冲或暂存单元(Temp)。则程序执行过程为:
Void InsertSort (SqList &L) ——教材P265
{ // 对顺序表L做直接插入排序
for ( i=2; i<=L.length; ++i )
if ( LT (L.r[i].key, L.r[i-1].key) )
// “<“,需将L.r[i]插入有序子表
{ L.r[0] = L.r[i]; // 复制为哨兵
L.r[i] = L.r[i-1];
for ( j=i-2; LT(L.r[0].key, L.r[j].key); --j )
L.r[ j+1] = L.r[ j]; // 记录后移
L.r[ j+1] = L.r[0]; // 插入到正确位置
}
} // InsertSort
<?php
function insert_sort($arr) {
//从第二个元素开始,到最后一个元素都是这个需要排序的元素
for($i=1, $len=count($arr); $i<$len; $i++) {
//获得当前需要比较的元素值。
$tmp = $arr[$i];
//内层循环控制 比较 并 插入
for($j=$i-1;$j>=0;$j--) {
//$arr[$i];//需要插入的元素; $arr[$j];//需要比较的元素
if($tmp < $arr[$j]) {
//发现插入的元素要小,交换位置
//将后边的元素与前面的元素互换
$arr[$j+1] = $arr[$j];
//将前面的数设置为 当前需要交换的数
$arr[$j] = $tmp;
} else {
//如果碰到不需要移动的元素
//由于是已经排序好是数组,则前面的就不需要再次比较了。
break;
}
}
}
//将这个元素 插入到已经排序好的序列内。
//返回
return $arr;
}
$arr = array(21,25,49,25,16,8);
$arr = insert_sort($arr);
print_r($arr);
折半插入排序
在已形成的有序表中折半查找,并在适当位置插入,把原来位置上的元素向后顺移。
Void BInsertSort (SqList &L) // 折半插入排序
{ for ( i=2;i<=L.length;++i )
{ L.r[0] = L.r[ i ]; // 将L.r [i] 暂存到L.r[0]
low=1;high=i-1;
while (low<=high) //比较,折半查找插入位置
{ m=(low+high)/2; // 折半
if (LT(L.r[0].key,L.r[m].key)) high=m-1;//插入点在低半区
else low=m+1; // 插入点在高半区
} // while
for (j=i-1;j>=high+1;--j) L.r [j+1] = L.r [j];// 记录后移
L.r [high+1] = L.r [0]; // 插入
} // for
} // BInsertSort
希尔(shell)排序(又称缩小增量排序)
基本思想:先将整个待排记录序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
技巧:子序列的构成不是简单地“逐段分割”,而是将相隔某个增量dk的记录组成一个子序列,让增量dk逐趟缩短(例如依次取5,3,1),直到dk=1为止。
优点:让关键字值小的元素能很快前移,且序列若基本有序时,再用直接插入排序处理,时间效率会高很多。
算法分析:开始时dk 的值较大,子序列中的对象较少,排序速度较快;随着排序进展,dk 值逐渐变小,子序列中对象个数逐渐变多,由于前面工作的基础,大多数对象已基本有序,所以排序速度仍然很快。
void ShellInsert (SqList &L,int dk) {
//对顺序表L进行一趟增量为dk的Shell排序,dk为步长因子
for(i=dk+1;i<=L.length; ++ i)//开始将r[i] 插入有序增量子表
if (r[i].key < r[i-dk].key) {
r[0]=r[i];//暂存在r[0]
for( j=i-dk; j>0 &&(r[0].key<r[j].key); j=j-dk )
r[ j+dk ]=r[j];//关键字较大的记录在子表中后移
r[ j+dk ]=r[0];//在本趟结束时将r[i]插入到正确位置
}
}
<?php
//希尔排序(对直接插入排序的改进)
function ShellSort(array &$arr)
{
$count = count($arr);
$inc = $count; //增量
do {
//计算增量
//$inc = floor($inc / 3) + 1;
$inc = ceil($inc / 2);
for ($i = $inc; $i < $count; $i++) {
$temp = $arr[$i]; //设置哨兵
//需将$temp插入有序增量子表
for ($j = $i - $inc; $j >= 0 && $arr[$j + $inc] < $arr[$j]; $j -= $inc) {
$arr[$j + $inc] = $arr[$j]; //记录后移
}
//插入
$arr[$j + $inc] = $temp;
}
//增量为1时停止循环
} while ($inc > 1);
}
$arr = array(49,38,65,97,76,13,27,49,55,4);
ShellSort($arr);
var_dump($arr);