1+ // 主要JavaScript逻辑文件
2+ // 包含通用功能和页面初始化
3+
4+ // 全局变量
5+ let currentArray = [ ] ;
6+ let isSorting = false ;
7+ let animationSpeed = 5 ;
8+ let arraySize = 50 ;
9+
10+ // 初始化排序页面
11+ function initializeSortingPage ( ) {
12+ // 绑定事件监听器
13+ document . getElementById ( 'algorithmSelect' ) . addEventListener ( 'change' , updateAlgorithmInfo ) ;
14+ document . getElementById ( 'arraySize' ) . addEventListener ( 'input' , updateArraySize ) ;
15+ document . getElementById ( 'speed' ) . addEventListener ( 'input' , updateSpeed ) ;
16+ document . getElementById ( 'generateArray' ) . addEventListener ( 'click' , generateNewArray ) ;
17+ document . getElementById ( 'startSort' ) . addEventListener ( 'click' , startSorting ) ;
18+ document . getElementById ( 'stopSort' ) . addEventListener ( 'click' , stopSorting ) ;
19+
20+ // 初始化数组
21+ generateNewArray ( ) ;
22+ updateAlgorithmInfo ( ) ;
23+
24+ // 初始化动画
25+ initializeAnimations ( ) ;
26+ }
27+
28+ // 生成新的随机数组
29+ function generateNewArray ( ) {
30+ if ( isSorting ) return ;
31+
32+ currentArray = [ ] ;
33+ const minValue = 10 ;
34+ const maxValue = 400 ;
35+
36+ for ( let i = 0 ; i < arraySize ; i ++ ) {
37+ currentArray . push ( Math . floor ( Math . random ( ) * ( maxValue - minValue + 1 ) ) + minValue ) ;
38+ }
39+
40+ displayArray ( ) ;
41+ resetStatistics ( ) ;
42+ }
43+
44+ // 显示数组可视化
45+ function displayArray ( ) {
46+ const container = document . getElementById ( 'arrayContainer' ) ;
47+ container . innerHTML = '' ;
48+
49+ const maxValue = Math . max ( ...currentArray ) ;
50+ const containerHeight = container . clientHeight - 20 ;
51+
52+ currentArray . forEach ( ( value , index ) => {
53+ const bar = document . createElement ( 'div' ) ;
54+ const height = ( value / maxValue ) * containerHeight ;
55+
56+ bar . className = 'array-bar' ;
57+ bar . style . height = `${ height } px` ;
58+ bar . style . width = `${ Math . max ( 2 , ( container . clientWidth - 40 ) / arraySize - 1 ) } px` ;
59+ bar . style . background = `linear-gradient(to top, #00d4ff, #4ecdc4)` ;
60+ bar . style . marginRight = '1px' ;
61+ bar . id = `bar-${ index } ` ;
62+
63+ // 添加数值标签
64+ const label = document . createElement ( 'div' ) ;
65+ label . textContent = value ;
66+ label . style . position = 'absolute' ;
67+ label . style . bottom = '-20px' ;
68+ label . style . left = '50%' ;
69+ label . style . transform = 'translateX(-50%)' ;
70+ label . style . fontSize = '10px' ;
71+ label . style . color = '#b0b0b0' ;
72+ label . style . display = arraySize <= 20 ? 'block' : 'none' ;
73+
74+ bar . style . position = 'relative' ;
75+ bar . appendChild ( label ) ;
76+
77+ container . appendChild ( bar ) ;
78+ } ) ;
79+ }
80+
81+ // 更新数组大小
82+ function updateArraySize ( ) {
83+ const sizeSlider = document . getElementById ( 'arraySize' ) ;
84+ const sizeValue = document . getElementById ( 'arraySizeValue' ) ;
85+
86+ arraySize = parseInt ( sizeSlider . value ) ;
87+ sizeValue . textContent = arraySize ;
88+
89+ generateNewArray ( ) ;
90+ }
91+
92+ // 更新动画速度
93+ function updateSpeed ( ) {
94+ const speedSlider = document . getElementById ( 'speed' ) ;
95+ const speedValue = document . getElementById ( 'speedValue' ) ;
96+
97+ animationSpeed = parseInt ( speedSlider . value ) ;
98+ speedValue . textContent = animationSpeed ;
99+ }
100+
101+ // 更新算法信息
102+ function updateAlgorithmInfo ( ) {
103+ const algorithm = document . getElementById ( 'algorithmSelect' ) . value ;
104+ const description = document . getElementById ( 'algorithmDescription' ) ;
105+ const bestCase = document . getElementById ( 'bestCase' ) ;
106+ const averageCase = document . getElementById ( 'averageCase' ) ;
107+ const worstCase = document . getElementById ( 'worstCase' ) ;
108+ const spaceComplexity = document . getElementById ( 'spaceComplexity' ) ;
109+ const stability = document . getElementById ( 'stability' ) ;
110+ const code = document . getElementById ( 'algorithmCode' ) ;
111+
112+ const algorithmInfo = {
113+ bubble : {
114+ description : '冒泡排序是一种简单的排序算法,通过重复遍历数组,比较相邻元素并交换位置,使较大的元素逐渐"冒泡"到数组末尾。虽然效率不高,但是稳定排序,适合教学使用。' ,
115+ bestCase : 'O(n)' ,
116+ averageCase : 'O(n²)' ,
117+ worstCase : 'O(n²)' ,
118+ spaceComplexity : 'O(1)' ,
119+ stability : '稳定' ,
120+ code : `function bubbleSort(arr) {
121+ const n = arr.length;
122+ for (let i = 0; i < n - 1; i++) {
123+ let swapped = false;
124+ for (let j = 0; j < n - i - 1; j++) {
125+ if (arr[j] > arr[j + 1]) {
126+ // 交换元素
127+ [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
128+ swapped = true;
129+ }
130+ }
131+ if (!swapped) break; // 优化:如果没有交换,提前结束
132+ }
133+ return arr;
134+ }`
135+ } ,
136+ selection : {
137+ description : '选择排序每次从未排序部分选择最小元素,放到已排序部分的末尾。虽然交换次数较少,但比较次数固定,不稳定排序。' ,
138+ bestCase : 'O(n²)' ,
139+ averageCase : 'O(n²)' ,
140+ worstCase : 'O(n²)' ,
141+ spaceComplexity : 'O(1)' ,
142+ stability : '不稳定' ,
143+ code : `function selectionSort(arr) {
144+ const n = arr.length;
145+ for (let i = 0; i < n - 1; i++) {
146+ let minIndex = i;
147+ for (let j = i + 1; j < n; j++) {
148+ if (arr[j] < arr[minIndex]) {
149+ minIndex = j;
150+ }
151+ }
152+ if (minIndex !== i) {
153+ // 交换元素
154+ [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
155+ }
156+ }
157+ return arr;
158+ }`
159+ } ,
160+ insertion : {
161+ description : '插入排序将数组分为已排序和未排序两部分,逐个将未排序元素插入到已排序部分的适当位置。对于部分有序数组效率很高。' ,
162+ bestCase : 'O(n)' ,
163+ averageCase : 'O(n²)' ,
164+ worstCase : 'O(n²)' ,
165+ spaceComplexity : 'O(1)' ,
166+ stability : '稳定' ,
167+ code : `function insertionSort(arr) {
168+ const n = arr.length;
169+ for (let i = 1; i < n; i++) {
170+ const key = arr[i];
171+ let j = i - 1;
172+
173+ while (j >= 0 && arr[j] > key) {
174+ arr[j + 1] = arr[j];
175+ j--;
176+ }
177+ arr[j + 1] = key;
178+ }
179+ return arr;
180+ }`
181+ } ,
182+ merge : {
183+ description : '归并排序采用分治策略,将数组分成两半,递归排序后再合并。时间复杂度稳定为O(nlogn),但需要额外空间。' ,
184+ bestCase : 'O(nlogn)' ,
185+ averageCase : 'O(nlogn)' ,
186+ worstCase : 'O(nlogn)' ,
187+ spaceComplexity : 'O(n)' ,
188+ stability : '稳定' ,
189+ code : `function mergeSort(arr) {
190+ if (arr.length <= 1) return arr;
191+
192+ const mid = Math.floor(arr.length / 2);
193+ const left = mergeSort(arr.slice(0, mid));
194+ const right = mergeSort(arr.slice(mid));
195+
196+ return merge(left, right);
197+ }
198+
199+ function merge(left, right) {
200+ const result = [];
201+ let leftIndex = 0, rightIndex = 0;
202+
203+ while (leftIndex < left.length && rightIndex < right.length) {
204+ if (left[leftIndex] < right[rightIndex]) {
205+ result.push(left[leftIndex]);
206+ leftIndex++;
207+ } else {
208+ result.push(right[rightIndex]);
209+ rightIndex++;
210+ }
211+ }
212+
213+ return result.concat(left.slice(leftIndex), right.slice(rightIndex));
214+ }`
215+ } ,
216+ quick : {
217+ description : '快速排序选择基准元素,将数组分为小于和大于基准的两部分,递归排序。平均性能极佳,但最坏情况下为O(n²)。' ,
218+ bestCase : 'O(nlogn)' ,
219+ averageCase : 'O(nlogn)' ,
220+ worstCase : 'O(n²)' ,
221+ spaceComplexity : 'O(logn)' ,
222+ stability : '不稳定' ,
223+ code : `function quickSort(arr, low = 0, high = arr.length - 1) {
224+ if (low < high) {
225+ const pivotIndex = partition(arr, low, high);
226+ quickSort(arr, low, pivotIndex - 1);
227+ quickSort(arr, pivotIndex + 1, high);
228+ }
229+ return arr;
230+ }
231+
232+ function partition(arr, low, high) {
233+ const pivot = arr[high];
234+ let i = low - 1;
235+
236+ for (let j = low; j < high; j++) {
237+ if (arr[j] < pivot) {
238+ i++;
239+ [arr[i], arr[j]] = [arr[j], arr[i]];
240+ }
241+ }
242+
243+ [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
244+ return i + 1;
245+ }`
246+ } ,
247+ heap : {
248+ description : '堆排序利用堆数据结构,首先构建最大堆,然后重复取出堆顶元素。时间复杂度稳定为O(nlogn),空间效率高。' ,
249+ bestCase : 'O(nlogn)' ,
250+ averageCase : 'O(nlogn)' ,
251+ worstCase : 'O(nlogn)' ,
252+ spaceComplexity : 'O(1)' ,
253+ stability : '不稳定' ,
254+ code : `function heapSort(arr) {
255+ const n = arr.length;
256+
257+ // 构建最大堆
258+ for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
259+ heapify(arr, n, i);
260+ }
261+
262+ // 一个个从堆中取出元素
263+ for (let i = n - 1; i > 0; i--) {
264+ [arr[0], arr[i]] = [arr[i], arr[0]]; // 交换
265+ heapify(arr, i, 0);
266+ }
267+
268+ return arr;
269+ }
270+
271+ function heapify(arr, n, i) {
272+ let largest = i;
273+ const left = 2 * i + 1;
274+ const right = 2 * i + 2;
275+
276+ if (left < n && arr[left] > arr[largest]) {
277+ largest = left;
278+ }
279+
280+ if (right < n && arr[right] > arr[largest]) {
281+ largest = right;
282+ }
283+
284+ if (largest !== i) {
285+ [arr[i], arr[largest]] = [arr[largest], arr[i]];
286+ heapify(arr, n, largest);
287+ }
288+ }`
289+ }
290+ } ;
291+
292+ const info = algorithmInfo [ algorithm ] ;
293+ if ( info ) {
294+ description . textContent = info . description ;
295+ bestCase . textContent = info . bestCase ;
296+ averageCase . textContent = info . averageCase ;
297+ worstCase . textContent = info . worstCase ;
298+ spaceComplexity . textContent = info . spaceComplexity ;
299+ stability . textContent = info . stability ;
300+ code . textContent = info . code ;
301+ }
302+ }
303+
304+ // 重置统计信息
305+ function resetStatistics ( ) {
306+ document . getElementById ( 'comparisons' ) . textContent = '0' ;
307+ document . getElementById ( 'swaps' ) . textContent = '0' ;
308+ document . getElementById ( 'executionTime' ) . textContent = '0ms' ;
309+ document . getElementById ( 'currentArraySize' ) . textContent = arraySize ;
310+ }
311+
312+ // 初始化动画
313+ function initializeAnimations ( ) {
314+ // 页面加载动画
315+ anime ( {
316+ targets : '.performance-card' ,
317+ translateY : [ 50 , 0 ] ,
318+ opacity : [ 0 , 1 ] ,
319+ duration : 800 ,
320+ delay : anime . stagger ( 200 ) ,
321+ easing : 'easeOutQuart'
322+ } ) ;
323+ }
324+
325+ // 导航栏滚动效果
326+ window . addEventListener ( 'scroll' , function ( ) {
327+ const nav = document . querySelector ( 'nav' ) ;
328+ if ( window . scrollY > 100 ) {
329+ nav . classList . add ( 'bg-gray-900/95' ) ;
330+ } else {
331+ nav . classList . remove ( 'bg-gray-900/95' ) ;
332+ }
333+ } ) ;
334+
335+ // 工具函数:睡眠函数用于动画控制
336+ function sleep ( ms ) {
337+ return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
338+ }
339+
340+ // 工具函数:获取动画延迟时间
341+ function getAnimationDelay ( ) {
342+ return Math . max ( 50 , 1100 - animationSpeed * 100 ) ;
343+ }
344+
345+ // 导出函数供其他文件使用
346+ window . AlgorithmUtils = {
347+ currentArray,
348+ isSorting,
349+ animationSpeed,
350+ arraySize,
351+ generateNewArray,
352+ displayArray,
353+ sleep,
354+ getAnimationDelay,
355+ resetStatistics
356+ } ;
0 commit comments