前端基础算法

114 阅读3分钟

一、常见的数据结构

1. 栈 Stack

栈:是一种先进后出的数据结构

// 数组实现栈
const stack = []
stack.push(100) // 压栈
stack.pop // 出栈

image.png

2. 队列 Queue

队列:是一种先进先出的数据结构

// 数组实现队列
const stack = []
queue.push(100) // 入队
queue.shift // 出队

image.png

3. 链表 Linked list

链表不是连续的数据结构,而是由一系列的节点组成,节点之间通过指针相连

// 链表节点的数据结构
interface IListNode {
    data: any
    next: IListNode | null
}

image.png

4. 树 Tree

树,是一种有序的层级结构。每个节点下面可以有若干个子节点。例如常见的DOM树。

// 树节点的数据结构
interface ITreeNode {
    data: any
    children: ITreeNode[]|null
} 

image.png

5. 二叉树 BinaryTree

二叉树,首先它是一棵树,其次它的每个节点,最多有两个子节点,分别为left和right

image.png

// 二叉树节点的数据结构
interface IBinaryTreeNode {
    data: any
    left: IBinaryTreeNode | null
    right: IBinaryTreeNode | null
}

二、基础知识

2.1 复杂度

什么是复杂度?

  1. 程序执行时需要的计算量(时间复杂度)和内存空间(空间复杂度),与代码简洁程度无关。
  2. 复杂度是数量级(方便计算推广)用O(...)表示,内部是一个函数表达式,不是具体的数字。
  3. 一般针对一个具体的算法,而非一个完整的系统。
  4. 前端开发重时间,轻空间

image.png

  • O(1)代码就是平铺直叙的执行,没有任何循环。
  • O(logn)有循环,但其中使用了二分法,例如:二分查找算法。二分法是非常重要的算法思维,它可以极大的减少复杂度,而且计算量越大、减少的越明显。
  • O(n)普通的循环。
  • O(n*logn)嵌套循环,一层是普通循环,一层有二分算法。例如:快速排序算法。
  • O(n^2)两个普通循环的嵌套,例如常见的冒泡排序。

三、练习题

3.1 将一个数组旋转K步

// 例:有一个数组[1,2,3,4,5,6,7],K=3,则旋转3步,输出[5,6,7,1,2,3,4]

// 方案一:末尾元素pop,然后unshift到数组前面
// 时间复杂度为O(n^2),原因在于数组的unshift操作也是O(n)的复杂度
// 数组是一个有序结构,unshift操作非常慢O(n),push很快
const arr = [1, 2, 3, 4, 5, 6, 7];
function rotate(k) {
  for (let i = 0; i < k; i++) {
    const popData = arr.pop();
    arr.unshift(popData);
  }
}
rotate(3);
console.log(arr); // [5,6,7,1,2,3,4]

// 方案二:数组splice方法截取,再unshift到数组前面
const arr = [1, 2, 3, 4, 5, 6, 7];
function rotate(k) {
  const newArr = arr.splice(arr.length - k, k);
  arr.unshift(...newArr);
}
rotate(3);
console.log(arr); // [5,6,7,1,2,3,4]

// 方案三:截取后,concat拼接
// concat会在当前数组尾部拼接传入的数组,然后返回一个新数组,原数组不变
const arr = [1, 2, 3, 4, 5, 6, 7];
function rotate(k) {
  const arr1 = arr.slice(-k);
  const arr2 = arr.slice(0, arr.length - k);
  const arr3 = arr1.concat(arr2);
  return arr3;
}
const arr1 = rotate(3);
console.log(arr1); // [5,6,7,1,2,3,4]