【算法】经典排序算法总结-JavaScript描述-图解-复杂度分析

已经有很多排序算法的文章了,这里主要是做一个自己的总结。
内容大部分整合自《算法第四版》,图示大部分来自菜鸟教程网。语言选择的当然是JavaScript啦~
代码可以直接在LeetCode的912.排序数组题目上运行

在此之前先定义一个交换数组中两个元素的函数

function swap(arr, i, j) {
   
  let temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

1. 冒泡排序 (简单)

流程

  • 比较相邻的元素。如果前者大于后者就交换
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数
  • 针对所有的元素重复以上的步骤,除了最后一个
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

图示

在这里插入图片描述

代码

参考代码1

/**
 * @param {number[]} nums
 * @return {number[]}
 */
 var sortArray = function (nums) {
   
  for (let i = 0; i < nums.length; i++) {
   
    for (let j = 0; j < nums.length - i -1; j++) {
   
      if (nums[j] > nums[j + 1]) {
   
        swap(nums, j, j + 1);
      }
    }
  }
  return nums;
};

参考代码2 优化冒泡排序

/**
 * @param {number[]} nums
 * @return {number[]}
 */
 var sortArray = function (nums) {
   
  for (let i = 0; i < nums.length; i++) {
   
    let flag = true;
    for (let j = 0; j < nums.length - i -1; j++) {
   
      if (nums[j] > nums[j + 1]) {
   
		swap(nums, j, j + 1);
        flag = false;
      }
    }
    if(flag) {
   
      return;
    }
  }
  return nums;
};

复杂度分析

时间复杂度: O ( N 2 ) O(N^2) O(N2),这里 N N N是数组的长度;
空间复杂度: O ( 1 ) O(1) O(1),使用到常数个临时变量。

2. 选择排序(简单)

一种最简单的排序算法:首先找到数组中最小的元素,将它和数组中的第一个元素交换位置,然后在剩下的元素中找到最小的,与第二个元素交换位置,直到整个数组排序。(不断选择剩余数组中最小的元素)

流程

  1. 首先在未排序序列中找到最小元素,存放到排序序列的起始位置
  2. 再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾
  3. 重复第二步,直到所有元素均排序完毕

图示

在这里插入图片描述

代码

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArray = function (nums) {
   
  for (let i = 0; i < nums.length; i++) {
   
    let min = i;
    // 已排序区间 [0, i) ,未排序区间 [i+1 , len)
    // 遍历 i+1 之后的元素找到最小元素的索引
    for (let j = i + 1; j < nums.length; j++) {
   
      if (nums[j] < nums[min]) {
   
        min = j;
      }
    }
    swap(nums, i, min);
  }
  return nums;
};

复杂度分析

  • 对于长度为N的数组,选择排序需要大约 N 2 / 2 N^2/2 N2/2次比较和 N N N次交换。
  • 有两个特点:①运行时间和输入无关 ②数据移动是最少的,交换次数和数组的大小是线性关系

时间复杂度: O ( N 2 ) O(N^2) O(N2),这里 N N N 是数组的长度;
空间复杂度: O ( 1 ) O(1) O(1),使用到常数个临时变量。

3. 插入排序(重点)

流程

每次将一个数字插入一个有序的数组里,成为一个长度更长的有序数组,有限次操作以后,数组整体有序

图示

在这里插入图片描述

代码

参考代码1(交换元素)(算法第四版的思路)

/**
 * 插入排序
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArray = function (nums) {
   
  // 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
  // 已排序区间 [0, i) ,未排序区间 [i , len)

  // 将 nums[i] 插入到区间 [0, i) 使之成为有序数组
  for (let i = 1; i < nums.length; i++) {
   
    // 从右往左遍历
    for (let j = i; j > 0 && nums[j] < nums[j - 1]; j--) {
   
      // 只要nums[j]比前一个元素nums[j-1]小,就交换这两个元素
      swap(nums, j, j - 1);
    }
  }
  return nums;
};

参考代码2(移动元素)

/**
 * 插入排序
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArray = function (nums) {
   
  for (let i = 1; i < nums.length; i++) {
   
    // 已排序区间 [0, i) ,未排序区间 [i , len)
    // 将 nums[i] 插入到区间 [0, i) 使之成为有序数组

    // 先暂存这个元素,然后之前元素逐个后移,留出空位
    let temp = nums[i];
	let j = i;
    while(j > 0 && temp < nums[j - 1]) {
   
      // 只要nums[j]比前一个元素nums[j-1]小,将nums[j-1]移动到nums[j]
      nums[j] = nums[j - 1];
      j--;
    }
    
    // 找到位置j,将i的值放在j上
    nums[j] = temp;
  }
  return nums;
};

复杂度分析

插入排序对部分有序的数组和“短数组”很有效

时间复杂度: O ( N 2 ) O(N^2) O(N<

  • 18
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值