让我们来写写排序算法(javaScript)吧!

1,156 阅读4分钟

1. 冒泡排序

定义

重复地走访要排序的数列,一次比较两个元素,如果他们的顺序有变化就交换过来。冒泡排序是一种稳定排序,值相等的元素不会打乱原本的顺序。由于该排序算法每一轮都有遍历所有的元素,总共遍历(元素数量-1)轮,所以平均时间复杂度是O(n^2)。

实现步骤

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个的大小;
  2. 对每一个相邻元素做同样的工作,从开始第一队到结尾的最后一对。这步做完后,最后的元素会是最大的数;
  3. 针对所有的元素重复以上的步骤,除了最后一个;
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

实现代码

const bubbleSort = function (arr) {
  // 控制行数
  for (let i = 0; i < arr.length - 1; i++) {
    // 是否排序,默认已经排序
    let isSort = true;
    for (let j = 0; j < arr.length - 1 - i; j++) {
      // 如果当前值比后一个大,就进行两两交换大小
      if (arr[j] > arr[j + 1]) {
        // 利用数组解构进行交换
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
        // 设置排序标志为未排序
        isSort = false
      }
    }
    // 如果已经排序完了,就中断循环
    if (isSort) {
      break;
    }
  }
  return arr;
}

2. 插入排序

定义

不断地将尚未排好序的数插入到已经排好序的部分。平均时间复杂度是O(n^2)

实现步骤

  1. 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列;
  2. 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。

实现代码

const insertSort = function(arr) {
    // 设置第一项是已经排好序的,开始变量之后的元素
    for(let i = 1; i < arr.length; i++) {
        let preIndex = i - 1;
        const current = arr[i]
        // 遍历前面已经排好序的数组,从后往前遍历
        while(preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex + 1] = arr[preIndex]
            preIndex--
        }
        // 设置要插入的数组位置值
        arr[preIndex+1] = current
    }
    return arr
}

冒泡排序是找到最大或最小值依次放在右边;插入排序是找到最大或最小值依次放在左边

3. 选择排序

定义

每次找出最小的元素依次最前面

实现步骤

  1. 首先在未排序的数组中找出最小的元素,放在数组的第一个元素位置;
  2. 再从剩余的位置中继续寻找最小的元素,然后放在已排序的末尾位置;
  3. 重复第2个步骤,直到所有的元素均排序完成。

实现代码

const selectSort = function(arr) {
    // 已排序末尾位置记录
    let pos = 0;
    // 已排序数组循环
    while(pos < arr.length - 1) {
        // 存放本次循环当前最小元素的索引
        let index = pos
        // 循环未排序数组
         for(let i = pos + 1; i < arr.length; i++ ) {
           if (arr[i] < arr[index]) {
               // 存储本轮最小元素的索引
               index = i
           }
        }
        // 数组结构方式交换位置
        [arr[pos], arr[index]] = [arr[index], arr[pos]]
        // 更新下次已排序位置
        pos += 1 
    }
    return arr
   
}

4. 快速排序

定义

采用了分治的思想,把原始数组筛选成较大和较小的两个子数组,然后递归地排序两个子数组

实现步骤

  1. 从数组中挑选一个元素,作为基准元素;
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边);
  3. 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。

实现代码

const quickSort = function(arr){
    // 终止条件
    if (arr.length < 2) {
        return arr.slice()
    }
    // 基准值
    let pivot = arr[Math.floor(Math.random() * arr.length)]
    let left = [], mid = [], right = [];
    for (let i = 0; i < arr.length; i++) {
        const value = arr[i]
        // 比基准值小的放在左边
        if (value < pivot) {
            left.push(value)
        } else if (value === pivot) {
            mid.push(value)
        } else {
        // 比基准值大的放在右边
            right.push(value)
        }
    }
    // 继续递归的找出左边和右边数组中排序值
    return quickSort(left).concat(mid, quickSort(right))
    
}

5. 归并排序

定义

把数组从中间划分成两个子数组;一直递归地把子数组划分成更小的子数组,直到子数组里面只有一个元素。

实现步骤

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。

实现代码

function mergeSort(arr) {  // 采用自上而下的递归方法
    var len = arr.length;
    if(len < 2) {
        return arr;
    }
    // 取中间位置
    var middle = Math.floor(len / 2),
        // 划分两个数组
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    // 递归划分数组,然后合并数组
    return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right)
{
    var result = [];

    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }

    while (left.length)
        result.push(left.shift());

    while (right.length)
        result.push(right.shift());

    return result;
}