1、冒泡排序
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。
这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
function popOrder($arr)
{
$len = count($arr);
for($i = 1; $i < $len; $i++){
for($j=0; $j < $len-$i;$j++){
if($arr[$j] > $arr[$j+1]){
$temp = $arr[$j];
$arr[$j] = $arr[j+1];
$arr[$j+1] = $temp;
}
}
}
return $res;
}
2、选择排序
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
function selectOrder($arr)
{
$len = count($arr);
for($i=0; $i<$len; $i++){
$min = $i;
for($j=$i; $j<$len;$j++){
if($arr[$min] > $arr[$j]){
$min = $j;
}
}
if($min != $i){
$temp = $arr[$min];
$arr[$min] = $arr[$i];
$arr[$i] = $temp;
}
}
return $res;
}
3、插入排序
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。
(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
function insertOrder($arr)
{
$len = count($arr);
for($i=1; $i<$len; $i++){
if($arr[$i] < $arr[$i-1]){
for($j=$i;$j>0;$j--){
if($arr[$j] < $arr[$j-1]){
$tmp = $arr[$j];
$arr[$j] = $arr[$j-1];
$arr[$j-1] = $tmp;
}
}
}
}
return $arr;
}
4、希尔排序
选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
按增量序列个数 k,对序列进行 k 趟排序;
每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,
分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,
表长度即为整个序列的长度。
function shellOrder($arr)
{
$len = count($arr);
$gap = 3;间隔几个(0与第一个数中间的间隔个数)
$h = 1;分成多少份
while($h < $len/$gap){
$h = $gap * $h + 1;
}
while($h >= 1){
for($i = $h; $i < $len; $i++){
for($j = $i; $j >= $h;$j = $j-$h){
if($arr[$j] < $arr[$j-$h]){
$tmp = $arr[$j];
$arr[$j] = $arr[$j-$h];
$arr[$j-$h] = $tmp;
}
}
}
$h = $h/$gap;
}
return $arr;
}
5、归并排序
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
设定两个指针,最初位置分别为两个已经排序序列的起始位置;
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
重复步骤 3 直到某一指针达到序列尾;
将另一序列剩下的所有元素直接复制到合并序列尾。
function mergeOrder($arr)
{
if(count($arr) < 2){
return $arr;
}
$middle = count($arr)/2;
$left = array_slice($arr,0,$middle);
$right = array_slice($arr,$middle);
return merge(mergeOrder($left),mergeOrder($right));
}
function merge($left,$right)
{
$res = [];
while(count($left) > 0 && count($right) > 0){
if($left[0] <= $right[0]){
$res[] = array_shift($left);
}else{
$res[] = array_shift($right);
}
}
while(count($left)){
$res[] = array_shift($left);
}
while(count($right)){
$res[] = array_shift($right);
}
return $res;
}
6、快速排序
从数列中挑出一个元素,称为 “基准”(pivot);
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
function quickOrder($arr)
{
$len = count($arr);
if($len < 2){
return $arr;
}
$tmp = $arr[0];
$left = [];
$right = [];
for($i=1; $i < $len; $i++){
if($arr[$i] < $tmp){
$left[] = $arr[$i];
}else{
$right[] = $arr[$i];
}
}
$left = quickOrder($left);
$left[] = $tmp;
$right = quickOrder($right);
return array_merge($left,$right);
}
7、堆排序
创建一个堆 H[0……n-1];
把堆首(最大值)和堆尾互换;
把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
重复步骤 2,直到堆的尺寸为 1。
function heapSort($arr)
{
//建立堆
$len = count($arr);
for($i = floor($len/2); $i>=0; $i--){
buildHeap($arr,$i,$len);
}
for($i=count($arr)-1; $i >=1; $i--){
$tmp = $arr[0];
$arr[0] = $arr[$i];
$arr[$i] = $tmp;
$len--;
buildHeap($arr,0,$len);
}
return $arr;
}
function buildHeap(&$arr,$i,$len)
{
$left = 2 * $i + 1;
$right = 2 * $i + 2;
$largest = $i;
if($left < $len && $arr[$left] > $arr[$largest]){
$largest = $left;
}
if($right < $len && $arr[$right] > $arr[$largest]){
$largest = $right;
}
if($i != $largest){
$tmp = $arr[$i];
$arr[$i] = $arr[$largest];
$arr[$largest] = $tmp;
buildHeap($arr,$largest,$len);
}
}
或者
function heapOrder($arr)
{
global $len;
$len = count($arr);
buildMaxHeap($arr);
for($i = count($arr)-1; $i > 0;$i--){
swap($arr, 0, $i);
$len--;
heapify($arr, 0);
}
return $arr;
}
function buildMaxHeap(&$arr)
{
global $len;
for($i = floor($len/2);$i >= 0;$i--){
heapify($arr, $i);
}
}
function heapify(&$arr,$i)
{
global $len;
$left = 2 * $i + 1;
$right = 2 * $i + 2;
$largest = $i;
if($left < $len && $arr[$left] > $arr[$largest]){
$largest = $left;
}
if($right < $len && $arr[$right] > $arr[$largest]){
$largest = $right;
}
if($largest != $i){
swap($arr, $i, $largest);
heapify($arr, $largest);
}
}
function swap(&$arr, $i, $j)
{
$tmp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $tmp;
}
8、计数排序
花O(n)的时间扫描一下整个序列 A,获取最小值 min 和最大值 max
开辟一块新的空间创建新的数组 B,长度为 ( max - min + 1)
数组 B 中 index 的元素记录的值是 A 中某元素出现的次数
最后输出目标整数序列,具体的逻辑是遍历数组 B,输出相应元素以及对应的个数
function countOrder($arr)
{
$max = max($arr);
for($i=0;$i<$max+1;$i++){
$bucket[$i] = 0;
}
foreach($arr as $value){
$bucket[$value]++;
}
$index = 0;
foreach($bucket as $key=>$len){
if($len !== 0){
$res[$index++] = $key;
}
}
return $res;
}
9、桶排序
设置固定数量的空桶。
把数据放到对应的桶中。
对每个不为空的桶中数据进行排序。
拼接不为空的桶中数据,得到结果
function bucketsOrder($arr)
{
$min = min($arr);
$max = max($arr);
$len = count($arr);
$bucketNum = ($max-$min)/$len + 1;//桶的数量
for($i=0;$i<count($arr);$i++){
$bucketsArr[($arr[$i]-$min)/$len][] = $arr[$i];
}
$res = [];
for($i=0;$i<$bucketNum;$i++){//循环桶的数量
$tmp = $bucketsArr[$i];
if(is_array($tmp) && !empty($tmp)){
sort($tmp);
for($j=0;$j<count($tmp);$j++){
$res[] = $tmp[$j];
}
}
}
return $res;
}
function bucketSort($nonSortArray){
//选出桶中最大值和最小值
$min = min($nonSortArray);
$max = max($nonSortArray);
//生成桶,默认每个桶中数据只有0个
$bucket = array_fill($min, $max-$min+1, 0);
//数据入桶
foreach ($nonSortArray as $value){
$bucket[$value]++;//对应桶的个数计增
}
//数据出桶
$sortArray = array();
foreach ($bucket as $k=>$v){
for($i=1;$i<=$v;$i++){
//每个桶中的数据个数
$sortArray[]=$k;
}
}
return $sortArray;
}
10、基数排序
将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零
从最低位开始,依次进行一次排序
从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列
function radixOrder($arr)
{
$max = max($arr);
$loopTimes = strlen($max);
$length = count($arr);
for($i=1;$i<=$loopTimes;$i++){
$counter = [];
$tmpNumber = (int)pow(10,$i-1);
for($j=0;$j<$length;$j++){
$rowIndex = ($arr[$j]/$tmpNumber)%10;
$counter[$rowIndex][] = $arr[$j];
}
$key = 0;
for($j=0;$j<10;$j++){
for($m=0;$m<$length;$m++){
if(!is_null($counter[$j][$m]) && !empty($counter[$j][$m])){
$arr[$key++] = $counter[$j][$m];
}
}
}
}
return $arr;
}
或者
//交换函数
function swap(array &$arr,$a,$b){
$temp = $arr[$a];
$arr[$a] = $arr[$b];
$arr[$b] = $temp;
}
//获取数组中的最大数
//就像上面的例子一样,我们最终是否停止算法不过就是看数组中的最大值:4249,它的位数就是循环的次数
function getMax(array $arr){
$max = 0;
$length = count($arr);
for($i = 0;$i < $length;$i ++){
if($max < $arr[$i]){
$max = $arr[$i];
}
}
return $max;
}
//获取最大数的位数,最大值的位数就是我们分配桶的次数
function getLoopTimes($maxNum){
$count = 1;
$temp = floor($maxNum / 10);
while($temp != 0){
$count ++;
$temp = floor($temp / 10);
}
return $count;
}
/**
* @param array $arr 待排序数组
* @param $loop 第几次循环标识
* 该函数只是完成某一位(个位或十位)上的桶排序
*/
function R_Sort(array &$arr,$loop){
//桶数组,在强类型语言中,这个数组应该声明为[10][count($arr)]
//第一维是 0-9 十个数
//第二维这样定义是因为有可能待排序的数组中的所有数的某一位上的只是一样的,这样就全挤在一个桶里面了
$tempArr = array();
$count = count($arr);
//初始化$tempArr数组
for($i = 0;$i < 10;$i ++){
$tempArr[$i] = array();
}
//求桶的index的除数
//如798个位桶index=(798/1)%10=8
//十位桶index=(798/10)%10=9
//百位桶index=(798/100)%10=7
//$tempNum为上式中的1、10、100
$tempNum = (int)pow(10, $loop - 1);
for($i = 0;$i < $count;$i ++){
//求出某位上的数字
$row_index = ($arr[$i] / $tempNum) % 10;
for($j = 0;$j < $count;$j ++){
if(@$tempArr[$row_index][$j] == NULL){
$tempArr[$row_index][$j] = $arr[$i]; //入桶
break;
}
}
}
//还原回原数组中
$k = 0;
for($i = 0;$i < 10;$i ++){
for($j = 0;$j < $count;$j ++){
if(@$tempArr[$i][$j] != NULL){
$arr[$k ++] = $tempArr[$i][$j]; //出桶
$tempArr[$i][$j] = NULL; //避免下次循环的时候污染数据
}
}
}
}
//最终调用的主函数
function RadixSort(array &$arr){
$max = getMax($arr);
$loop = getLoopTimes($max);
//对每一位进行桶分配(1 表示个位,$loop 表示最高位)
for($i = 1;$i <= $loop;$i ++){
R_Sort($arr,$i);
}
}
或者
function R_Sort(array &$arr,$loop){
$tempArr = array();
$count = count($arr);
for($i = 0;$i < 10;$i ++){
$tempArr[$i] = array();
}
//求桶的index的除数
//如798个位桶index=(798/1)%10=8
//十位桶index=(798/10)%10=9
//百位桶index=(798/100)%10=7
//$tempNum为上式中的1、10、100
$tempNum = (int)pow(10, $loop - 1);
for($i = 0;$i < $count;$i ++){
//求出某位上的数字
$row_index = ($arr[$i] / $tempNum) % 10;
//入桶
array_push($tempArr[$row_index],$arr[$i]);
}
//还原回原数组中
$k = 0;
for($i = 0;$i < 10;$i ++){
//出桶
while(count($tempArr[$i]) > 0){
$arr[$k ++] = array_shift($tempArr[$i]);
}
}
}
原文链接:https://github.com/hustcc/JS-Sorting-Algorithm
https://mp.weixin.qq.com/s/vn3KiV-ez79FmbZ36SX9lg