玩转经典排序算法

351 阅读2分钟

排序算法是非常常见的面试题, 有了这个, 再也不怕啦

1. 冒泡排序

相邻元素两两比较,大的数字往后排序

    function bubble(arr) {
      let flag = false; // 提交结束冒泡的标识
      if (arr.length < 2) return arr;
      for (let i = 0; i < arr.length; i++) {
        flag = false; // 循环内的标识
        for (let j = 0; j < arr.length - 1 - i; j++) {
          // 从0开始, 到length-1-i结束
          if (arr[j] > arr[j + 1]) {
            const temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
            flag = true; // 表示进行了数据交换
          }
        }
         if (!flag) break; // 如果没有进行数据交换, 表示已经排序完成, 跳出循环
      }
      console.log("arr", arr);
      return arr;
    }
    // bubble([1, 4, 3, 4, 5, 6, 3, 2, 21, 2]);

2. 插入排序

拿到一个元素, 和前面的所有元素对比, 只要比他大就交换位置.

    function insert(arr) {
      let len = arr.length;
      if (len < 2) {
        return arr;
      }
      let cur, pre;
      for (var i = 1; i < len; i++) {
        // 从1开始, len结束
        cur = arr[i];
        pre = i - 1;
        while (pre >= 0 && cur < arr[pre]) {
          arr[pre + 1] = arr[pre];
          pre--;
        }
        arr[pre + 1] = cur;
      }
      console.log("arr", arr);

      return arr;
    }
    // insert([1, 4, 3, 4, 5, 6, 3, 2, 21, 2]);

3.选择排序

最小的元素放在起始位置, 再从剩下的未排序的数组选最小值, 放在已经排序的后面. 每次找到最小值放在已经排序的数组后面

    function select(arr) {
      let len = arr.length;
      let minIndex, temp;
      for (let i = 0; i < arr.length - 1; i++) {
        minIndex = i; // 定义最小元素的索引
        for (let j = i + 1; j < arr.length; j++) {
          if (arr[minIndex] > arr[j]) {
            minIndex = j; // 找到剩余数组中的最小值的索引, 赋值给minIndex
          }
        }
        // 交换当前arr[i]和arr[minIndex]的位置
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
      }
      console.log(arr);
      return arr;
    }
    // select([1, 4, 3, 4, 5, 6, 3, 2, 21, 2]);

4. 归并排序

  • 分治算法 递归 先处理子问题 再合并
  • 先把数组分成两部分 递归进行排序
    function mergeSort(arr) {
   // 具体排序逻辑
   function merge(left, right) {
     const result = [];
     let i = 0, // 初始化i,j 的值
       j = 0;
     // 如果i,j都分别小于对应的数组长度, result的值为两个数组中对应的i,j的最小值
     while (i < left.length && j < right.length) {
       if (left[i] < right[j]) {
         result.push(left[i++]);
       } else {
         result.push(right[j++]);
       }
     }
     while (i < left.length) {
       result.push(left[i++]);
     }
     while (j < right.length) {
       result.push(right[j++]);
     }
     return result;
   }
   // 根据中间数, 分割数组成两部分
   function sort(arr) {
     if (arr.length === 1) return arr;
     const middle = Math.floor(arr.length / 2);
     const left = arr.slice(0, middle);
     const right = arr.slice(middle, arr.length);
     // merge 函数递归
     return merge(mergeSort(left), mergeSort(right));
   }

   return sort(arr);
 }

5. 快速排序

根据一个基准, 比基准小的数放在左边, 大的数放在右边. 根据这个规则,递归左右的两个数组

    function quickSort(arr) {
    // 具体逻辑
    function quick(arr) {
      if (arr.length <= 1) return arr;
      const baseIndex = Math.floor(arr.length >> 1); // 找到基准点的索引
      const base = arr.splice(baseIndex, 1)[0]; // 找到基准点, arr去掉这个数
      const left = [],
        right = [];
      for (let i = 0; i < arr.length; i++) {
        if (arr[i] > base) {
          right.push(arr[i]);
        } else {
          left.push(arr[i]);
        }
      }
      return quick(left).concat([base], quick(right)); // 递归去找, 直到arr.length<=1 退出循环
    }
    let result = quick(arr);
    return result;
  }
  let result = quickSort([1, 4, 3, 4, 5, 6, 3, 2, 21, 2]);
  console.log(result, "result");

6.堆排序

  • 堆是一种特殊的树,满足以下两点就是堆:
  • 堆是一个完全二叉树
  • 堆中每一个节点的值都必须大于等于(或小于等于)其子树中的每个节点的值
  • 堆如果用一个数组表示的话,给定一个节点的下标 i (i从1开始),那么它的父节点一定为 A[i / 2],左子节点为 A[2i],右子节点为 A[2i + 1]

  function heapSort(arr) {
    buildTop(arr, arr.length - 1);
    let size = arr.length - 1;
    for (let i = size; i > 1; i--) {
      swap(arr, i, 1);
      size--;
      heapify(arr, size, 1);
    }
    return arr;
  }
  // 构建大顶堆
  function buildTop(arr, size) {
    for (let i = Math.floor(size / 2); i >= 1; i--) {
      heapify(arr, size, i);
    }
  }
  // 堆化
  function heapify(arr, size, i) {
    while (true) {
      let maxIndex = i;
      if (2 * i <= size && arr[i] < arr[i * 2]) {
        maxIndex = i * 2;
      }
      if (2 * i + 1 <= size && arr[maxIndex] < arr[i * 2 + 1]) {
        maxIndex = i * 2 + 1;
      }
      if (maxIndex === i) {
        break;
      }
      swap(arr, maxIndex, i);
      i = maxIndex;
    }
  }
  // 交换工具函数
  function swap(arr, i, j) {
    let temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }
  // let result = heapSort([1, 4, 3, 4, 5, 6, 3, 2, 21, 2]);
  // console.log(result, "result");

六种排序算法的时间和空间复杂度及稳定比较

avatar