引言
在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性能优化离不开对数据结构和算法的深入理解。本文涵盖了从基础数据结构到高级算法优化的完整体系,包括:
- 数据结构选择策略: 根据不同场景选择最合适的数据结构
- 链表及其变体: 单向链表、双向链表的实现与应用
- 栈和队列: 基础实现及其在算法中的应用
- 树结构: 二叉树、平衡树的实现与遍历优化
- 缓存机制: LRU缓存的实现原理
- 图算法: 遍历、最短路径等核心算法
- 散列表: 哈希函数设计与冲突解决
- 排序搜索: 各类算法的性能比较与优化
- 实际应用: 在前端框架和状态管理中的实践
在实际开发中,需要根据具体场景选择合适的数据结构和算法。对于大多数前端应用,合理使用Map、Set等内置数据结构,结合适当的算法优化,就能显著提升性能。对于复杂场景,则需要深入理解各种数据结构的特性,做出最优选择。
记住,没有绝对最优的数据结构,只有在特定场景下的最适合选择。持续学习和实践,才能在性能优化这条道路上越走越远。