js 排序

126 阅读5分钟

一、冒泡排序 bubble sort

思想:

让数组中的当前项和后一项进行比较,如果当前项比后一项大,则两项交换位置(让大的靠后)即可。

var arr=[12,8,24,16,1];

12>8  位置交换   [8,12,24,16,1]   第二轮:   8<12  不交换 [8,12,16,1,24]    ......
12<24 不交换位置 [8,12,24,16,1]             12<16 不交换 [8,12,16,1,24]
24<16 位置交换   [8,12,16,24,1]             16>1  交换   [8,12,1,16,24] 
24<1  位置交换   [8,12,16,1,24]
最多比较length-1次(不用和自己比)          每一轮比较都把当前最大的放到了末尾,所以当前轮比较多少次,需要把之前放到末尾的值也得去掉

第一轮完成后,虽然没有实现最后的结果,但是当前数组中最大的这个值24放到了末尾,

第二轮比较:不用再和24比较了,而且本轮结束剩余值中最大的16也放到末尾。

 /* 冒泡排序 */   
/*    
*bubble:实现冒泡排序   
* @params arr [ARRAY] 需要排序的数组   
* @return [ARRAY] 排序后的新数组    
*/   
 function bubble(arr) {        
   let temp = null;       
     //外层循环I控制比较的轮数            
   for (let i = 0; i < arr.length - 1; i++) {            
     //里层循环控制每一轮比较的次数                    
    for (let j = 0; j < arr.length - 1 - i; j++) {                
     //如果当前项大于后一项                           
       if (arr[j] > arr[j + 1]) {                   
      //1、交换值                                    
      // temp =arr[j+1]                                    
     // arr[j+1] = arr[j]                                    
     // arr[j]=temp;                                    
    //2、使用解构赋值                                    
     [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]                
     }            
   }        
  }        
  return arr;   
 }    
bubble([5, 7, 2, 4])    // [2, 4, 5, 7]

二、插入排序 Insert sort

思想:

就好比玩牌,在抓牌的时候一边抓牌一边排序,让新抓的牌和手里的牌比较

var arr=[12,8,24,16,1];

只要会打牌,就会插入排序:(抓牌并整理牌的过程)
左手  开始先抓一张牌过来
12    继续抓牌,抓到这样的牌和手里的牌依次比较(个人习惯从后向前比)
      如果当前新牌A比手里的某张牌B大,则把A放到B的后面,如果小则继续向前面的牌比较
      前提: 如果已经比较到第一张牌,则把当前牌A插入到最前面即可
8 12
8 12 24
8 12 16 24

稳定性 和 范围:

比较稳定的一种算法;

不适合数量特别大的排序,量级小千

/* 插入排序 */

    /*        
     *insert:实现插入排序       
     * @params arr [ARRAY] 需要排序的数组       
    * * @return [ARRAY] 排序后的新数组        
   * */    
function insert(arr) {        
//准备一个新数组,用来存储抓到手里的牌,开始先抓一张进来               
  let handle = [];        
  handle.push(arr[0]);        
// 从第二项开始依次抓牌,一直到把台面上的牌抓光               
for (let i = 1; i < arr.length; i++) {            
 //A是新抓牌                        
 let A = arr[i];            
 //和handle手中里的牌进行比较(从后向前比)                        
  for (let j = handle.length - 1; j >= 0; j--) {                
    //每一次要比较的手里的牌                                
    let B = handle[j];                
   //如果当前新牌A比要比较的牌B大,把A放到B的后面                               
     if (A > B) {                    
     //想要把A放到B的后面,j必须加1,否则是放到了B的前面,这是splice的特性;
      handle.splice(j + 1, 0, A);                    
      break;                
     }                
   //如果已经比较到第一项,就直接把新牌A放到最前即可                               
    if (j === 0) {                   
     handle.unshift(A);                
    }            
   }        
  }        
return handle;    
}    
insert([12, 8, 24, 16, 1])

三、快速排序 quick sort

思想:

找到中间项,让拿出来的每一项和中间项继续比较,比中间项小的放到左边,比他大的放到右边,用递归的方式将左右数组排好,最后将左边+中间+右边。

稳定性 和 范围:

不是很稳定。

擅长处理大数据。

快速排序又称为划分交换排序,以分治法为策略实现的快速排序算法。

var arr=[12,8,15,24,16,1];

左边数组                    中间项           右边数组
12 8  1                        15              16 24
每一次继续不断的重复操作(递归)
1 8 12                                           16 24

递归:函数执行的时候自己调用自己

/* 快速排序 */    
/*         
*quick:实现快速排序        
* @params arr [ARRAY] 需要排序的数组        
* @return [ARRAY] 排序后的新数组        
*      
* */    
function quick(arr) {        
//结束递归                
if (arr.length <= 1) {           
 return arr;        }        
//找到数组的中间项,在原数组的数组红把它移除                
let middleIndex = Math.floor(arr.length / 2);        
let middleValue = arr.splice(middleIndex, 1)[0];        
// arr.splice(middleIndex,1)取出后是数组,所以得取第一个[0]                
//准备左右两个数组,循环剩下的数组中的每一项,比较当前项下的放到左边数组中,反之放到右边数组中                
let leftArr = [],           
rightArr = [];        
for (let i = 0; i < arr.length; i++) {            
let item = arr[i];            
item < middleValue ? leftArr.push(item) : rightArr.push(item);        
}        
//递归方式让左右两边的数组持续这样处理,一直到左右两边都排好序位置        
//(最后左边+中间+右边排好的数组)               
 return quick(leftArr).concat(middleValue, quick(rightArr));   
}    
let arr = [12, 8, 15, 24, 16, 1];    
quick(arr); //[1, 8, 12, 15, 16, 24]


四、sort 排序

思路:

使用sort() 函数进行排序。

 let arr=[12, 8, 15, 24, 16, 1];

let arr=[12, 8, 15, 24, 16, 1];
arr.sort((a,b)=>a-b); //[1, 8, 12, 15, 16, 24]

// 倒序
arr.sort((a,b)=> b-a);
// [24, 16, 15, 12, 8, 1]

五、归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

思路:

  • 归并排序的过程是首先用递归的方法把大数组分割成只包含1个元素的小数组。
  • 再用递归的方法,将每个小数组合并并排序。
  • 归并排序使用的是分治法。
  • FireFox使用归并排序作为sort方法的实现。

思路理解:

归并排序其实可以类比二分法,二分法其实就是二等分的意思,简而言之就是不断和新序列的中间值进行比较。归并排序似乎有异曲同工之妙,什么意思呢,就是将一个原始序对等分为两部分,然后不断地对等分新的序列,直至序列的长度为1或者2,那么想,如果一个序列为1,那就没有比较的意义了,它本身就是之最,如果是两个呢,那直接比较不就完了,把比较之后的值推送到一个新的数组。就这样不断地细分,不断的产生子序列,然后把穿产生的新序列作为新的父序列,然后同等级的父序列再比较产生新的祖序列,依次类推。

稳定性和适用范围:

归并排序是稳定的排序算法。

归并排序适合数据量较大的情况,如几百万个数据。

归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间

实现:

function mergeSort(arr){        
if (arr.length > 1) {            
let mid = Math.floor(arr.length / 2)            
let left = mergeSort(arr.slice(0, mid))            
let right = mergeSort(arr.slice(mid))            
arr = merge(left, right)        
}        
return arr    
}    
function merge(left, right) {        
let res = []        
let index1 = 0        
let index2 = 0        
while (index1 < left.length && index2 < right.length) {           
 if (left[index1] < right[index2]) {              
  res.push(left[index1++])         
   } else {              
  res.push(right[index2++])          
  }       
 }        
  return res.concat(index1 < left.length ? left.slice(index1) : right.slice(index2)) 
}   
 var arry = [12, 8, 24, 16, 1]    
mergeSort(arry)    // [1, 8, 12, 16, 24]

** 学习总结;

 排序方法有多重选择合适的即可

用于学习记录,如有问题,欢迎指出