排序算法

99 阅读2分钟

排序算法:

常见排序算法时间复杂度

image.png

常见排序算法

冒泡排序:时间复杂度O(n^2)

  • 比较相邻元素,如果第一个比第二个大,则交换他们
  • 一轮下来,可以保证最后一个数是最大的
  • 执行n-1轮,就可以完成排序
 function bubbleSort(arr) {
      const len = arr.length;
      //判断一趟比较中元素是否发生交换
      let flag = false;
      //外层循环代表需要比较几趟(比较length趟)
      for (let i = 0; i < len; i++) {
        //内层循环用于控制每一趟比较的次数,比较了i次,说明最后i个元素已有序无序需比较
        for (let j = 0; j < len - 1 - i; j++) {
          if (arr[j] > arr[j + 1]) {
            [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
            //如果一次都没交换则说明有序(flag=false)
            flag = true;
          }
        }
        if (!flag) {
          console.log(flag);
          return arr;
        }
      }
      return arr;
    }
    let arr1 = [1, 2, 3, 4];
    let arr2 = [5, 2, 1, 4];
    res1 = bubbleSort(arr1);
    res2 = bubbleSort(arr2);
    console.log(res1);
    console.log(res2);

选择排序:时间复杂度O(n^2)

  • 找到数组中的最小值,将它放在第一位
  • 接着找到第二小的值,将它放在第二位
  • 依次类推,执行n-1轮
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;
}

插入排序:时间复杂度O(n^2)

  • 从第二个数开始往前比
  • 每次比较前保证前面的元素有序,
  • 然后每次从后向前比较, 比它大就往后排。
function insertionSort(arr) {
    var len = arr.length;
    var preIndex, current;
    for (var i = 1; i < len; i++) {
        preIndex = i - 1;
        current = arr[i];
        while(preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex+1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex+1] = current;
    }
    return arr;
}

快速排序时间复杂度O(nlogn)

  • 分区:从数组中选一个基准值,比基准值小的放在它的前面,比基准值大的放在它的后面
  • 递归:递归对基准值前后的子数组进行第一步的操作
//每次以中点为基准值,比基准值小放入leftArr,大放到rightArr,然后分别对左右数组进行取基准值放入对应数组的操作,递归结束这些基准值的位置都有序了,再按序拼接合并;也就是先分治后合并。
const quickSort = (arr) => {
      const len = arr.length;
      if (len <= 1) return arr;
      const midIndex = Math.floor(len / 2);
      const leftArr = [];
      const rightArr = [];
      //取出基准值(小 --》 基准值 --》大)
      const midValue = arr.splice(midIndex, 1);
      let index = 0;
      //遍历数组,将元素放到适合他的子数组中
      while (index < len - 1) {
        if (arr[index] < midValue) {
          leftArr.push(arr[index]);
        } else {
          rightArr.push(arr[index]);
        }
        index++;
      }
      return quickSort(leftArr).concat(midValue).concat(quickSort(rightArr));
    };
    const arr = [3, 5, 1, 2];
    const res = quickSort(arr);
    console.log(res);

归并排序:时间复杂度O(nlogn)

分的时间复杂度O(logn),合并的过程的复杂度是O(n)

  • 分:把数组分成两半,递归子数组,进行分割操作,直到分成一个数
  • 合:把两个子数组合并成一个有序数组,直到全部子数组合并完毕,合并前先准备一个空数组,存放合并之后的结果,然后不断取出两个子数组的第一个元素,比较他们的大小,小的先进入之前准备的空数组中,然后继续遍历其他元素,直到子数组中的元素都完成遍历
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;
}
console.log(mergeSort([3, 2, 2, 13, 4, 2, 1]));