js常见算法及算法思想-排序

目录

1.冒泡排序

2.选择排序

3.插入排序

4.归并排序

5.快速排序


把某个乱序的数组变成升序序或者降序的数组, js比较常用sort方法进行排序

1.冒泡排序

  • 比较所有相邻元素,如果第一个比第二个大就交换他们

  • 执行一次后可以保证最后一个数字是最大的

  • 重复执行 n-1 次,就可以完成排序

// 时间复杂度 O(n ^ 2) n为数组长度
// 空间复杂度 O(1)
Array.prototype.bubbleSort = function () {
  for (i = 0; i < this.length - 1; i++) {
    for (let j = 0; j < this.length - 1 - i; j++) {
      if (this[j] > this[j + 1]) {
      
        // 交换数据
        [this[j], this[j + 1]] = [this[j + 1], this[j]];
      }
    }
  }
}

2.选择排序

  • 找到数组中最小的值,选中它并放到第一位

  • 接着找到数组中第二小的值,选中它并放到第二位

  • 重复上述步骤执行 n-1 次

// 时间复杂度:O(n ^ 2) n为数组长度
// 空间复杂度:O(1)
Array.prototype.selectionSort = function () {
  for (let i = 0; i < this.length - 1; i++) {
    let indexMin = i;

    for (let j = i; j < this.length; j++) {

      // 如果当前这个元素 小于最小值的下标 就更新最小值的下标
      if (this[j] < this[indexMin]) {
        indexMin = j;
      }
    }

    // 避免自己和自己进行交换
    if (indexMin !== i) {

      // 进行交换数据
      [this[i], this[indexMin]] = [this[indexMin], this[i]];
    }
  }
}

3.插入排序

  • 从第二个数,开始往前比较

  • 它大就往后排

  • 以此类推进行到最后一个数

// 时间复杂度 O(n ^ 2)
Array.prototype.insertionSort = function () {

  // 遍历数组 从第二个开始
  for (let i = 1; i < this.length; i++) {

    // 获取第二个元素
    const temp = this[i];

    let j = i;
    while (j > 0) {

      // 如果当前元素小于前一个元素 就开始往后移动
      if (this[j - 1] > temp) {
        this[j] = this[j - 1];
      } else {

        // 否则就跳出循环
        break
      }

      // 递减
      j--;
    }

    // 前一位置赋值为当前元素
    this[j] = temp;
  }
}

4.归并排序

  • 分:把数组劈成两半 在递归的对子数组进行分操作,直到分成一个个单独的数

  • 合:把两个树合并为有序数组,再对有序数组进行合并, 直到全部子数组合并为一个完整的数组

// 时间复杂度 O(nlogn) 分需要劈开数组,所以是logn, 合则是n
// 空间复杂度 O(n)
Array.prototype.mergeSort = function () {

  const rec = (arr) => {
    // 递归终点
    if (arr.length === 1) return arr

    // 获取中间索引
    const mid = arr.length >> 1;

    // 通过中间下标,进行分割数组
    const left = arr.slice(0, mid);
    const right = arr.slice(mid);

    // 左边和右边的数组进行递归,会得到有序的左数组,和有序的右数组
    const orderLeft = rec(left);
    const orderRight = rec(right);


    // 存放结果的数组
    const res = [];

  
    while (orderLeft.length || orderRight.length) {

      // 如左边和右边数组都有值
      if (orderLeft.length && orderRight.length) {

        // 左边队头的值小于右边队头的值 就左边队头出队,否则就是右边队头出队
        res.push(orderLeft[0] < orderRight[0] ? orderLeft.shift() : orderRight.shift())
      } else if (orderLeft.length) {

        // 把左边的队头放入数组
        res.push(orderLeft.shift())
      } else if (orderRight.length) {

        // 把右边的队头放入数组
        res.push(orderRight.shift())
      }
    }

    return res
  }

  const res = rec(this)

  // 把结果放入原数组
  res.forEach((n, i) => this[i] = n)
}

合并两个有序链表:

// 时间复杂度O(n) n为链表1和链表2的长度之和
// 空间复杂度O(1)
var mergeTwoLists = function (list1, list2) {

  // 新建一个新链表 作为返回值
  const res = {
    val: 0,
    next: null
  }

  // 指向新链表的指针
  let p = res;

  // 建立两个指针
  let p1 = list1;
  let p2 = list2;


  // 遍历两个链表
  while (p1 && p2) {

    // 如果链表1 小于 链表2的值 就接入链表1的值
    if (p1.val < p2.val) {
      p.next = p1;

      // 需要往后移动
      p1 = p1.next;
    } else {

      // 否则接入链表2的值
      p.next = p2;

      // 需要往后移动
      p2 = p2.next;
    }

    // p永远要往后移动一位
    p = p.next;
  }

  // 如果链表1或者链表2还有值,就把后面的值全部接入新链表
  if (p1) {
    p.next = p1;
  }
  if (p2) {
    p.next = p2;
  }

  return res.next;
};

5.快速排序

  • 分区:从数组中任意选择一个 基准, 所有比基准小的元素放在基准前面比基准大的元素放在基准后面

  • 递归: 递归的对基准前后的子数组进行分区

// 时间复杂度 O(nlogN)
// 空间复杂度 O(1)
Array.prototype.quickSort = function () {
  const rec = (arr) => {
  
    // 如果数组长度小于等于1 就不用排序了
    if (arr.length <= 1) { return arr }

    // 存放基准前后的数组
    const left = [];
    const right = [];

    // 取基准
    const mid = arr[0];

    for (let i = 1; i < arr.length; i++) {

      // 如果当前值小于基准就放到基准前数组里面
      if (arr[i] < mid) {
        left.push(arr[i]);
      } else {

        // 否则就放到基准后数组里面
        right.push(arr[i]);
      }
    }

    // 递归调用两边的子数组
    return [...rec(left), mid, ...rec(right)];
  };

  const res = rec(this);
  res.forEach((n, i) => this[i] = n);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值