1、直接插入排序
将一个记录插入到已排序好的有序的序列中,从而得到一个新的记录数增1的有序序列。(先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。)
设立标识值作为临时存储和判断数组边界的作用。
算法实现:
function InsertSort($num){
$count = count($num);
for($i =1 ; $i < $count ; $i++){
if($num[$i] < $num[$i-1]){ // 若第i个元素值大于第i-1个元素值,则直接插入;若小于则移动到有序序列后插入
$j = $i-1; // 有序序列中的最后一个元素的索引值
$x = $num[$i]; // 复制为标识值,即存储待排序元素
$num[$i] = $num[$i-1]; // 先将有序序列中的最后一个值向后移覆盖待排序的元素
while ($x < $num[$j]){ // 查找在有序序列中的插入位置
$num[$j+1] = $num[$j];
$j--; // 元素向后移动
}
$num[$j+1] = $x; // 插入到正确位置
}
print_r($num);
}
}
2、简单选择排序
在要排序的队列中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,直至第n-1个元素(倒数第二个数)和第n个元素(最后一个数为止)。
选择排序与冒泡排序的区别:冒泡排序通过依次交换相邻两个顺序不对的元素的位置,从而将当前最小(最大)元素放到合适的位置;而选择排序每遍历一次都记住了当前最小(最大)元素的位置,最后仅需一次交换操作即可将其放到合适的位置。
/*
* 给出的剩下的元素中寻找出最小值
* @param $i数组的索引值
* @return $k 返回最小值的索引值
*/
function SelectMinKey($arr,$i){
$k = $i;
$n = count($arr);
for ($j=$i+1;$j<$n;++$j){
if($arr[$k] > $arr[$j]){
$k = $j;
}
}
return $k;
}
// 选择排序
function selectSort($arr){
$n = count($arr);
for( $i = 0; $i<$n; ++$i ){
$key = SelectMinKey($arr,$i); // 选择最小的元素
if($key != $i){
$tmp = $arr[$i]; // 最小元素与第i位置元素互换
$arr[$i] = $arr[$key];
$arr[$key] = $tmp;
}
print_r($arr);
}
}
3、二元选择排序
每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。即每次循环确定最大最小值的索引,分别将当前循环中的最前和最后的索引的值进行替换。它是对简单选择排序的改进。
function selectSort($arr){
$len = count($arr);
for( $i=0; $i<$len/2; $i++ ){
$max = $i;
$min = $i;
for($j=$i+1 ; $j<=$len-1-$i;$j++){
$max = $arr[$j] > $arr[$max] ? $j : $max; // 每一趟取出当前最大和最小的数组下标
$min = $arr[$j] < $arr[$min] ? $j : $min;
}
$tmp = $arr[$i];
$arr[$i] = $arr[$min];
if($i == $max){ // 最大数在数组头部
if(($len-$i-1) !== $min){ // 最大数在头部,最小数在尾部
$arr[$min] = $arr[$len-$i-1];
}
$arr[$len-$i-1] = $tmp;
}else if( ($len-$i-1) == $min ){ // 最大数不在头部,最小数在尾部
$arr[$len-$i-1] = $arr[$max];
$arr[$max] = $tmp;
}else{
$arr[$min] = $tmp;
$tmp = $arr[$len-$i-1];
$arr[$len-$i-1] = $arr[$max];
$arr[$max] = $tmp;
}
}
print_r($arr);
}
4、冒泡算法
越小(或越大)的元素经由交换慢慢浮到队列顶端,它是比较相邻的元素,如果前一个比后一个大,则将它们两个调换位置,最后的元素将是最大的数。每次最大元素像气泡一样浮到数组的最后,依次比较相邻的两个元素,使较大的那个向后移。
function bubbleSort($arr){
$n = count($arr);
for($j=0;$j<$n-1;$j++){
for($i=0;$i<$n-1-$j;$i++){
if( $arr[$i] > $arr[$i+1] ){
$temp = $arr[$i];
$arr[$i] = $arr[$i+1];
$arr[$i+1] = $temp;
}
}
}
}
5、鸡尾酒排序
也叫定向冒泡排序,是对冒泡排序的一种改进。它是从低到高然后从高到低去比较队列中的元素。
function cocktailSort($arr){
$n = count($arr);
$left = 0; // 初始化边界
$right = $n - 1;
while ($left < $right){
for( $i=$left; $i<$right; $i++ ){ // 前半轮,将最大元素放到后面
if($arr[$i] > $arr[$i+1]){
$temp = $arr[$i];
$arr[$i] = $arr[$i+1];
$arr[$i+1] = $temp;
}
}
$right--;
for( $i=$right; $i>$left; $i-- ){ // 后半轮,将最小元素放前面
if( $arr[$i-1] > $arr[$i] ){
$temp = $arr[$i-1];
$arr[$i-1] = $arr[$i];
$arr[$i] = $temp;
}
}
$left++;
}
}
6、希尔排序
核心:先将序列分成较多个子序列分别进行排序,再分成较少个子序列分别进行排序,直到最后为一个序列排序。希尔排序采用每隔固定距离选取一个数的方法划分子序,其中间距距离称为增量。增量就是隔多少距离的数都为同一个子序,如果增量为N,则可以分成N个子序。每次子序都排好后,增量减半,增量减少意味着子序数减少,直到增量为1,便是全部的数序了,希尔排序完成。
划分子序后对子序分别排序,希尔排序的子序排序方法为插入排序。通过增量是否为1控制整个排序的结束,在增量为d时,遍历此时的d个子序,从k=0到k=d-1,随后对每个子序进行插入排序操作。希尔排序是插入排序的加强版,通过对原始数据进行分组再排序。
插入排序的明显的缺点是插入元素时需要与已排序的元素进行对比,对比的次数可能比较多。希尔排序就是通过将元素数组划分为若干小组,然后对各个小组进行插入排序来减少元素之间对比的次数,大大地降低了排序的时间复杂度。
function shellSort($arr){
$n = count($arr);
$d = floor( $n / 2 ); // 设置起始增量
while ( $d >= 1 ){ // 排序为1时排序结束
for($k=0;$k<$d;$k++){ // 遍历所有的子序
for($i=$k+$d;$i<$n;$i+=$d){ // 对每个子序进行插入排序
$temp = $arr[$i];
$j = $i-$d;
while ($j>=$k && $arr[$j]>$temp){
$arr[$j+$d] = $arr[$j];
$j = $j-$d;
}
$arr[$j+$d] = $temp;
}
}
$d = floor($d/2); // 缩小增量
}
}
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
内排序:所有的排序操作都在内存中完成;
外排序:由于数据太大,因此将数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;