web前端初学数据结构笔记---待续未完

107 阅读2分钟

时间复杂度

时间复杂度是一个函数,用来定性描述算法的运行时间,用大写字母O表示,例如:O(1),O(n),O(logN)

空间复杂度

空间复杂度是一个函数,用来描述算法在运行过程中临时占用存储空间的大小,用大写字母O表示,例如:O(1),O(n),O(n^2)

1.数据结构---栈

一种后进先出的数据结构

经典场景

1. 十进制转二进制

// 封装一个 Stack 类,包括 push、pop、peek 方法。
class Stack {
  constructor() {
    this.stack = []
  }
  push(item) {
    this.stack.push(item)
  }
  pop() {
    return this.stack.pop()
  }
  peek() {
    return this.stack[this.stack.length - 1]
  }
  length() {
    return this.stack.length
  }
}
const stack = new Stack()
console.log(stack.length()) // 0
stack.push('123')
stack.push('456')
console.log(stack.length()) // 2
console.log(stack.pop()) // 456
console.log(stack.length()) // 1
console.log(stack.peek()) // 123

// 将100这个十进制数字转为二进制。
function dec2bin(num) {
  let res = '';
  let stack = new Stack();

  while (num) {
    stack.push(num % 2);
    num = parseInt(num / 2);
  }

  while (stack.length()) {
    res += stack.pop()
  }

  return res;
}
console.log(dec2bin(100)) // 1100100

2. 有效的括号

力扣题目 20. 有效的括号

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function (s) {
  const sLen = s.length
  if (sLen % 2 === 1) return false
  const stack = []
  for (let i = 0; i < sLen; i++) {
    const c = s[i]
    if (c === '(' || c === '[' || c === '{') {
      stack.push(c)
    } else {
      const t = stack[stack.length - 1]
      if (
        t === '(' && c === ')' ||
        t === '{' && c === '}' ||
        t === '[' && c === ']'
      ) {
        stack.pop()
      } else {
        return false
      }
    }
  }
  return stack.length === 0
};

3. 函数调用堆栈

2.数据结构---队列

一种先进先出的数据结构

class Queue {
  constructor() {
    this.queue = []
  }
  push(item) {
    this.queue.push(item)
    return this.queue
  }
  shift() {
    return this.queue.shift()
  }
  peek() {
    return this.queue[0]
  }
}
const queue = new Queue()
console.log(queue.push(1)) // [1]
console.log(queue.push(2)) // [1,2]
console.log(queue.shift()) // 1
console.log(queue.peek())  // 2

经典场景

1.食堂排队打饭

2.js异步中的任务队列

3.计算最近请求次数

力扣题目933. 最近的请求次数

var RecentCounter = function () {
  this.queue = []
};

/** 
* @param {number} t
* @return {number}
*/
RecentCounter.prototype.ping = function (t) {
  this.queue.push(t)
  while (this.queue[0] < t - 3000) {
    this.queue.shift()
  }
  return this.queue.length
};

/**
* Your RecentCounter object will be instantiated and called as such:
* var obj = new RecentCounter()
* var param_1 = obj.ping(t)
*/

3.数据结构---链表

多个元素组成的列表,元素储存不连续,用next指针连在一起。

数组 VS 链表

  • 数组:增删非首尾元素时,需要移动元素
  • 链接:增删非首尾元素时,不需要移动元素,只要更改next的指向即可。
const a = { val: 'a' }
const b = { val: 'b' }
const c = { val: 'c' }
const d = { val: 'd' }

a.next = b
b.next = c
c.next = d

// 遍历链表
let p = a
while (p) {
  console.log(p)
  p = p.next
}

// 插入
const e = { val: e }
c.next = e
e.next = d

// 删除
c.next = d

力扣题目237. 删除链表中的节点

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} node
 * @return {void} Do not return anything, modify node in-place instead.
 */
var deleteNode = function (node) {
  node.val = node.next.val
  node.next = node.next.next
};

力扣题目206. 反转链表

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */

// 定义两个指针:pre 和 cur;pre 在前 cur 在后
// 每次让 pre.next 指向 cur,实现一次局部反转
// 局部反转完成之后,pre 和 cur 同时往前移动一个位置
// 循环上述过程,直至 pre 到达链表尾部

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function (head) {
    let cur = null;
    let pre = head;

    while (pre) {
        const temp = pre.next
        pre.next = cur // 每次让 pre.next 指向 cur,实现一次局部反转
        cur = pre // cur 往前移动一个位置
        pre = temp // pre 往前移动一个位置
    }

    return cur
};

力扣题目2. 两数相加

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function (l1, l2) {
    const l3 = new ListNode(0)
    let p1 = l1
    let p2 = l2
    let p3 = l3
    let carry = 0
    while (p1 || p2) {
        const v1 = p1 ? p1.val : 0
        const v2 = p2 ? p2.val : 0
        const val = v1 + v2 + carry
        carry = Math.floor(val / 10)
        p3.next = new ListNode(val % 10)
        if (p1) p1 = p1.next
        if (p2) p2 = p2.next
        p3 = p3.next
    }
    if (carry) {
        p3.next = new ListNode(carry)
    }
    return l3.next
};

4.数据结构---集合

一种无序且唯一的数据结构

经典应用

// 去重
const arr1 = [1, 1, 2, 2]
const arr2 = [...new Set(arr1)]
console.log(arr2) // [1, 2]

// 判断元素是否在集合中
const set1 = new Set(arr1)
console.log(set1.has(1)) // true
console.log(set1.has(3)) // false

// 求交集
const set2 = new Set([2, 3])
const set3 = new Set([...set1, 3].filter(item => set2.has(item)))
console.log(...set3) // 2 3

力扣题目349. 两个数组的交集

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function(nums1, nums2) {
    return [...new Set(nums1)].filter(n => nums2.includes(n))
};

5.数据结构---字典

与集合类似,字典也是一种存储唯一值的数据结构,但是它是以键值对的形式来存储。

力扣题目349. 两个数组的交集

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function (nums1, nums2) {
    const map = new Map()
    nums1.forEach((n) => {
        map.set(n, true)
    })

    const result = []
    nums2.forEach((n) => {
        if (map.get(n)) {
            result.push(n)
            map.delete(n)
        }
    })

    return result
};

力扣题目1. 两数之和

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
    const map = new Map()
    for (let i = 0; i < nums.length; i++) {
        const n = nums[i]
        const n2 = target - n
        if (map.has(n2)) {
            return [i, map.get(n2)]
        } else {
            map.set(n, i)
        }
    }
};

力扣题目 20. 有效的括号优化

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function (s) {
    const sLen = s.length
    if (sLen % 2 === 1) return false
    const stack = []
    const map = new Map()
    map.set('(', ')')
    map.set('{', '}')
    map.set('[', ']')

    for (let i = 0; i < sLen; i++) {
        const c = s[i]
        if (map.has(c)) {
            stack.push(c)
        } else {
            const t = stack[stack.length - 1]
            if (map.get(t) === c) {
                stack.pop()
            } else {
                return false
            }
        }
    }
    return stack.length === 0
};

6.数据结构---树

一种分层数据的抽象模型

1.树的深度遍历

  1. 访问根节点。
  2. 再对根节点的children进行深度优先遍历。
const tree = {
  value: 'a',
  children: [{
    value: 'b',
    children: [{
      value: 'd',
      children: []
    }, {
      value: 'e',
      children: []
    }]
  }, {
    value: 'c',
    children: [{
      value: 'f',
      children: []
    }, {
      value: 'g',
      children: []
    }]
  }]
}

function dfs(node) {
  console.log(node.value)
  // node.children.forEach(child => { dfs(child.children) })
  node.children.forEach(dfs)
}

dfs(tree)

// 输出顺序
a

b

d

e

c

f

g

2.树的广度优先遍历

  1. 新建一个队列,把根节点入队。
  2. 把队头出队并访问。
  3. 把队头的children挨个入队。
  4. 重复第二,第三步,直到队列为空。
const tree = {
  value: 'a',
  children: [{
    value: 'b',
    children: [{
      value: 'd',
      children: []
    }, {
      value: 'e',
      children: []
    }]
  }, {
    value: 'c',
    children: [{
      value: 'f',
      children: []
    }, {
      value: 'g',
      children: []
    }]
  }]
}

function bfs(root) {
  const queue = [root]
  while (queue.length > 0) {
    const node = queue.shift()
    console.log(node.value)
    node.children.forEach(child => {
      queue.push(child)
    });
  }
}

bfs(tree)

// 输出顺序
a

b

c

d

e

f

g

3.二叉树:树的每个节点,最多只能拥有两个子节点

// 待更新。。。

7.数据结构---图

图是网络结构的抽象模型,是一组由连接的节点。 图可以表示任何二元关系,比如道路,航班等。

图的表示法之---邻接矩阵

图的表示法之---邻接表

8.数据结构---堆

  • 堆是一种特殊的完全二叉树。所有的节点都大于等于或小于等于它的子节点。
  • 最大堆:所有的节点都于等于它的子节点。
  • 最小堆:所有的节点都于等于它的子节点。