放肆青春的博客
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)

放肆青春

一个前端菜鸟的技术成长之路
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)
  • 算法基础

    • 数据结构和算法
    • 算法blog
    • 算法基础
    • 算法思维
  • 算法汇总

    • 常见算法题
    • 穷举算法(枚举算法)
    • 递归
    • 二分法
    • 双指针

      • 双指针
      • 双指针算法题
      • 滑动窗口
      • 滑动窗口算法题
    • 回溯法

      • 回溯法
      • 回溯法算法题
    • 分治算法
    • 贪心算法

      • 贪心算法
      • 贪心算法题
    • 动态规划

      • 动态规划
      • 动态规划算法题
  • 排序算法

    • 排序算法
    • 1. 冒泡排序
      • 冒泡排序简介
        • 稳定性
        • 流程:
        • 演示图:
      • 冒泡排序代码实现
        • 最简单的冒泡排序
        • 优化 1:检查某次内层遍历是否发生交换
        • 优化 2:记录内层遍历最后一次发生交换的位置
        • 优化 3:双向冒泡排序
    • 2. 选择排序
    • 3. 插入排序
    • 4. 希尔排序
    • 5. 归并排序
    • 6. 快速排序
    • 7. 堆排序
    • 8. 计数排序
    • 9. 桶排序
    • 10. 基数排序
  • 数据结构

    • 数组

      • 数组概览
      • 数组算法题
    • 字符串

      • 字符串概览
      • 字符串算法题
    • 树

      • 树概览
      • 树算法题
    • 链表

      • 链表概览
      • 双向链表
      • 链表算法题
    • 队列

      • 队列概览
      • 队列算法题
    • 堆

      • 堆概览
      • 堆算法题
    • 散列表(哈希表)

      • 散列表(哈希表)概览
      • 散列表(哈希表)算法题
    • 栈

      • 栈概览
      • 栈算法题
    • 图

      • 图概览
      • 图算法题
  • algorithm
放肆青春
2021-03-18

1. 冒泡排序

//先将交换元素部分抽象出来
function swap(i, j, array) {
  var temp = array[j];
  array[j] = array[i];
  array[i] = temp;
}
1
2
3
4
5
6

# 冒泡排序简介

# 稳定性

由于冒泡排序只在相邻元素大小不符合要求时才调换他们的位置, 它并不改变相同元素之间的相对顺序, 因此它是稳定的排序算法.

# 流程:

  1. 从第一个元素开始,比较每两个相邻元素,如果前者大,就交换位置

  2. 每次遍历结束,能够找到该次遍历过的元素中的最大值

  3. 如果还有没排序过的元素,继续步骤 1

# 演示图:

image

# 冒泡排序代码实现

# 最简单的冒泡排序

function bubbleSort(array) {
  for (let i = 0; i < array.length; i++) {
    for (let j = 0; j < array.length - i - 1; j++) {
      if (array[j] > array[j + 1]) {
        swap(j, j + 1, array);
      }
    }
  }
  return array;
}
1
2
3
4
5
6
7
8
9
10

# 优化 1:检查某次内层遍历是否发生交换

检查某次内层遍历是否发生交换,如果没有发生交换,说明已经排序完成,就算外层循环还没有执行完 length - 1 次也可以直接 break。

function bubbleSort(array) {
  var length = array.length,
    isSwap;
  for (var i = 0; i < length; i++) {
    //正序
    isSwap = false;
    for (var j = 0; j < length - 1 - i; j++) {
      //正序
      array[j] > array[j + 1] && (isSwap = true) && swap(j, j + 1, array);
    }
    if (!isSwap) break;
  }
  return array;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 优化 2:记录内层遍历最后一次发生交换的位置

记录内层遍历最后一次发生交换的位置,下一次外层遍历只需要到这个位置就可以了。

那么外层遍历就不能用 for 了,因为每次遍历的结束位置可能会发生改变。

function bubbleSort2(arr) {
  // 遍历结束位置的初始值为数组尾,并逐渐向数组头部逼近
  let high = arr.length - 1;
  while (high > 0) {
    // 本次内层遍历发生交换的位置的初始值
    let position = 0;
    for (let j = 0; j < high; j++) {
      if (arr[j] > arr[j + 1]) {
        swap(j, j + 1, arr);
        // 如果发生了交换,更新 position
        position = j;
      }
    }
    // 下次遍历只需要到 position 的位置即可
    high = position;
  }
  return arr;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 优化 3:双向冒泡排序

双向遍历,每次循环能找到一个最大值和一个最小值。

前后各设置一个索引,向中间的未排序部分逼近。

image

function bothwayBubbleSort(array) {
  let left = 0,
    right = array.length - 1;
  for (let i = 0; i < array.length; i++) {
    if (left >= right) {
      // 左侧大于等于右侧,意味着左侧大于等于一半的length,说明已经完成整个排序了
      break;
    }
    let isSwap = false;
    if (i % 2 === 0) {
      // 通过奇偶来区分从左向右,还是从右向左
      for (let j = left; j < right; j++) {
        if (array[j] > array[j + 1]) {
          swap(j, j + 1, array);
          isSwap = true;
        }
      }
      right--; // 从左向右排序,最大的放在最右边,则最后边在下一轮不用参与排序,right --
    } else {
      for (let j = right; j > left; j--) {
        if (array[j - 1] > array[j]) {
          swap(j - 1, j, array);
          isSwap = true;
        }
      }
      left++; // 从右向左排序,最小的放在最左边,最左边最小在下一轮不用参与排序,left ++
    }
    if (!isSwap) {
      // 如果一轮里数据都没有变化,则说明排序完成,可终止排序
      break;
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
更新时间: 1/21/2022, 7:50:17 PM
排序算法
2. 选择排序

← 排序算法 2. 选择排序→

最近更新
01
前端权限管理
02-24
02
vue2指令
02-24
03
vue2 hook
02-24
更多文章>
Theme by Vdoing | Copyright © 2019-2022 放肆青春
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式