loading

【数据结构与算法图解】- 算法基础

个人感觉 【数据结构与算法图解】这本书讲的比较简单,有计算机基础的不推荐看

# 尽量减少重复劳动力

系统学习推荐小伙伴直接去 awesome-coding-js (opens new window)

这里是我个人学习的的一些小结

# 【数据结构与算法图解】 结合 awesome-coding-js 总结的

个人感觉 【数据结构与算法图解】这本书讲的比较简单,有计算机基础的不推荐看

# 1、一些概念

  • 时间复杂度 理论:操作的速度,并不按时间计算,而是按步数 计算
  • 读取:一步,查找:最多N步,插入:最多N+1(N次移动,1次插入),删除:最多N

# 2、查找

  • 线性查找: 一个个查,比对
  • 二分查找: 每次有序数组长度乘以 2,二分查找所需的最多步数只会加 1。

# 3、大 O 记法

一般指: 最坏的情况

  • O(1) 不管需要多少步,步数不变就是O(1)
  • O(N) 根据数据量变化而变化
  • O(log N) 对数时间,比如二分查找,数据量翻倍时,步数+1

JavaScript简单记(不准):根据for循环的数量来记,2个for就是O(n2)

# 4、冒泡排序

# 概念

循环数组,比较当前元素和下一个元素,如果当前元素比下一个元素大,向上冒泡。

这样一次循环之后最后一个数就是本数组最大的数。

下一次循环继续上面的操作,不循环已经排序好的数。

优化:当一次循环没有发生冒泡,说明已经排序完成,停止循环

# 解法

function bubbleSort(array) {
      for (let j = 0; j < array.length; j++) {
        let complete = true;
        for (let i = 0; i < array.length - 1 - j; i++) {
          // 比较相邻数
          if (array[i] > array[i + 1]) {
            [array[i], array[i + 1]] = [array[i + 1], array[i]];
            complete = false;
          }
        }
        // 没有冒泡结束循环
        if (complete) {
          break;
        }
      }
      return array;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 复杂度

时间复杂度:O(n2)

空间复杂度:O(1)

# 5、选择排序

每次循环选取一个最小的数字放到前面的有序序列中。

# 解法

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

# 复杂度

时间复杂度:O(n2)

空间复杂度:O(1)

# 大O记法忽略常数

选择排序的步数大概只有冒泡排序的一半,即选择排序比冒泡排序 快一倍。

但是严格来说选择排序应为 O(N2 / 2),最终得写成 O(N2 )。

类似地,O(2N)要写成 O(N); O(N / 2)也写成 O(N);就算是比 O(N)慢 100 倍的 O(100N),也要写成 O(N)。

# 6、插入排序

将左侧序列看成一个有序序列,每次将一个数字插入该有序序列。

插入时,从有序序列最右侧开始比较,若比较的数较大,后移一位。

function insertSort(array) {
      for (let i = 1; i < array.length; i++) {
        let target = i;
        for (let j = i - 1; j >= 0; j--) {
          if (array[target] < array[j]) {
            [array[target], array[j]] = [array[j], array[target]]
            target = j;
          } else {
            break;
          }
        }
      }
      return array;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 复杂度

时间复杂度:O(n2)

空间复杂度:O(1)

# 7、快速排序

快速排序:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另一部分的所有数据要小,再按这种方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,使整个数据变成有序序列。

先从右往左找一个小于 基准值 的数,再从左往右找一个大于 基准值 的数,然后交换他们。

这个图解很清楚:算法 3:最常用的排序——快速排序 (opens new window)

实现步骤:

  • 选择一个基准元素target(一般选择第一个数)
  • 将比target小的元素移动到数组左边,比target大的元素移动到数组右边
  • 分别对target左侧和右侧的元素进行快速排序

简单版本

function quickSort(array) {
      if (array.length < 2) {
        return array;
      }
      const target = array[0];
      const left = [];
      const right = [];
      for (let i = 1; i < array.length; i++) {
        if (array[i] < target) {
          left.push(array[i]);
        } else {
          right.push(array[i]);
        }
      }
      return quickSort(left).concat([target], quickSort(right));
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 8、数据结构

  • 链表(带有存储下一个结点地址的)插入和删除效率比数组高很多

# 9、空间复杂度

空间复杂度:当所处理的数据有 N 个元素时,该算法还需额外消耗多少元素大小的内存空间

O(1): 记住,时间 复杂度的O(1)意味着一个算法无论处理多少数据,其速度恒定。相似地,空间复杂度的 O(1)则 意味着一个算法无论处理多少数据,其消耗的内存恒定

最近更新时间: 2021/06/17 10:13:36
最近更新
01
2023/07/03 00:00:00
02
2023/04/22 00:00:00
03
2023/02/16 00:00:00