【数据结构】

213 阅读3分钟

队列Queue : 先进先出的数组

  1. 先进先出的数组
  2. 只提供入队和出队两个操作
  • array.push(n) 请用高级写法array.push.call(array,n)
  • array.shift() 请用高级写法array.shift.call(array)

为啥要用高级用法:array.shift(),操作对象是this,默认指定的this就是array。如果我们用高级写法,那么函数对谁操作一目了然。

  1. 举例:外出用餐取号和叫号就是一个队列。先取号的就会先叫号。

栈stack : 后进先出的数组

  1. 后进先出的数组
  2. 只提供压栈和弹栈两个操作。
  • array.push(n) 请用高级写法array.push.call(array,n)
  • array.pop() 请用高级写法array.pop.call(array)
  1. 举例
  • 坐电梯就是先进后出,后进先出
  • JS函数调用栈也是先压栈的后弹栈。

阶乘函数

function f(n){
return n !== 1 ? n* f(n-1) : 1
}

f(4)

链表Linked List : 一个链一个

  1. 举例:原型链
array.__proto__ === Array.prototype
Array.prototype.__proto__ === Object.prototype

  1. 类型

①单向链表:每个节点有一个next指向下一个节点

②双向链表:每个节点有一个previous指向上一个节点

③循环链表:最后一个节点的next指向头节点

  1. 链表的创建和增删改查节点
const createList = value => {
  return createNode(value);
};
const appendList = (list, value) => {
  const node = createNode(value);
  let x = list;
  while (x.next) {
    x = x.next;
  }
  // x.next === null //x 是最后一个节点
  x.next = node;
  return node;
};
const removeFromList = (list, node) => {
  let x = list;
  let p = node; // 课堂里将 p 初始化为 null,这里改为 node
  while (x !== node && x !== null) { // 课堂里忘了对 null 进行处理,如果 node 不在 list 中,x 就可能为 null
    p = x;
    x = x.next;
  }
  if(x === null){ // 若 x 为 null,则不需要删除,直接 return, false 表示无法删除不在list里的节点
    return false
  }else if(x === p){ // 这说明要删除的节点是第一个节点
    p = x.next
    return p // 如果删除的是第一个节点,那么就要把新 list 的头节点 p 返回给外面,即 newList = removeFromList(list, list)
  }else{
    p.next = x.next;
    return list // 如果删除的不是第一个节点,返回原来的 list 即可
  }
};

const createNode = value => {
  return {
    data: value,
    next: null
  };
};

const travelList = (list, fn) => {
  let x = list;
  while (x !== null) {
    fn(x);
    x = x.next;
  }
};

const list = createList(10);
const node2 = appendList(list, 20);
const node3 = appendList(list, 30);
const node4 = appendList(list, 40);
travelList(list, node => {
  console.log(node.data);
});

哈希表key-value pairs

定义

哈希表就是一个个个键值对的组成的。

问题 : 存键值对容易,那读呢?

假设哈希表hash里有一万对key-value

比如{name: 'yy', age: 18, p1: 'property1'}

如何使得读取hash['xxx']速度最快

4个解决办法

  1. 不作任何优化,hash['xx'] 需要遍历所有key, O(n)
  2. 对key排序,使用二分查找,o(log2 n)
  3. 用字符串对应的ASCII数字做索引,o(1)
  4. 对索引做除法取余数,就可以直接取到那个key,o(1),还有个小问题就是冲突了怎么办,冲突了就顺延

树tree : 一个链多个

  1. 举例
  • 中国的省市区,可以看成一棵树
  • 公司的层级结构,可以看成一棵树
  • 网页中的节点,可以看成一棵树
  1. 树的创建和增删改查
let tree = createTree(value)
let node = createNode(value)
addChild(tree, node)
removeChild(node1, node2)
travel(tree)
const createTree = value => {
  return {
    data: value,
    children: null,
    parent: null
  };
};
const addChild = (node, value) => {
  const newNode = {
    data: value,
    children: null,
    parent: node
  };
  node.children = node.children || [];
  node.children.push(newNode);
  return newNode;
};
const travel = (tree, fn) => {
  fn(tree);
  if (!tree.children) {
    return;
  }
  for (let i = 0; i < tree.children.length; i++) {
    travel(tree.children[i], fn);
  }
};

const find = (tree, node) => {
  if (tree === node) {
    return tree;
  } else if (tree.children) {
    for (let i = 0; i < tree.children.length; i++) {
      const result = find(tree.children[i], node);
      if (result) {
        return result;
      }
    }
    return undefined;
  } else {
    return undefined;
  }
};

const removeNode = (tree, node) => {
  const siblings = node.parent.children;
  let index = 0;
  for (let i = 1; i < siblings.length; i++) {
    if (siblings[i] === node) {
      index = i;
    }
  }
  siblings.splice(index, 1);
};

const tree = createTree(10);
const node2 = addChild(tree, 20);
const node3 = addChild(tree, 30);
addChild(tree, 40);
const node5 = addChild(tree, 50);
addChild(node2, 201);
addChild(node2, 202);
addChild(node2, 203);
addChild(node2, 204);
console.log(tree);

const fn = node => {
  console.log(node.data);
};

removeNode(tree, node5);
console.log(tree);

代码