JavaScript中对数组排序的各种算法整理(面试反思)

排序问题

场景:给你一个数组,请你书写实现排序的函数

方法一:冒泡排序

// 方法一:冒泡排序
	var arr = [1,7,3,8,6,5]
	var temp = 0; // 中间变量temp
	for (var i = 0; i < arr.length; i++){
		for (var j = 0; j < arr.length - i; j++){
			if (arr[j] > arr[j + 1]){
				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
	}
	console.log(array);

在这里插入图片描述
方法二:数组的sort()方法

var arr=new Array(1,8,7,6,2,5);
arr.sort();

在这里插入图片描述 但是需要注意的是sort()数组方法比较的是第一个字符的unicode码

var arr=new Array(1,8,70,61,2,5);
	arr.sort();
	// 输出1,2,5,61,70,8 为什么?

在这里插入图片描述
解决方式

var arr=new Array(1,8,70,61,2,5);
	arr.sort(function(a, b) {
		return a-b;
	});
	// 输出1,2,5,8,61,70
	//  Array.sort()方法允许我们传入一个比较函数进去。如果第一个参数大于第二个参数返回1,如果第一个参数小于第二个参数就返回-1,否则返回0.

在这里插入图片描述
方式三:快速排序算法(递归实现)

算法:利用分治思想,每次定义一个主元(当前选择数组中间项),然后从前后两个方向进行对比和移动,把数据按照基元为中心,分成两份,
后面的为所有大于基于的数,前面的为所有小于基元的数(从小到大排序则相反),然后递归调用,分别再对两侧的数组
进行排序,直到顺序排好为止。
function quickSort(arr){  
  if(arr.length<=1){//如果数组只有一个数,就直接返回;
  // 注意这个十分重要:是递归的结束条件  
    return arr;  
   }  
  // Math.floor() 可以向下取整 Math.ceil()向上取整
  var num=Math.floor(arr.length/2);//找到中间数的索引值,如果是浮点数,则向下取整  
  var newValue=arr.splice(num,1);// arr.splice返回从下标为num开始向后取1个数  
  var left=[],right=[];  
  // 以中间项为中心,对大于中间项和小于中间项的进行分割
  for(var i=0;i<arr.length;i++){  
      if(arr[i]<newValue){  
        left.push(arr[i]);//基准点的左边的数传到左边数组  
      }else{  
        right.push(arr[i]);//基准点的右边的数传到右边数组  
      }  
 }  
 return quickSort(left).concat(newValue,quickSort(right));//递归不断重复比较 
 // 上述代码解释为:对原数组左边依次进行以中间值分开  对原数组右侧依次以中间值分开
 // 递归持续调用
 // 最后返回数组用concat连接 
}  
console.log(quickSort([4,10,25,52,13,80])); 

在这里插入图片描述
方法四:插入排序算法

算法描述
一般来说,插入排序都采用 in-place 在数组上实现:

从第一个元素开始,该元素可以认为已经被排序;
取出下一个元素,在已经排序的元素序列中**从后向前**扫描;
如果该元素(已排序)大于新元素,将该元素移到下一位置;
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
将新元素插入到该位置后;
重复步骤2~5。

在这里插入图片描述

function Insertion(arr) {
  let preIndex, current;
  for (let i = 1; i < arr.length; i++) {
    preIndex = i - 1; // preIndex前一项下标
    current = arr[i]; // current变量 保存当前项
    // while循环 执行的是当前项从后向前依次比较
    while (preIndex >= 0 && current < arr[preIndex]) {
      arr[preIndex + 1] = arr[preIndex];
      preIndex--;
    }
    arr[preIndex + 1] = current;
  }
  return arr;
}
var arr = [3,5,7,1,4,56,12,78,25,0,9,8,42,37];
Insertion(arr);

在这里插入图片描述

方法五:希尔排序算法(希尔排序又叫缩小增量排序)

其工作原理是定义一个间隔序列来表示排序过程中进行比较的元素之间有多远的间隔,
每次将具有相同间隔的数分为一组,进行插入排序,大部分场景中,
间隔是可以提前定义好的,也可以动态生成。
**希尔排序的实质就是分组的插入排序**

在这里插入图片描述

	function shellSort(nums){//希尔排序
        var gaps=[5,3,1];//定义间隔区间
        for(var g=0;g<gaps.length;g++){//一个一个间隔值开始
            for(var i=gaps[g];i<nums.length;i++){//以间隔值遍历
                var temp=nums[i];//选中元素
                for(var j=i;j>=gaps[g]&&nums[j-gaps[g]]>temp;j-=gaps[g]){
                // 如果前面一个大于后面一个
                // 注意   nums[j-gaps[g]]保证了隔项比较
                    nums[j]=nums[j-gaps[g]];//后移
                }
                nums[j]=temp;//填补
            }
        }
    }
    var nums=[1,23,43,24,54,61,37,86,79];
    shellSort(nums);//希尔排序

在这里插入图片描述
方法六:选择排序算法

选择排序(Selection-sort)是一种简单直观的排序算法。
它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
缺点:表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。

在这里插入图片描述

function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp; // 最小值变量 中间变量
    for(var i = 0; i < len - 1; i++) {
        minIndex = i;
        for(var j = i + 1; j < len; j++) {
            if(arr[j] < arr[minIndex]) {     // 寻找最小的数
                minIndex = j;                 // 将最小数的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
} 
arr=[2,3,54,21,24,224,76]
selectionSort(arr) // 2, 3, 21, 24, 54, 76, 224

在这里插入图片描述
方法七:归并排序算法

归并排序是建立在归并操作上的一种有效的排序算法。
该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;
即先使每个子序列有序,再使子序列段间有序。
若将两个有序表合并成一个有序表,称为2-路归并。 
算法描述
把长度为n的输入序列分成两个长度为n/2的子序列;
对这两个子序列分别采用归并排序;
将两个排序好的子序列合并成一个最终的排序序列。
归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,
但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。

在这里插入图片描述

// 实现分割
function mergeSort(arr) {
    varlen = arr.length;
    if(len < 2) {
        return arr;
    }
    var middle = Math.floor(len / 2),
    	// arr.slice 字符串分割 根据中间项分割成两部分
         left = arr.slice(0, middle),
         right = arr.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}
 // 实现依次排列
function merge(left, right) {
    var result = [];
 	// 结合shift方法仔细思考你就会知道这里是 依次删除每一项 同时从小到大依次添加到result中
    while(left.length>0 && right.length>0) {
        if(left[0] <= right[0]) {
          // shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
            result.push(left.shift());
        } else{
            result.push(right.shift());
        }
    }
 
    while(left.length)
        result.push(left.shift());
        // shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
 
    while(right.length)
        result.push(right.shift());
 
    return result;
}

ps

这个是自己的亲身面试经历,当时就说出了冒泡排序和sort()方法,而且眼高手低,说的出来,在纸上写就有些卡壳,面试官问我还有其他算法可以实现不?我回答不上来,回家特地查找资料进行对排序算法以及注意事项进行了总结,一些不好理解的地方进行了补充说明,求个赞哈。
参考博客链接有:
排序的方法总结:https://www.cnblogs.com/ting6/p/9725529.html
插入排序算法:https://www.cnblogs.com/cc-freiheit/p/10983395.html
十大经典排序算法:https://www.cnblogs.com/onepixel/articles/7674659.html#3%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8Finsertion-sort

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值