JavaScript 性能与优化:数据结构和算法

引言

在JavaScript开发中, 正确的数据结构和算法选择对应用性能有着决定性的影响。随着Web应用日益复杂, 处理的数据量不断增长, 优化代码性能变得至关重要。本文将深入探讨JavaScript中关键数据结构和算法的实现、优化策略以及其在实际项目中的应用。

一、JavaScript中数据结构的选择策略

1.1 数组与对象的选择

在JavaScript中, 数组和对象是最常用的数据结构, 但它们在不同场景下的性能特征差异显著。

javascript 复制代码
// 数组和对象性能对比示例
class DataStructureSelector {
  // 数组: 适合顺序访问和索引访问
  static arrayPerformanceTest() {
    const arr = [];
    const size = 1000000;

    // 测试插入性能
    console.time("数组插入");
    for (let i = 0; i < size; i++) {
      arr.push(i);
    }
    console.timeEnd("数组插入");

    // 测试随机访问性能
    console.time("数组随机访问");
    for (let i = 0; i < 1000; i++) {
      const index = Math.floor(Math.random() * size);
      const _ = arr[index];
    }
    console.timeEnd("数组随机访问");
  }

  // 对象: 适合键值对查找
  static objectPerformanceTest() {
    const obj = {};
    const size = 1000000;

    console.time("对象插入");
    for (let i = 0; i < size; i++) {
      obj[`key${i}`] = i;
    }
    console.timeEnd("对象插入");

    console.time("对象查找");
    for (let i = 0; i < 1000; i++) {
      const key = `key${Math.floor(Math.random() * size)}`;
      const _ = obj[key];
    }
    console.timeEnd("对象查找");
  }
}

// 性能测试
DataStructureSelector.arrayPerformanceTest();
DataStructureSelector.objectPerformanceTest();
// 数组插入: 24.589ms
// 数组随机访问: 0.172ms
// 对象插入: 933.765ms
// 对象查找: 0.512ms
1.2 Map与Set的优势

ES6引入的Map和Set提供了更专业的键值对和集合操作。

javascript 复制代码
class MapSetPerformance {
  static compareMapVsObject() {
    const size = 1000000;

    // Object测试
    const obj = {};
    console.time("Object设置");
    for (let i = 0; i < size; i++) {
      obj[i] = `value${i}`;
    }
    console.timeEnd("Object设置");

    // Map测试
    const map = new Map();
    console.time("Map设置");
    for (let i = 0; i < size; i++) {
      map.set(i, `value${i}`);
    }
    console.timeEnd("Map设置");

    // 查找性能比较
    console.time("Object查找");
    for (let i = 0; i < 10000; i++) {
      const key = Math.floor(Math.random() * size);
      const _ = obj[key];
    }
    console.timeEnd("Object查找");

    console.time("Map查找");
    for (let i = 0; i < 10000; i++) {
      const key = Math.floor(Math.random() * size);
      const _ = map.get(key);
    }
    console.timeEnd("Map查找");
  }

  static setOperations() {
    const setA = new Set([1, 2, 3, 4, 5]);
    const setB = new Set([4, 5, 6, 7, 8]);

    // 并集
    const union = new Set([...setA, ...setB]);

    // 交集
    const intersection = new Set([...setA].filter((x) => setB.has(x)));

    // 差集
    const difference = new Set([...setA].filter((x) => !setB.has(x)));

    return { union, intersection, difference };
  }
}

MapSetPerformance.compareMapVsObject();
MapSetPerformance.setOperations();
// Object设置: 192.252ms
// Map设置: 329.439ms
// Object查找: 1.574ms
// Map查找: 2.983ms

二、链表及其变体实现

2.1 单向链表
javascript 复制代码
class ListNode {
  constructor(value, next = null) {
    this.value = value;
    this.next = next;
  }
}

class LinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.size = 0;
  }

  // 添加节点到末尾
  append(value) {
    const newNode = new ListNode(value);

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      this.tail = newNode;
    }

    this.size++;
    return this;
  }

  // 添加节点到开头
  prepend(value) {
    const newNode = new ListNode(value, this.head);
    this.head = newNode;

    if (!this.tail) {
      this.tail = newNode;
    }

    this.size++;
    return this;
  }

  // 删除节点
  delete(value) {
    if (!this.head) return null;

    let deletedNode = null;

    // 如果头节点就是要删除的节点
    while (this.head && this.head.value === value) {
      deletedNode = this.head;
      this.head = this.head.next;
      this.size--;
    }

    let currentNode = this.head;

    // 遍历删除匹配的节点
    if (currentNode !== null) {
      while (currentNode.next) {
        if (currentNode.next.value === value) {
          deletedNode = currentNode.next;
          currentNode.next = currentNode.next.next;
        } else {
          currentNode = currentNode.next;
        }
      }
    }

    // 更新尾节点
    if (this.tail && this.tail.value === value) {
      this.tail = currentNode;
    }

    return deletedNode;
  }

  // 查找节点
  find(value) {
    if (!this.head) return null;

    let currentNode = this.head;

    while (currentNode) {
      if (currentNode.value === value) {
        return currentNode;
      }

      currentNode = currentNode.next;
    }

    return null;
  }

  // 反转链表
  reverse() {
    let currentNode = this.head;
    let prevNode = null;
    let nextNode = null;

    while (currentNode) {
      nextNode = currentNode.next;
      currentNode.next = prevNode;

      prevNode = currentNode;
      currentNode = nextNode;
    }

    this.tail = this.head;
    this.head = prevNode;

    return this;
  }

  // 转换为数组
  toArray() {
    const nodes = [];
    let currentNode = this.head;

    while (currentNode) {
      nodes.push(currentNode.value);
      currentNode = currentNode.next;
    }

    return nodes;
  }
}
2.2 双向链表
javascript 复制代码
class DoublyListNode {
  constructor(value, next = null, prev = null) {
    this.value = value;
    this.next = next;
    this.prev = prev;
  }
}

class DoublyLinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.size = 0;
  }
  
  // 在末尾添加节点
  append(value) {
    const newNode = new DoublyListNode(value);
    
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      newNode.prev = this.tail;
      this.tail = newNode;
    }
    
    this.size++;
    return this;
  }
  
  // 在开头添加节点
  prepend(value) {
    const newNode = new DoublyListNode(value, this.head);
    
    if (this.head) {
      this.head.prev = newNode;
    }
    
    this.head = newNode;
    
    if (!this.tail) {
      this.tail = newNode;
    }
    
    this.size++;
    return this;
  }
  
  // 删除节点
  delete(value) {
    if (!this.head) return null;
    
    let deletedNode = null;
    let currentNode = this.head;
    
    while (currentNode) {
      if (currentNode.value === value) {
        deletedNode = currentNode;
        
        if (deletedNode === this.head) {
          this.head = deletedNode.next;
          
          if (this.head) {
            this.head.prev = null;
          }
          
          if (deletedNode === this.tail) {
            this.tail = null;
          }
        } else if (deletedNode === this.tail) {
          this.tail = deletedNode.prev;
          this.tail.next = null;
        } else {
          const prevNode = deletedNode.prev;
          const nextNode = deletedNode.next;
          
          prevNode.next = nextNode;
          nextNode.prev = prevNode;
        }
        
        this.size--;
      }
      
      currentNode = currentNode.next;
    }
    
    return deletedNode;
  }
  
  // 从尾部遍历
  reverseTraversal(callback) {
    let currentNode = this.tail;
    
    while (currentNode) {
      callback(currentNode.value);
      currentNode = currentNode.prev;
    }
  }
}

三、栈和队列的优化实现

3.1 栈的实现
javascript 复制代码
class Stack {
  constructor() {
    this.items = [];
    this.count = 0;
  }
  
  // 入栈
  push(element) {
    this.items[this.count] = element;
    this.count++;
    return this.count;
  }
  
  // 出栈
  pop() {
    if (this.count === 0) return undefined;
    
    this.count--;
    const deletedItem = this.items[this.count];
    delete this.items[this.count];
    return deletedItem;
  }
  
  // 查看栈顶元素
  peek() {
    if (this.count === 0) return undefined;
    return this.items[this.count - 1];
  }
  
  // 检查栈是否为空
  isEmpty() {
    return this.count === 0;
  }
  
  // 获取栈大小
  size() {
    return this.count;
  }
  
  // 清空栈
  clear() {
    this.items = [];
    this.count = 0;
  }
  
  // 栈的应用:括号匹配
  static isBalancedParentheses(str) {
    const stack = new Stack();
    const parenthesesMap = {
      ')': '(',
      '}': '{',
      ']': '['
    };
    
    for (let char of str) {
      if (char === '(' || char === '{' || char === '[') {
        stack.push(char);
      } else if (char === ')' || char === '}' || char === ']') {
        if (stack.isEmpty() || stack.pop() !== parenthesesMap[char]) {
          return false;
        }
      }
    }
    
    return stack.isEmpty();
  }
}
3.2 队列的实现
javascript 复制代码
class Queue {
  constructor() {
    this.items = {};
    this.frontIndex = 0;
    this.backIndex = 0;
  }
  
  // 入队
  enqueue(element) {
    this.items[this.backIndex] = element;
    this.backIndex++;
    return this.backIndex - this.frontIndex;
  }
  
  // 出队
  dequeue() {
    if (this.frontIndex === this.backIndex) return undefined;
    
    const element = this.items[this.frontIndex];
    delete this.items[this.frontIndex];
    this.frontIndex++;
    return element;
  }
  
  // 查看队首元素
  peek() {
    if (this.frontIndex === this.backIndex) return undefined;
    return this.items[this.frontIndex];
  }
  
  // 队列大小
  size() {
    return this.backIndex - this.frontIndex;
  }
  
  // 是否为空
  isEmpty() {
    return this.size() === 0;
  }
  
  // 清空队列
  clear() {
    this.items = {};
    this.frontIndex = 0;
    this.backIndex = 0;
  }
}

// 循环队列实现
class CircularQueue {
  constructor(k) {
    this.capacity = k;
    this.queue = new Array(k);
    this.headIndex = 0;
    this.count = 0;
  }
  
  enQueue(value) {
    if (this.isFull()) return false;
    
    const tailIndex = (this.headIndex + this.count) % this.capacity;
    this.queue[tailIndex] = value;
    this.count++;
    return true;
  }
  
  deQueue() {
    if (this.isEmpty()) return false;
    
    this.headIndex = (this.headIndex + 1) % this.capacity;
    this.count--;
    return true;
  }
  
  Front() {
    if (this.isEmpty()) return -1;
    return this.queue[this.headIndex];
  }
  
  Rear() {
    if (this.isEmpty()) return -1;
    const tailIndex = (this.headIndex + this.count - 1) % this.capacity;
    return this.queue[tailIndex];
  }
  
  isEmpty() {
    return this.count === 0;
  }
  
  isFull() {
    return this.count === this.capacity;
  }
}

四、树结构的深度优化

4.1 二叉树实现
javascript 复制代码
class TreeNode {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

class BinaryTree {
  constructor() {
    this.root = null;
  }
  
  // 插入节点
  insert(value) {
    const newNode = new TreeNode(value);
    
    if (!this.root) {
      this.root = newNode;
      return this;
    }
    
    let currentNode = this.root;
    
    while (true) {
      if (value < currentNode.value) {
        if (!currentNode.left) {
          currentNode.left = newNode;
          break;
        }
        currentNode = currentNode.left;
      } else {
        if (!currentNode.right) {
          currentNode.right = newNode;
          break;
        }
        currentNode = currentNode.right;
      }
    }
    
    return this;
  }
  
  // 深度优先遍历:前序
  preOrderTraversal(node = this.root, result = []) {
    if (node) {
      result.push(node.value);
      this.preOrderTraversal(node.left, result);
      this.preOrderTraversal(node.right, result);
    }
    return result;
  }
  
  // 深度优先遍历:中序
  inOrderTraversal(node = this.root, result = []) {
    if (node) {
      this.inOrderTraversal(node.left, result);
      result.push(node.value);
      this.inOrderTraversal(node.right, result);
    }
    return result;
  }
  
  // 深度优先遍历:后序
  postOrderTraversal(node = this.root, result = []) {
    if (node) {
      this.postOrderTraversal(node.left, result);
      this.postOrderTraversal(node.right, result);
      result.push(node.value);
    }
    return result;
  }
  
  // 广度优先遍历
  levelOrderTraversal() {
    if (!this.root) return [];
    
    const result = [];
    const queue = [this.root];
    
    while (queue.length > 0) {
      const levelSize = queue.length;
      const currentLevel = [];
      
      for (let i = 0; i < levelSize; i++) {
        const currentNode = queue.shift();
        currentLevel.push(currentNode.value);
        
        if (currentNode.left) {
          queue.push(currentNode.left);
        }
        if (currentNode.right) {
          queue.push(currentNode.right);
        }
      }
      
      result.push(currentLevel);
    }
    
    return result;
  }
  
  // 查找节点
  find(value) {
    let currentNode = this.root;
    
    while (currentNode) {
      if (value === currentNode.value) {
        return currentNode;
      } else if (value < currentNode.value) {
        currentNode = currentNode.left;
      } else {
        currentNode = currentNode.right;
      }
    }
    
    return null;
  }
}
4.2 平衡二叉搜索树(AVL树)
javascript 复制代码
class AVLNode {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
    this.height = 1;
  }
}

class AVLTree {
  constructor() {
    this.root = null;
  }
  
  // 获取节点高度
  getHeight(node) {
    return node ? node.height : 0;
  }
  
  // 获取平衡因子
  getBalanceFactor(node) {
    return node ? this.getHeight(node.left) - this.getHeight(node.right) : 0;
  }
  
  // 右旋转
  rightRotate(y) {
    const x = y.left;
    const T2 = x.right;
    
    x.right = y;
    y.left = T2;
    
    y.height = Math.max(this.getHeight(y.left), this.getHeight(y.right)) + 1;
    x.height = Math.max(this.getHeight(x.left), this.getHeight(x.right)) + 1;
    
    return x;
  }
  
  // 左旋转
  leftRotate(x) {
    const y = x.right;
    const T2 = y.left;
    
    y.left = x;
    x.right = T2;
    
    x.height = Math.max(this.getHeight(x.left), this.getHeight(x.right)) + 1;
    y.height = Math.max(this.getHeight(y.left), this.getHeight(y.right)) + 1;
    
    return y;
  }
  
  // 插入节点
  insert(value) {
    this.root = this._insertNode(this.root, value);
  }
  
  _insertNode(node, value) {
    if (!node) return new AVLNode(value);
    
    if (value < node.value) {
      node.left = this._insertNode(node.left, value);
    } else if (value > node.value) {
      node.right = this._insertNode(node.right, value);
    } else {
      return node; // 不允许重复值
    }
    
    // 更新高度
    node.height = 1 + Math.max(
      this.getHeight(node.left),
      this.getHeight(node.right)
    );
    
    // 获取平衡因子
    const balance = this.getBalanceFactor(node);
    
    // 平衡调整
    // 左左情况
    if (balance > 1 && value < node.left.value) {
      return this.rightRotate(node);
    }
    
    // 右右情况
    if (balance < -1 && value > node.right.value) {
      return this.leftRotate(node);
    }
    
    // 左右情况
    if (balance > 1 && value > node.left.value) {
      node.left = this.leftRotate(node.left);
      return this.rightRotate(node);
    }
    
    // 右左情况
    if (balance < -1 && value < node.right.value) {
      node.right = this.rightRotate(node.right);
      return this.leftRotate(node);
    }
    
    return node;
  }
  
  // 查找最小值节点
  findMinNode(node) {
    while (node && node.left) {
      node = node.left;
    }
    return node;
  }
}

五、LRU缓存机制实现

javascript 复制代码
class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
    this.head = { key: null, value: null, prev: null, next: null };
    this.tail = { key: null, value: null, prev: null, next: null };
    this.head.next = this.tail;
    this.tail.prev = this.head;
  }
  
  // 添加节点到链表头部
  _addToHead(node) {
    node.prev = this.head;
    node.next = this.head.next;
    this.head.next.prev = node;
    this.head.next = node;
  }
  
  // 移除节点
  _removeNode(node) {
    const prev = node.prev;
    const next = node.next;
    prev.next = next;
    next.prev = prev;
  }
  
  // 移动到头部
  _moveToHead(node) {
    this._removeNode(node);
    this._addToHead(node);
  }
  
  // 移除尾部节点
  _popTail() {
    const res = this.tail.prev;
    this._removeNode(res);
    return res;
  }
  
  // 获取缓存
  get(key) {
    if (!this.cache.has(key)) {
      return -1;
    }
    
    const node = this.cache.get(key);
    this._moveToHead(node);
    return node.value;
  }
  
  // 设置缓存
  put(key, value) {
    if (this.cache.has(key)) {
      const node = this.cache.get(key);
      node.value = value;
      this._moveToHead(node);
    } else {
      const newNode = {
        key,
        value,
        prev: null,
        next: null
      };
      
      this.cache.set(key, newNode);
      this._addToHead(newNode);
      
      if (this.cache.size > this.capacity) {
        const tail = this._popTail();
        this.cache.delete(tail.key);
      }
    }
  }
  
  // 获取所有缓存键(按使用顺序)
  getKeys() {
    const keys = [];
    let node = this.head.next;
    
    while (node !== this.tail) {
      keys.push(node.key);
      node = node.next;
    }
    
    return keys;
  }
  
  // 清空缓存
  clear() {
    this.cache.clear();
    this.head.next = this.tail;
    this.tail.prev = this.head;
  }
}

// LRU缓存使用示例
const lruCache = new LRUCache(3);

// 添加数据
lruCache.put('user1', { name: 'Alice', age: 25 });
lruCache.put('user2', { name: 'Bob', age: 30 });
lruCache.put('user3', { name: 'Charlie', age: 35 });

console.log('当前缓存键:', lruCache.getKeys()); // ['user3', 'user2', 'user1']

// 访问user1,将其移动到最前面
lruCache.get('user1');
console.log('访问user1后:', lruCache.getKeys()); // ['user1', 'user3', 'user2']

// 添加新数据,超出容量
lruCache.put('user4', { name: 'David', age: 40 });
console.log('添加user4后:', lruCache.getKeys()); // ['user4', 'user1', 'user3']

六、图的算法实现

6.1 图的表示和遍历
javascript 复制代码
class Graph {
  constructor(isDirected = false) {
    this.vertices = new Map();
    this.isDirected = isDirected;
  }
  
  // 添加顶点
  addVertex(vertex) {
    if (!this.vertices.has(vertex)) {
      this.vertices.set(vertex, new Set());
    }
  }
  
  // 添加边
  addEdge(vertex1, vertex2) {
    if (!this.vertices.has(vertex1)) {
      this.addVertex(vertex1);
    }
    if (!this.vertices.has(vertex2)) {
      this.addVertex(vertex2);
    }
    
    this.vertices.get(vertex1).add(vertex2);
    
    if (!this.isDirected) {
      this.vertices.get(vertex2).add(vertex1);
    }
  }
  
  // 深度优先遍历
  dfs(startVertex, callback) {
    const visited = new Set();
    
    const dfsVisit = (vertex) => {
      visited.add(vertex);
      callback && callback(vertex);
      
      const neighbors = this.vertices.get(vertex);
      for (const neighbor of neighbors) {
        if (!visited.has(neighbor)) {
          dfsVisit(neighbor);
        }
      }
    };
    
    dfsVisit(startVertex);
  }
  
  // 广度优先遍历
  bfs(startVertex, callback) {
    const visited = new Set([startVertex]);
    const queue = [startVertex];
    
    while (queue.length > 0) {
      const vertex = queue.shift();
      callback && callback(vertex);
      
      const neighbors = this.vertices.get(vertex);
      for (const neighbor of neighbors) {
        if (!visited.has(neighbor)) {
          visited.add(neighbor);
          queue.push(neighbor);
        }
      }
    }
  }
  
  // 最短路径(BFS)
  shortestPath(startVertex, endVertex) {
    if (!this.vertices.has(startVertex) || !this.vertices.has(endVertex)) {
      return null;
    }
    
    const visited = new Set([startVertex]);
    const queue = [startVertex];
    const predecessors = new Map();
    const distances = new Map();
    
    distances.set(startVertex, 0);
    
    while (queue.length > 0) {
      const vertex = queue.shift();
      
      if (vertex === endVertex) {
        return this._buildPath(predecessors, startVertex, endVertex);
      }
      
      const neighbors = this.vertices.get(vertex);
      for (const neighbor of neighbors) {
        if (!visited.has(neighbor)) {
          visited.add(neighbor);
          predecessors.set(neighbor, vertex);
          distances.set(neighbor, distances.get(vertex) + 1);
          queue.push(neighbor);
        }
      }
    }
    
    return null;
  }
  
  _buildPath(predecessors, start, end) {
    const path = [end];
    let current = end;
    
    while (current !== start) {
      current = predecessors.get(current);
      path.unshift(current);
    }
    
    return path;
  }
  
  // 拓扑排序(仅适用于有向无环图)
  topologicalSort() {
    if (!this.isDirected) {
      throw new Error('拓扑排序仅适用于有向图');
    }
    
    const visited = new Set();
    const stack = [];
    
    const visit = (vertex) => {
      visited.add(vertex);
      
      const neighbors = this.vertices.get(vertex);
      for (const neighbor of neighbors) {
        if (!visited.has(neighbor)) {
          visit(neighbor);
        }
      }
      
      stack.push(vertex);
    };
    
    for (const vertex of this.vertices.keys()) {
      if (!visited.has(vertex)) {
        visit(vertex);
      }
    }
    
    return stack.reverse();
  }
}
6.2 Dijkstra最短路径算法
javascript 复制代码
class WeightedGraph {
  constructor() {
    this.adjacencyList = new Map();
  }
  
  addVertex(vertex) {
    if (!this.adjacencyList.has(vertex)) {
      this.adjacencyList.set(vertex, []);
    }
  }
  
  addEdge(vertex1, vertex2, weight) {
    this.adjacencyList.get(vertex1).push({ node: vertex2, weight });
    this.adjacencyList.get(vertex2).push({ node: vertex1, weight });
  }
  
  dijkstra(start, end) {
    const nodes = new PriorityQueue();
    const distances = new Map();
    const previous = new Map();
    const path = [];
    
    // 初始化
    for (const vertex of this.adjacencyList.keys()) {
      if (vertex === start) {
        distances.set(vertex, 0);
        nodes.enqueue(vertex, 0);
      } else {
        distances.set(vertex, Infinity);
        nodes.enqueue(vertex, Infinity);
      }
      previous.set(vertex, null);
    }
    
    while (!nodes.isEmpty()) {
      const smallest = nodes.dequeue().value;
      
      if (smallest === end) {
        // 构建路径
        let current = end;
        while (current) {
          path.unshift(current);
          current = previous.get(current);
        }
        break;
      }
      
      if (smallest && distances.get(smallest) !== Infinity) {
        for (const neighbor of this.adjacencyList.get(smallest)) {
          const candidate = distances.get(smallest) + neighbor.weight;
          
          if (candidate < distances.get(neighbor.node)) {
            distances.set(neighbor.node, candidate);
            previous.set(neighbor.node, smallest);
            nodes.enqueue(neighbor.node, candidate);
          }
        }
      }
    }
    
    return path.length > 1 ? path : [];
  }
}

// 优先队列实现
class PriorityQueue {
  constructor() {
    this.values = [];
  }
  
  enqueue(value, priority) {
    this.values.push({ value, priority });
    this.sort();
  }
  
  dequeue() {
    return this.values.shift();
  }
  
  sort() {
    this.values.sort((a, b) => a.priority - b.priority);
  }
  
  isEmpty() {
    return this.values.length === 0;
  }
}

七、散列表与哈希函数

7.1 自定义散列表实现
javascript 复制代码
class HashTable {
  constructor(size = 53) {
    this.keyMap = new Array(size);
  }
  
  // 哈希函数
  _hash(key) {
    let total = 0;
    const PRIME = 31;
    
    for (let i = 0; i < Math.min(key.length, 100); i++) {
      const char = key[i];
      const value = char.charCodeAt(0) - 96;
      total = (total * PRIME + value) % this.keyMap.length;
    }
    
    return total;
  }
  
  // 二次哈希解决冲突
  _hash2(key) {
    let total = 0;
    const PRIME = 37;
    
    for (let i = 0; i < Math.min(key.length, 100); i++) {
      const char = key[i];
      const value = char.charCodeAt(0) - 96;
      total = (total * PRIME + value) % this.keyMap.length;
    }
    
    return total || 1; // 确保不为0
  }
  
  // 双重散列解决冲突
  _doubleHash(key, attempt) {
    const hash1 = this._hash(key);
    const hash2 = this._hash2(key);
    return (hash1 + attempt * hash2) % this.keyMap.length;
  }
  
  // 设置键值对
  set(key, value) {
    let attempt = 0;
    let index = this._doubleHash(key, attempt);
    
    // 处理冲突
    while (this.keyMap[index] && this.keyMap[index][0] !== key) {
      attempt++;
      index = this._doubleHash(key, attempt);
      
      if (attempt > this.keyMap.length) {
        throw new Error('哈希表已满');
      }
    }
    
    this.keyMap[index] = [key, value];
  }
  
  // 获取值
  get(key) {
    let attempt = 0;
    let index = this._doubleHash(key, attempt);
    
    while (this.keyMap[index]) {
      if (this.keyMap[index][0] === key) {
        return this.keyMap[index][1];
      }
      attempt++;
      index = this._doubleHash(key, attempt);
    }
    
    return undefined;
  }
  
  // 获取所有键
  keys() {
    const keysArr = [];
    
    for (let i = 0; i < this.keyMap.length; i++) {
      if (this.keyMap[i]) {
        keysArr.push(this.keyMap[i][0]);
      }
    }
    
    return keysArr;
  }
  
  // 获取所有值
  values() {
    const valuesArr = [];
    
    for (let i = 0; i < this.keyMap.length; i++) {
      if (this.keyMap[i]) {
        // 避免重复值
        if (!valuesArr.includes(this.keyMap[i][1])) {
          valuesArr.push(this.keyMap[i][1]);
        }
      }
    }
    
    return valuesArr;
  }
}

八、排序算法优化

8.1 快速排序优化
javascript 复制代码
class SortingAlgorithms {
  // 快速排序(原地排序)
  static quickSort(arr, left = 0, right = arr.length - 1) {
    if (left < right) {
      const pivotIndex = this.partition(arr, left, right);
      this.quickSort(arr, left, pivotIndex - 1);
      this.quickSort(arr, pivotIndex + 1, right);
    }
    return arr;
  }
  
  static partition(arr, left, right) {
    const pivot = arr[Math.floor((left + right) / 2)];
    let i = left;
    let j = right;
    
    while (i <= j) {
      while (arr[i] < pivot) {
        i++;
      }
      while (arr[j] > pivot) {
        j--;
      }
      if (i <= j) {
        [arr[i], arr[j]] = [arr[j], arr[i]];
        i++;
        j--;
      }
    }
    
    return i;
  }
  
  // 归并排序
  static mergeSort(arr) {
    if (arr.length <= 1) return arr;
    
    const mid = Math.floor(arr.length / 2);
    const left = this.mergeSort(arr.slice(0, mid));
    const right = this.mergeSort(arr.slice(mid));
    
    return this.merge(left, right);
  }
  
  static merge(left, right) {
    const result = [];
    let i = 0;
    let j = 0;
    
    while (i < left.length && j < right.length) {
      if (left[i] < right[j]) {
        result.push(left[i]);
        i++;
      } else {
        result.push(right[j]);
        j++;
      }
    }
    
    return result.concat(left.slice(i), right.slice(j));
  }
  
  // 堆排序
  static heapSort(arr) {
    const n = arr.length;
    
    // 构建最大堆
    for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
      this.heapify(arr, n, i);
    }
    
    // 一个个提取元素
    for (let i = n - 1; i > 0; i--) {
      [arr[0], arr[i]] = [arr[i], arr[0]];
      this.heapify(arr, i, 0);
    }
    
    return arr;
  }
  
  static heapify(arr, n, i) {
    let largest = i;
    const left = 2 * i + 1;
    const right = 2 * i + 2;
    
    if (left < n && arr[left] > arr[largest]) {
      largest = left;
    }
    
    if (right < n && arr[right] > arr[largest]) {
      largest = right;
    }
    
    if (largest !== i) {
      [arr[i], arr[largest]] = [arr[largest], arr[i]];
      this.heapify(arr, n, largest);
    }
  }
  
  // 性能比较
  static performanceTest() {
    const sizes = [1000, 10000, 100000];
    
    for (const size of sizes) {
      const arr = Array.from({ length: size }, () => 
        Math.floor(Math.random() * size)
      );
      
      console.log(`\n测试数组大小: ${size}`);
      
      // 快速排序
      const arr1 = [...arr];
      console.time('快速排序');
      this.quickSort(arr1);
      console.timeEnd('快速排序');
      
      // 归并排序
      const arr2 = [...arr];
      console.time('归并排序');
      this.mergeSort(arr2);
      console.timeEnd('归并排序');
      
      // 堆排序
      const arr3 = [...arr];
      console.time('堆排序');
      this.heapSort(arr3);
      console.timeEnd('堆排序');
      
      // 内置排序
      const arr4 = [...arr];
      console.time('内置排序');
      arr4.sort((a, b) => a - b);
      console.timeEnd('内置排序');
    }
  }
}

九、搜索算法优化

9.1 二分查找及其变体
javascript 复制代码
class SearchAlgorithms {
  // 标准二分查找
  static binarySearch(arr, target) {
    let left = 0;
    let right = arr.length - 1;
    
    while (left <= right) {
      const mid = Math.floor((left + right) / 2);
      
      if (arr[mid] === target) {
        return mid;
      } else if (arr[mid] < target) {
        left = mid + 1;
      } else {
        right = mid - 1;
      }
    }
    
    return -1;
  }
  
  // 查找第一个等于目标值的位置
  static binarySearchFirst(arr, target) {
    let left = 0;
    let right = arr.length - 1;
    let result = -1;
    
    while (left <= right) {
      const mid = Math.floor((left + right) / 2);
      
      if (arr[mid] >= target) {
        if (arr[mid] === target) {
          result = mid;
        }
        right = mid - 1;
      } else {
        left = mid + 1;
      }
    }
    
    return result;
  }
  
  // 查找最后一个等于目标值的位置
  static binarySearchLast(arr, target) {
    let left = 0;
    let right = arr.length - 1;
    let result = -1;
    
    while (left <= right) {
      const mid = Math.floor((left + right) / 2);
      
      if (arr[mid] <= target) {
        if (arr[mid] === target) {
          result = mid;
        }
        left = mid + 1;
      } else {
        right = mid - 1;
      }
    }
    
    return result;
  }
  
  // 查找第一个大于等于目标值的位置
  static binarySearchCeil(arr, target) {
    let left = 0;
    let right = arr.length - 1;
    let result = -1;
    
    while (left <= right) {
      const mid = Math.floor((left + right) / 2);
      
      if (arr[mid] >= target) {
        result = mid;
        right = mid - 1;
      } else {
        left = mid + 1;
      }
    }
    
    return result;
  }
  
  // 插值查找(适用于均匀分布的有序数组)
  static interpolationSearch(arr, target) {
    let low = 0;
    let high = arr.length - 1;
    
    while (low <= high && target >= arr[low] && target <= arr[high]) {
      if (low === high) {
        return arr[low] === target ? low : -1;
      }
      
      // 计算插值位置
      const pos = low + Math.floor(
        ((target - arr[low]) * (high - low)) / (arr[high] - arr[low])
      );
      
      if (arr[pos] === target) {
        return pos;
      } else if (arr[pos] < target) {
        low = pos + 1;
      } else {
        high = pos - 1;
      }
    }
    
    return -1;
  }
}

十、实际应用场景

10.1 虚拟DOM diff算法中的优化
javascript 复制代码
class VNode {
  constructor(tag, props, children) {
    this.tag = tag;
    this.props = props || {};
    this.children = children || [];
    this.key = props && props.key;
  }
}

class VirtualDOM {
  // 简化的diff算法
  static diff(oldVNode, newVNode) {
    // 如果标签不同,直接替换
    if (oldVNode.tag !== newVNode.tag) {
      return { type: 'REPLACE', node: newVNode };
    }
    
    // 如果都有key且不同,移动节点
    if (oldVNode.key !== newVNode.key) {
      return { type: 'REORDER', moves: this.calculateMoves(oldVNode, newVNode) };
    }
    
    // 比较属性
    const propsPatches = this.diffProps(oldVNode.props, newVNode.props);
    
    // 比较子节点
    const childrenPatches = this.diffChildren(oldVNode.children, newVNode.children);
    
    return {
      type: 'UPDATE',
      props: propsPatches,
      children: childrenPatches
    };
  }
  
  static diffProps(oldProps, newProps) {
    const patches = {};
    const allKeys = new Set([
      ...Object.keys(oldProps),
      ...Object.keys(newProps)
    ]);
    
    for (const key of allKeys) {
      if (oldProps[key] !== newProps[key]) {
        patches[key] = newProps[key];
      }
    }
    
    return patches;
  }
  
  static diffChildren(oldChildren, newChildren) {
    const patches = [];
    const len = Math.max(oldChildren.length, newChildren.length);
    
    for (let i = 0; i < len; i++) {
      const oldChild = oldChildren[i];
      const newChild = newChildren[i];
      
      if (!oldChild && newChild) {
        patches.push({ type: 'INSERT', node: newChild });
      } else if (oldChild && !newChild) {
        patches.push({ type: 'REMOVE' });
      } else if (oldChild && newChild) {
        patches.push(this.diff(oldChild, newChild));
      }
    }
    
    return patches;
  }
  
  static calculateMoves(oldNode, newNode) {
    // 简化的移动计算,实际实现更复杂
    return [];
  }
}
10.2 状态管理中的优化
javascript 复制代码
class OptimizedStore {
  constructor(reducer, initialState) {
    this.state = initialState;
    this.reducer = reducer;
    this.listeners = new Set();
    this.isDispatching = false;
  }
  
  getState() {
    if (this.isDispatching) {
      throw new Error('不能在reducer执行中获取状态');
    }
    return this.state;
  }
  
  dispatch(action) {
    if (this.isDispatching) {
      throw new Error('不能在reducer执行中dispatch');
    }
    
    try {
      this.isDispatching = true;
      this.state = this.reducer(this.state, action);
    } finally {
      this.isDispatching = false;
    }
    
    // 通知所有监听器
    this.listeners.forEach(listener => listener());
  }
  
  subscribe(listener) {
    this.listeners.add(listener);
    
    // 返回取消订阅的函数
    return () => {
      this.listeners.delete(listener);
    };
  }
  
  // 选择器优化:记忆化
  createSelector(...funcs) {
    const resultFunc = funcs.pop();
    const dependencies = funcs;
    let lastArgs = [];
    let lastResult;
    
    return (...args) => {
      if (lastArgs.length === args.length && 
          lastArgs.every((arg, i) => arg === args[i])) {
        return lastResult;
      }
      
      const dependenciesResults = dependencies.map(fn => fn(...args));
      lastResult = resultFunc(...dependenciesResults);
      lastArgs = args;
      
      return lastResult;
    };
  }
}

总结

JavaScript性能优化离不开对数据结构和算法的深入理解。本文涵盖了从基础数据结构到高级算法优化的完整体系,包括:

  1. 数据结构选择策略: 根据不同场景选择最合适的数据结构
  2. 链表及其变体: 单向链表、双向链表的实现与应用
  3. 栈和队列: 基础实现及其在算法中的应用
  4. 树结构: 二叉树、平衡树的实现与遍历优化
  5. 缓存机制: LRU缓存的实现原理
  6. 图算法: 遍历、最短路径等核心算法
  7. 散列表: 哈希函数设计与冲突解决
  8. 排序搜索: 各类算法的性能比较与优化
  9. 实际应用: 在前端框架和状态管理中的实践

在实际开发中,需要根据具体场景选择合适的数据结构和算法。对于大多数前端应用,合理使用Map、Set等内置数据结构,结合适当的算法优化,就能显著提升性能。对于复杂场景,则需要深入理解各种数据结构的特性,做出最优选择。

记住,没有绝对最优的数据结构,只有在特定场景下的最适合选择。持续学习和实践,才能在性能优化这条道路上越走越远。

相关推荐
沐风。562 小时前
TypeScript
前端·javascript·typescript
用户47949283569152 小时前
XSS、CSRF、CSP、HttpOnly 全扫盲:前端安全不只是后端的事
前端·后端·面试
O***p6042 小时前
当“前端虚拟化”成为可能:构建下一代 Web 应用的新范式
前端
kaikaile19952 小时前
MATLAB 灰度图像的二维傅里叶变换
算法·计算机视觉·matlab
仰泳的熊猫2 小时前
1112 Stucked Keyboard
数据结构·c++·算法·pat考试
roman_日积跬步-终至千里2 小时前
【计算机算法与设计(14)】例题五:最小生成树:Prim算法详细解释:π的含义、更新逻辑和选点原因
算法
孤酒独酌2 小时前
一次断网重连引发的「模块加载缓存」攻坚战
前端
让学习成为一种生活方式2 小时前
压缩文件夹下下所有文件成压缩包tar.gz--随笔016
算法
jinzeming9992 小时前
Vue3 PDF 预览组件设计与实现分析
前端