一、直接插入排序
算法分析
- 直接插入排序的基本思想是 : 每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
- 第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从后向前扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
- 直接插入排序是由两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较,直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。
- 插入排序的基本方法是:每步将一个待排序的记录按其关键字的大小插到前面已经排序的序列中的适当位置,直到全部记录插入完毕为止。
算法实现
第一种
function InsertSort(&$arr){
$n = count($arr);
//数组中第一个元素作为一个已经存在的有序表
for($i=1;$i<$n;$i++){
$temp = $arr[$i]; //设置哨兵
for($j = $i - 1;$j >= 0 && $arr[$j] > $temp;$j --){
$arr[$j + 1] = $arr[$j]; //记录后移
}
$arr[$j + 1] = $temp; //插入到正确的位置
}
}
第二种
function insertSort($arr){
$len = count($arr);
for ($i = 1; $i < $len; $i++) {
$key = $arr[$i]; // 当前值
$pos = $i; // 当前位置
while ($pos > 0 && $arr[$pos - 1] > $key) {
$arr[$pos] = $arr[$pos - 1]; // 当前值 = 前一个值
$pos = $pos - 1; // 当前位置后移
}
$arr[$pos] = $key; // 找到当前值的位置
}
return $arr;
}
二、冒泡排序
算法分析
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
算法实现
第一种
//交换方法
function swap(array &$arr,$a,$b){
$temp = $arr[$a];
$arr[$a] = $arr[$b];
$arr[$b] = $temp;
}
//冒泡排序
function BubbleSort(array &$arr){
$length = count($arr);
for($i = 0;$i < $length - 1;$i ++){
//从后往前逐层上浮小的元素
for($j = $length - 2;$j >= $i;$j --){
//两两比较相邻记录
if($arr[$j] > $arr[$j + 1]){
swap($arr,$j,$j+1);
}
}
}
return $arr;
}
第二种
我们待排序的序列是{2,1,3,4,5,6,7,8,9},当 i = 2 时,我们已经对 9 与 8,8 与 7,·······,3 与 2 做了比较,没有任何数据交换,这就说明此序列已经有序,不需要再继续后面的循判断工作了(后面的工作也是不会发生任何数据交换,再做也是没有意义了)。为了实现这个想法,我们需要改进一下代码,增加一个标记变量 flag 来实现这一算法的改进:
/交换方法
function swap(array &$arr,$a,$b){
$temp = $arr[$a];
$arr[$a] = $arr[$b];
$arr[$b] = $temp;
}
//冒泡排序
function BubbleSort1(array &$arr){
$length = count($arr);
$flag = TRUE;
for($i = 0;($i < $length - 1) && $flag;$i ++){
$flag = FALSE;
for($j = $length - 2;$j >= $i;$j --){
if($arr[$j] > $arr[$j + 1]){
swap($arr,$j,$j+1);
$flag = TRUE;
}
}
}
return $arr;
}
代码改动的关键就是在 i 变量的for循环中,增加了对flag是否为 true 的判断,经过这样的改进,冒泡排序在性能上就有了一些提升,可以避免因已经有序的情况下的无意义循环判断。
三、选择排序
算法分析
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对 n 个元素的表进行排序总共进行至多 n -1 次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。
算法实现
function selectSort($arr)
{
$count = count($arr);
if ($count < 2) {
return $arr;
}
for ($i = 0; $i < $count - 1; $i++) {
$key = $i; // 当前值的位置
for ($k = $i + 1; $k < $count; $k++) { // 相邻值进行比较,条件成立替换当前值
if ($arr[$key] > $arr[$k]) { // 倒序 $arr[$key] < $arr[$k]
$key = $k;
}
}
if ($key != $i) {
$temp = $arr[$key]; // 交换位置
$arr[$key] = $arr[$i];
$arr[$i] = $temp;
}
}
return $arr;
}
四、快速排序
算法分析
选择一个基准元素,通常选择第一个元素或者最后一个元素。通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素。此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分
算法实现
function quickSort($arr) {
//先判断是否需要继续进行
$length = count($arr);
if($length <= 1) {
return $arr;
}
//选择第一个元素作为基准
$base_num = $arr[0];
//遍历除了标尺外的所有元素,按照大小关系放入两个数组内
//初始化两个数组
$left_array = array(); //小于基准的
$right_array = array(); //大于基准的
for($i=1; $i<$length; $i++) {
if($base_num > $arr[$i]) {
//放入左边数组
$left_array[] = $arr[$i];
} else {
//放入右边
$right_array[] = $arr[$i];
}
}
//再分别对左边和右边的数组进行相同的排序处理方式递归调用这个函数
$left_array = quickSort($left_array);
$right_array = quickSort($right_array);
//合并
return array_merge($left_array, array($base_num), $right_array);
}