外观
可视化工具
工具概述
JavaScript 算法可视化工具通过图形化展示算法执行过程,将抽象的计算逻辑转化为直观的视觉表现。这类工具帮助开发者理解算法内在机制、调试复杂逻辑,并为教学和演示提供生动素材。
核心可视化流程:
算法输入 → 执行步骤分解 → 图形元素映射 → 动画渲染
↓
交互控制 ← 状态显示核心架构设计
可视化引擎基础
javascript
// 可视化引擎基类
export class AlgorithmVisualizer {
constructor(container, options = {}) {
this.container = container;
this.options = {
speed: 1.0,
autoPlay: false,
highlightColor: '#ff6b6b',
compareColor: '#4ecdc4',
sortedColor: '#45b7d1',
...options
};
this.states = [];
this.currentStep = 0;
this.isPlaying = false;
this.animationFrameId = null;
this.initCanvas();
this.initControls();
}
// 初始化画布
initCanvas() {
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
// 响应式画布
this.resizeCanvas();
window.addEventListener('resize', () => this.resizeCanvas());
this.container.appendChild(this.canvas);
}
// 调整画布尺寸
resizeCanvas() {
const rect = this.container.getBoundingClientRect();
this.canvas.width = rect.width;
this.canvas.height = rect.height;
this.render();
}
// 初始化控制界面
initControls() {
this.controls = document.createElement('div');
this.controls.className = 'visualizer-controls';
this.controls.innerHTML = `
<button id="play-pause">▶</button>
<button id="step-back">⏮</button>
<button id="step-forward">⏭</button>
<input type="range" id="speed" min="0.1" max="5" step="0.1" value="${this.options.speed}">
<span id="step-counter">步骤: 0/0</span>
`;
this.container.appendChild(this.controls);
this.bindControlEvents();
}
// 绑定控制事件
bindControlEvents() {
document.getElementById('play-pause').addEventListener('click', () => this.togglePlay());
document.getElementById('step-back').addEventListener('click', () => this.stepBack());
document.getElementById('step-forward').addEventListener('click', () => this.stepForward());
document.getElementById('speed').addEventListener('input', (e) => {
this.options.speed = parseFloat(e.target.value);
});
}
// 记录算法状态
recordState(data, highlights = [], metadata = {}) {
this.states.push({
data: [...data],
highlights: [...highlights],
metadata: { ...metadata, step: this.states.length }
});
}
// 播放控制
togglePlay() {
this.isPlaying = !this.isPlaying;
const button = document.getElementById('play-pause');
button.textContent = this.isPlaying ? '⏸' : '▶';
if (this.isPlaying) {
this.play();
} else {
this.pause();
}
}
play() {
const playStep = () => {
if (this.isPlaying && this.currentStep < this.states.length - 1) {
this.currentStep++;
this.render();
this.updateStepCounter();
const delay = 1000 / this.options.speed;
this.animationFrameId = setTimeout(playStep, delay);
} else {
this.isPlaying = false;
document.getElementById('play-pause').textContent = '▶';
}
};
playStep();
}
pause() {
if (this.animationFrameId) {
clearTimeout(this.animationFrameId);
this.animationFrameId = null;
}
}
stepForward() {
if (this.currentStep < this.states.length - 1) {
this.currentStep++;
this.render();
this.updateStepCounter();
}
}
stepBack() {
if (this.currentStep > 0) {
this.currentStep--;
this.render();
this.updateStepCounter();
}
}
updateStepCounter() {
const counter = document.getElementById('step-counter');
counter.textContent = `步骤: ${this.currentStep}/${this.states.length - 1}`;
}
// 抽象渲染方法 - 由子类实现
render() {
throw new Error('render method must be implemented by subclass');
}
}排序算法可视化器
javascript
// 排序算法可视化器
export class SortingVisualizer extends AlgorithmVisualizer {
constructor(container, options = {}) {
super(container, options);
this.data = [];
this.maxValue = 1;
}
// 初始化数据
initData(size = 20, dataType = 'random') {
this.data = [];
this.states = [];
this.currentStep = 0;
switch (dataType) {
case 'random':
this.data = Array.from({ length: size }, () =>
Math.floor(Math.random() * 100) + 1
);
break;
case 'sorted':
this.data = Array.from({ length: size }, (_, i) => i + 1);
break;
case 'reversed':
this.data = Array.from({ length: size }, (_, i) => size - i);
break;
case 'nearly-sorted':
this.data = Array.from({ length: size }, (_, i) => i + 1);
// 随机交换几对元素
for (let i = 0; i < size / 10; i++) {
const a = Math.floor(Math.random() * size);
const b = Math.floor(Math.random() * size);
[this.data[a], this.data[b]] = [this.data[b], this.data[a]];
}
break;
}
this.maxValue = Math.max(...this.data);
this.recordState(this.data, [], { type: 'initial' });
}
// 可视化冒泡排序
*bubbleSort() {
const arr = [...this.data];
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - i - 1; j++) {
// 高亮比较的元素
this.recordState(arr, [j, j + 1], {
type: 'compare',
indices: [j, j + 1]
});
yield;
if (arr[j] > arr[j + 1]) {
// 交换元素
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
this.recordState(arr, [j, j + 1], {
type: 'swap',
indices: [j, j + 1]
});
yield;
}
}
// 标记已排序的元素
this.recordState(arr, [], {
type: 'sorted',
indices: [n - i - 1, n - 1]
});
}
this.recordState(arr, [], { type: 'complete' });
}
// 可视化快速排序
*quickSort(low = 0, high = this.data.length - 1, arr = [...this.data]) {
if (low < high) {
const pivotIndex = yield* this.partition(low, high, arr);
yield* this.quickSort(low, pivotIndex - 1, arr);
yield* this.quickSort(pivotIndex + 1, high, arr);
}
if (low === 0 && high === this.data.length - 1) {
this.recordState(arr, [], { type: 'complete' });
}
}
*partition(low, high, arr) {
const pivot = arr[high];
let i = low - 1;
this.recordState(arr, [high], { type: 'pivot', index: high });
yield;
for (let j = low; j < high; j++) {
this.recordState(arr, [j, high], { type: 'compare', indices: [j, high] });
yield;
if (arr[j] <= pivot) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]];
this.recordState(arr, [i, j], { type: 'swap', indices: [i, j] });
yield;
}
}
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
this.recordState(arr, [i + 1, high], { type: 'swap', indices: [i + 1, high] });
yield;
return i + 1;
}
// 渲染排序可视化
render() {
const state = this.states[this.currentStep];
if (!state) return;
const { data, highlights, metadata } = state;
const ctx = this.ctx;
const width = this.canvas.width;
const height = this.canvas.height;
ctx.clearRect(0, 0, width, height);
const barWidth = width / data.length;
const scale = height / this.maxValue;
// 绘制数据条
data.forEach((value, index) => {
const barHeight = value * scale;
const x = index * barWidth;
const y = height - barHeight;
// 确定颜色
let color = '#3498db'; // 默认蓝色
if (metadata.type === 'complete') {
color = this.options.sortedColor;
} else if (highlights.includes(index)) {
if (metadata.type === 'compare') {
color = this.options.compareColor;
} else if (metadata.type === 'swap') {
color = this.options.highlightColor;
} else if (metadata.type === 'pivot' && metadata.index === index) {
color = '#9b59b6'; // 紫色表示枢轴
}
}
// 绘制条形
ctx.fillStyle = color;
ctx.fillRect(x, y, barWidth - 1, barHeight);
// 绘制数值标签(如果空间足够)
if (barWidth > 20) {
ctx.fillStyle = '#2c3e50';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText(value, x + barWidth / 2, y - 5);
}
});
// 绘制状态信息
ctx.fillStyle = '#2c3e50';
ctx.font = '14px Arial';
ctx.textAlign = 'left';
ctx.fillText(`操作: ${this.getOperationText(metadata)}`, 10, 20);
ctx.fillText(`比较次数: ${this.getComparisonCount()}`, 10, 40);
ctx.fillText(`交换次数: ${this.getSwapCount()}`, 10, 60);
}
getOperationText(metadata) {
const operations = {
'initial': '初始化',
'compare': '比较元素',
'swap': '交换元素',
'pivot': '选择枢轴',
'sorted': '部分排序完成',
'complete': '排序完成'
};
return operations[metadata.type] || metadata.type;
}
getComparisonCount() {
return this.states.slice(0, this.currentStep + 1)
.filter(state => state.metadata.type === 'compare').length;
}
getSwapCount() {
return this.states.slice(0, this.currentStep + 1)
.filter(state => state.metadata.type === 'swap').length;
}
}图形渲染技术
Canvas 高级渲染
javascript
// 高级 Canvas 渲染器
export class AdvancedRenderer {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.animations = new Map();
this.animationId = 0;
}
// 绘制数组条形图
drawBarChart(data, options = {}) {
const {
x = 0,
y = 0,
width = this.canvas.width,
height = this.canvas.height,
colors = ['#3498db'],
spacing = 1,
showValues = true
} = options;
const barWidth = (width - (data.length - 1) * spacing) / data.length;
const maxValue = Math.max(...data);
const scale = height / maxValue;
data.forEach((value, index) => {
const barHeight = value * scale;
const barX = x + index * (barWidth + spacing);
const barY = y + height - barHeight;
// 选择颜色
const color = Array.isArray(colors) ?
colors[index % colors.length] : colors;
// 绘制条形
this.ctx.fillStyle = color;
this.ctx.fillRect(barX, barY, barWidth, barHeight);
// 绘制边框
this.ctx.strokeStyle = '#2c3e50';
this.ctx.lineWidth = 1;
this.ctx.strokeRect(barX, barY, barWidth, barHeight);
// 绘制数值
if (showValues && barWidth > 25) {
this.ctx.fillStyle = '#2c3e50';
this.ctx.font = '10px Arial';
this.ctx.textAlign = 'center';
this.ctx.fillText(
value.toString(),
barX + barWidth / 2,
barY - 5
);
}
});
}
// 绘制树形结构
drawTree(root, options = {}) {
const {
x = this.canvas.width / 2,
y = 50,
nodeRadius = 20,
levelHeight = 80,
highlightNodes = new Set()
} = options;
const drawNode = (node, x, y, level) => {
// 绘制连接线(先绘制线,再绘制节点)
if (node.left) {
const childX = x - (this.canvas.width / Math.pow(2, level + 2));
const childY = y + levelHeight;
this.drawLine(x, y + nodeRadius, childX, childY - nodeRadius);
drawNode(node.left, childX, childY, level + 1);
}
if (node.right) {
const childX = x + (this.canvas.width / Math.pow(2, level + 2));
const childY = y + levelHeight;
this.drawLine(x, y + nodeRadius, childX, childY - nodeRadius);
drawNode(node.right, childX, childY, level + 1);
}
// 绘制节点
const isHighlighted = highlightNodes.has(node.value);
this.ctx.fillStyle = isHighlighted ? '#e74c3c' : '#3498db';
this.ctx.beginPath();
this.ctx.arc(x, y, nodeRadius, 0, 2 * Math.PI);
this.ctx.fill();
// 绘制节点边框
this.ctx.strokeStyle = '#2c3e50';
this.ctx.lineWidth = 2;
this.ctx.stroke();
// 绘制节点值
this.ctx.fillStyle = 'white';
this.ctx.font = '12px Arial';
this.ctx.textAlign = 'center';
this.ctx.textBaseline = 'middle';
this.ctx.fillText(node.value.toString(), x, y);
};
drawNode(root, x, y, 0);
}
// 绘制连接线
drawLine(x1, y1, x2, y2, options = {}) {
const {
color = '#95a5a6',
width = 2,
dash = []
} = options;
this.ctx.strokeStyle = color;
this.ctx.lineWidth = width;
this.ctx.setLineDash(dash);
this.ctx.beginPath();
this.ctx.moveTo(x1, y1);
this.ctx.lineTo(x2, y2);
this.ctx.stroke();
this.ctx.setLineDash([]); // 重置虚线
}
// 平滑动画
animateValue(start, end, duration, updateCallback, easing = 'easeInOut') {
const startTime = performance.now();
const animationId = this.animationId++;
const easingFunctions = {
linear: t => t,
easeIn: t => t * t,
easeOut: t => t * (2 - t),
easeInOut: t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
};
const ease = easingFunctions[easing] || easingFunctions.easeInOut;
const animate = (currentTime) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const easedProgress = ease(progress);
const currentValue = start + (end - start) * easedProgress;
updateCallback(currentValue);
if (progress < 1) {
this.animations.set(animationId, requestAnimationFrame(animate));
} else {
this.animations.delete(animationId);
}
};
this.animations.set(animationId, requestAnimationFrame(animate));
return animationId;
}
// 停止所有动画
stopAllAnimations() {
this.animations.forEach(animationId => {
cancelAnimationFrame(animationId);
});
this.animations.clear();
}
}图算法可视化
javascript
// 图算法可视化器
export class GraphVisualizer extends AlgorithmVisualizer {
constructor(container, options = {}) {
super(container, {
nodeRadius: 20,
nodeColor: '#3498db',
edgeColor: '#bdc3c7',
visitedColor: '#e74c3c',
pathColor: '#2ecc71',
...options
});
this.graph = {
nodes: new Map(),
edges: new Map()
};
this.layout = new ForceDirectedLayout();
}
// 添加节点
addNode(id, data = {}) {
this.graph.nodes.set(id, {
id,
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
...data
});
}
// 添加边
addEdge(from, to, weight = 1) {
const edgeId = `${from}-${to}`;
this.graph.edges.set(edgeId, { from, to, weight });
}
// 可视化 BFS
*bfs(startNode) {
const visited = new Set();
const queue = [startNode];
visited.add(startNode);
this.recordState({ current: startNode, visited: new Set(visited) });
yield;
while (queue.length > 0) {
const current = queue.shift();
// 获取邻居节点
const neighbors = this.getNeighbors(current);
for (const neighbor of neighbors) {
if (!visited.has(neighbor)) {
visited.add(neighbor);
queue.push(neighbor);
this.recordState({
current: neighbor,
visited: new Set(visited),
processing: current
});
yield;
}
}
}
this.recordState({ visited: new Set(visited), complete: true });
}
// 可视化 Dijkstra 算法
*dijkstra(startNode) {
const distances = new Map();
const visited = new Set();
const previous = new Map();
// 初始化距离
for (const nodeId of this.graph.nodes.keys()) {
distances.set(nodeId, nodeId === startNode ? 0 : Infinity);
}
while (visited.size < this.graph.nodes.size) {
// 找到未访问的最小距离节点
let current = null;
let minDistance = Infinity;
for (const [nodeId, distance] of distances) {
if (!visited.has(nodeId) && distance < minDistance) {
minDistance = distance;
current = nodeId;
}
}
if (current === null) break;
visited.add(current);
this.recordState({
current,
visited: new Set(visited),
distances: new Map(distances),
previous: new Map(previous)
});
yield;
// 更新邻居距离
const neighbors = this.getNeighbors(current);
for (const neighbor of neighbors) {
if (!visited.has(neighbor)) {
const edge = this.graph.edges.get(`${current}-${neighbor}`) ||
this.graph.edges.get(`${neighbor}-${current}`);
const newDistance = distances.get(current) + edge.weight;
if (newDistance < distances.get(neighbor)) {
distances.set(neighbor, newDistance);
previous.set(neighbor, current);
this.recordState({
current: neighbor,
visited: new Set(visited),
distances: new Map(distances),
previous: new Map(previous),
updated: true
});
yield;
}
}
}
}
this.recordState({ complete: true, distances, previous });
}
getNeighbors(nodeId) {
const neighbors = new Set();
for (const [edgeId, edge] of this.graph.edges) {
if (edge.from === nodeId) neighbors.add(edge.to);
if (edge.to === nodeId) neighbors.add(edge.from);
}
return Array.from(neighbors);
}
// 渲染图
render() {
const state = this.states[this.currentStep] || {};
const ctx = this.ctx;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制边
for (const [edgeId, edge] of this.graph.edges) {
const fromNode = this.graph.nodes.get(edge.from);
const toNode = this.graph.nodes.get(edge.to);
if (fromNode && toNode) {
this.drawEdge(fromNode, toNode, edge, state);
}
}
// 绘制节点
for (const [nodeId, node] of this.graph.nodes) {
this.drawNode(node, state);
}
}
drawEdge(fromNode, toNode, edge, state) {
const ctx = this.ctx;
// 确定边颜色
let color = this.options.edgeColor;
if (state.complete) {
color = this.options.pathColor;
}
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(fromNode.x, fromNode.y);
ctx.lineTo(toNode.x, toNode.y);
ctx.stroke();
// 绘制权重
const midX = (fromNode.x + toNode.x) / 2;
const midY = (fromNode.y + toNode.y) / 2;
ctx.fillStyle = 'white';
ctx.strokeStyle = color;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(midX, midY, 12, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
ctx.fillStyle = '#2c3e50';
ctx.font = '10px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(edge.weight.toString(), midX, midY);
}
drawNode(node, state) {
const ctx = this.ctx;
// 确定节点颜色
let color = this.options.nodeColor;
if (state.visited && state.visited.has(node.id)) {
color = this.options.visitedColor;
}
if (state.current === node.id) {
color = '#f39c12'; // 当前节点用橙色
}
if (state.complete) {
color = this.options.pathColor;
}
// 绘制节点
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(node.x, node.y, this.options.nodeRadius, 0, 2 * Math.PI);
ctx.fill();
// 绘制节点边框
ctx.strokeStyle = '#2c3e50';
ctx.lineWidth = 2;
ctx.stroke();
// 绘制节点标签
ctx.fillStyle = 'white';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(node.id, node.x, node.y);
// 显示距离(如果存在)
if (state.distances && state.distances.has(node.id)) {
const distance = state.distances.get(node.id);
if (distance !== Infinity) {
ctx.fillStyle = '#2c3e50';
ctx.font = '10px Arial';
ctx.fillText(
distance.toString(),
node.x,
node.y + this.options.nodeRadius + 15
);
}
}
}
}
// 力导向布局
class ForceDirectedLayout {
constructor() {
this.springLength = 100;
this.springStrength = 0.1;
this.repulsionStrength = 1000;
}
updatePositions(nodes, edges, width, height) {
// 简化的力导向布局实现
// 实际实现会更复杂,包含斥力和引力的计算
for (const [_, node] of nodes) {
// 添加随机扰动避免重叠
node.x += (Math.random() - 0.5) * 2;
node.y += (Math.random() - 0.5) * 2;
// 边界检查
node.x = Math.max(50, Math.min(width - 50, node.x));
node.y = Math.max(50, Math.min(height - 50, node.y));
}
}
}交互功能增强
用户交互处理器
javascript
// 交互处理器
export class InteractionHandler {
constructor(visualizer) {
this.visualizer = visualizer;
this.isDragging = false;
this.draggedNode = null;
this.dragOffset = { x: 0, y: 0 };
this.bindEvents();
}
bindEvents() {
const canvas = this.visualizer.canvas;
canvas.addEventListener('mousedown', (e) => this.onMouseDown(e));
canvas.addEventListener('mousemove', (e) => this.onMouseMove(e));
canvas.addEventListener('mouseup', () => this.onMouseUp());
canvas.addEventListener('wheel', (e) => this.onWheel(e));
// 触摸事件支持
canvas.addEventListener('touchstart', (e) => this.onTouchStart(e));
canvas.addEventListener('touchmove', (e) => this.onTouchMove(e));
canvas.addEventListener('touchend', () => this.onTouchEnd());
}
onMouseDown(e) {
const rect = this.visualizer.canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 检查是否点击了节点
if (this.visualizer.graph) {
this.draggedNode = this.findNodeAt(x, y);
if (this.draggedNode) {
this.isDragging = true;
this.dragOffset.x = x - this.draggedNode.x;
this.dragOffset.y = y - this.draggedNode.y;
e.preventDefault();
}
}
}
onMouseMove(e) {
if (this.isDragging && this.draggedNode) {
const rect = this.visualizer.canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
this.draggedNode.x = x - this.dragOffset.x;
this.draggedNode.y = y - this.dragOffset.y;
this.visualizer.render();
}
}
onMouseUp() {
this.isDragging = false;
this.draggedNode = null;
}
onWheel(e) {
e.preventDefault();
// 缩放功能
const zoomIntensity = 0.1;
const wheel = e.deltaY < 0 ? 1 : -1;
const zoom = Math.exp(wheel * zoomIntensity);
// 更新可视化器的缩放级别
if (this.visualizer.scale) {
this.visualizer.scale *= zoom;
this.visualizer.render();
}
}
onTouchStart(e) {
if (e.touches.length === 1) {
const touch = e.touches[0];
const rect = this.visualizer.canvas.getBoundingClientRect();
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
this.draggedNode = this.findNodeAt(x, y);
if (this.draggedNode) {
this.isDragging = true;
this.dragOffset.x = x - this.draggedNode.x;
this.dragOffset.y = y - this.draggedNode.y;
}
}
}
onTouchMove(e) {
if (this.isDragging && this.draggedNode && e.touches.length === 1) {
const touch = e.touches[0];
const rect = this.visualizer.canvas.getBoundingClientRect();
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
this.draggedNode.x = x - this.dragOffset.x;
this.draggedNode.y = y - this.dragOffset.y;
this.visualizer.render();
}
}
onTouchEnd() {
this.isDragging = false;
this.draggedNode = null;
}
findNodeAt(x, y) {
if (!this.visualizer.graph) return null;
for (const [_, node] of this.visualizer.graph.nodes) {
const distance = Math.sqrt(
Math.pow(node.x - x, 2) + Math.pow(node.y - y, 2)
);
if (distance <= this.visualizer.options.nodeRadius) {
return node;
}
}
return null;
}
}数据导入导出
javascript
// 数据管理器
export class DataManager {
constructor(visualizer) {
this.visualizer = visualizer;
}
// 导出当前状态为 JSON
exportState() {
const state = {
algorithm: this.visualizer.constructor.name,
data: this.visualizer.data || [],
states: this.visualizer.states,
currentStep: this.visualizer.currentStep,
options: this.visualizer.options,
timestamp: new Date().toISOString()
};
if (this.visualizer.graph) {
state.graph = {
nodes: Array.from(this.visualizer.graph.nodes.entries()),
edges: Array.from(this.visualizer.graph.edges.entries())
};
}
return JSON.stringify(state, null, 2);
}
// 从 JSON 导入状态
importState(jsonString) {
try {
const state = JSON.parse(jsonString);
this.visualizer.data = state.data || [];
this.visualizer.states = state.states || [];
this.visualizer.currentStep = state.currentStep || 0;
this.visualizer.options = { ...this.visualizer.options, ...state.options };
if (state.graph && this.visualizer.graph) {
this.visualizer.graph.nodes = new Map(state.graph.nodes);
this.visualizer.graph.edges = new Map(state.graph.edges);
}
this.visualizer.render();
return true;
} catch (error) {
console.error('导入状态失败:', error);
return false;
}
}
// 生成测试数据
generateTestData(type, size) {
switch (type) {
case 'sorting':
return this.generateSortingData(size);
case 'graph':
return this.generateGraphData(size);
case 'tree':
return this.generateTreeData(size);
default:
return [];
}
}
generateSortingData(size) {
return Array.from({ length: size }, () =>
Math.floor(Math.random() * 100) + 1
);
}
generateGraphData(nodeCount) {
const nodes = new Map();
const edges = new Map();
// 创建节点
for (let i = 0; i < nodeCount; i++) {
nodes.set(`Node${i}`, {
id: `Node${i}`,
x: Math.random() * 600 + 50,
y: Math.random() * 400 + 50
});
}
// 创建随机边
const nodeArray = Array.from(nodes.keys());
for (let i = 0; i < nodeCount * 1.5; i++) {
const from = nodeArray[Math.floor(Math.random() * nodeArray.length)];
const to = nodeArray[Math.floor(Math.random() * nodeArray.length)];
if (from !== to) {
const edgeId = `${from}-${to}`;
const reverseEdgeId = `${to}-${from}`;
if (!edges.has(edgeId) && !edges.has(reverseEdgeId)) {
edges.set(edgeId, {
from,
to,
weight: Math.floor(Math.random() * 10) + 1
});
}
}
}
return { nodes, edges };
}
generateTreeData(level) {
// 生成平衡二叉树数据
const generateSubtree = (value, depth) => {
if (depth <= 0) return null;
return {
value,
left: generateSubtree(value * 2, depth - 1),
right: generateSubtree(value * 2 + 1, depth - 1)
};
};
return generateSubtree(1, level);
}
}