1bo commited on
Commit
cd8991d
·
verified ·
1 Parent(s): 146ce44

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +1121 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Sort Animal
3
- emoji: 🌖
4
  colorFrom: blue
5
- colorTo: purple
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: sort-animal
3
+ emoji: 🐳
4
  colorFrom: blue
5
+ colorTo: yellow
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1121 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>算法可视化 - 排序算法</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500;700&display=swap');
11
+
12
+ :root {
13
+ --primary: #6366f1;
14
+ --secondary: #8b5cf6;
15
+ --accent: #ec4899;
16
+ --dark: #1e293b;
17
+ --darker: #0f172a;
18
+ }
19
+
20
+ body {
21
+ font-family: 'Roboto Mono', monospace;
22
+ background-color: var(--darker);
23
+ color: white;
24
+ overflow-x: hidden;
25
+ }
26
+
27
+ .array-bar {
28
+ transition: all 0.3s ease;
29
+ display: flex;
30
+ align-items: flex-end;
31
+ justify-content: center;
32
+ color: white;
33
+ font-weight: bold;
34
+ border-radius: 4px 4px 0 0;
35
+ background-color: var(--primary);
36
+ position: relative;
37
+ }
38
+
39
+ .array-bar.comparing {
40
+ background-color: var(--accent);
41
+ transform: scale(1.05);
42
+ }
43
+
44
+ .array-bar.sorted {
45
+ background-color: #10b981;
46
+ }
47
+
48
+ .array-bar.pivot {
49
+ background-color: #f59e0b;
50
+ }
51
+
52
+ .array-bar.swapping {
53
+ background-color: #ef4444;
54
+ }
55
+
56
+ .array-bar.min {
57
+ background-color: #3b82f6;
58
+ }
59
+
60
+ .code-line.highlight {
61
+ background-color: rgba(99, 102, 241, 0.2);
62
+ border-left: 3px solid var(--primary);
63
+ }
64
+
65
+ .visualization-container {
66
+ perspective: 1000px;
67
+ }
68
+
69
+ .algorithm-card {
70
+ transition: all 0.3s ease;
71
+ transform-style: preserve-3d;
72
+ }
73
+
74
+ .algorithm-card:hover {
75
+ transform: translateY(-5px);
76
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
77
+ }
78
+
79
+ @keyframes pulse {
80
+ 0% { transform: scale(1); }
81
+ 50% { transform: scale(1.05); }
82
+ 100% { transform: scale(1); }
83
+ }
84
+
85
+ .pulse {
86
+ animation: pulse 1.5s infinite;
87
+ }
88
+
89
+ .tooltip {
90
+ position: relative;
91
+ }
92
+
93
+ .tooltip-text {
94
+ visibility: hidden;
95
+ width: 200px;
96
+ background-color: var(--dark);
97
+ color: #fff;
98
+ text-align: center;
99
+ border-radius: 6px;
100
+ padding: 8px;
101
+ position: absolute;
102
+ z-index: 1;
103
+ bottom: 125%;
104
+ left: 50%;
105
+ transform: translateX(-50%);
106
+ opacity: 0;
107
+ transition: opacity 0.3s;
108
+ }
109
+
110
+ .tooltip:hover .tooltip-text {
111
+ visibility: visible;
112
+ opacity: 1;
113
+ }
114
+
115
+ .slider-thumb::-webkit-slider-thumb {
116
+ -webkit-appearance: none;
117
+ appearance: none;
118
+ width: 20px;
119
+ height: 20px;
120
+ border-radius: 50%;
121
+ background: var(--primary);
122
+ cursor: pointer;
123
+ }
124
+
125
+ .slider-thumb::-moz-range-thumb {
126
+ width: 20px;
127
+ height: 20px;
128
+ border-radius: 50%;
129
+ background: var(--primary);
130
+ cursor: pointer;
131
+ }
132
+ </style>
133
+ </head>
134
+ <body class="min-h-screen">
135
+ <!-- Header -->
136
+ <header class="bg-gradient-to-r from-indigo-900 to-purple-900 py-6 shadow-lg">
137
+ <div class="container mx-auto px-4">
138
+ <div class="flex flex-col md:flex-row justify-between items-center">
139
+ <h1 class="text-3xl font-bold text-white mb-4 md:mb-0">
140
+ <i class="fas fa-sort-amount-down-alt mr-2"></i>
141
+ 排序算法可视化
142
+ </h1>
143
+ <div class="flex items-center space-x-4">
144
+ <div class="tooltip">
145
+ <button id="reset-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg transition">
146
+ <i class="fas fa-redo mr-2"></i>重置
147
+ </button>
148
+ <span class="tooltip-text">重置当前算法的可视化</span>
149
+ </div>
150
+ <div class="tooltip">
151
+ <button id="randomize-btn" class="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg transition">
152
+ <i class="fas fa-random mr-2"></i>随机化
153
+ </button>
154
+ <span class="tooltip-text">生成新的随机数组</span>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ </header>
160
+
161
+ <!-- Main Content -->
162
+ <main class="container mx-auto px-4 py-8">
163
+ <!-- Controls -->
164
+ <div class="bg-slate-800 rounded-xl p-6 mb-8 shadow-lg">
165
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
166
+ <div>
167
+ <label for="array-size" class="block text-sm font-medium mb-2">数组大小</label>
168
+ <input type="range" id="array-size" min="5" max="30" value="15" class="w-full slider-thumb">
169
+ <div class="flex justify-between text-xs text-gray-400 mt-1">
170
+ <span>5</span>
171
+ <span>30</span>
172
+ </div>
173
+ </div>
174
+ <div>
175
+ <label for="speed" class="block text-sm font-medium mb-2">动画速度</label>
176
+ <input type="range" id="speed" min="1" max="10" value="5" class="w-full slider-thumb">
177
+ <div class="flex justify-between text-xs text-gray-400 mt-1">
178
+ <span>慢</span>
179
+ <span>快</span>
180
+ </div>
181
+ </div>
182
+ <div>
183
+ <label for="algorithm" class="block text-sm font-medium mb-2">排序算法</label>
184
+ <select id="algorithm" class="w-full bg-slate-700 border border-slate-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
185
+ <option value="bubble">冒泡排序</option>
186
+ <option value="selection">选择排序</option>
187
+ <option value="insertion">插入排序</option>
188
+ <option value="merge">归并排序</option>
189
+ <option value="quick">快速排序</option>
190
+ <option value="heap">堆排序</option>
191
+ </select>
192
+ </div>
193
+ </div>
194
+ </div>
195
+
196
+ <!-- Visualization Area -->
197
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
198
+ <!-- Visualization -->
199
+ <div class="lg:col-span-2">
200
+ <div class="bg-slate-800 rounded-xl p-6 shadow-lg">
201
+ <h2 class="text-xl font-semibold mb-4 flex items-center">
202
+ <i class="fas fa-chart-bar mr-2"></i>
203
+ <span id="algorithm-name">冒泡排序</span> 可视化
204
+ </h2>
205
+ <div class="visualization-container">
206
+ <div id="array-container" class="flex items-end h-64 space-x-1 mt-4"></div>
207
+ </div>
208
+ <div class="mt-6 flex justify-center">
209
+ <button id="start-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-3 rounded-lg font-medium transition flex items-center">
210
+ <i class="fas fa-play mr-2"></i> 开始排序
211
+ </button>
212
+ </div>
213
+ </div>
214
+ </div>
215
+
216
+ <!-- Algorithm Info -->
217
+ <div>
218
+ <div class="bg-slate-800 rounded-xl p-6 shadow-lg sticky top-6">
219
+ <h2 class="text-xl font-semibold mb-4 flex items-center">
220
+ <i class="fas fa-info-circle mr-2"></i>
221
+ 算法信息
222
+ </h2>
223
+ <div id="algorithm-info" class="space-y-4">
224
+ <div>
225
+ <h3 class="font-medium text-indigo-400">时间复杂度</h3>
226
+ <p id="time-complexity" class="text-sm">O(n²) - 最坏和平均情况</p>
227
+ </div>
228
+ <div>
229
+ <h3 class="font-medium text-indigo-400">空间复杂度</h3>
230
+ <p id="space-complexity" class="text-sm">O(1) - 原地排序</p>
231
+ </div>
232
+ <div>
233
+ <h3 class="font-medium text-indigo-400">稳定性</h3>
234
+ <p id="stability" class="text-sm">稳定</p>
235
+ </div>
236
+ <div>
237
+ <h3 class="font-medium text-indigo-400">算法描述</h3>
238
+ <p id="algorithm-description" class="text-sm">
239
+ 冒泡排序通过重复地遍历要排序的列表,比较相邻的元素并交换���们的位置来完成排序。
240
+ 每一轮遍历都会将当前未排序部分的最大元素"冒泡"到正确的位置。
241
+ </p>
242
+ </div>
243
+ </div>
244
+
245
+ <div class="mt-6">
246
+ <h3 class="font-medium mb-2 flex items-center">
247
+ <i class="fas fa-code mr-2"></i>
248
+ 伪代码
249
+ </h3>
250
+ <div id="pseudo-code" class="bg-slate-900 p-4 rounded-lg font-mono text-sm overflow-auto">
251
+ <pre>procedure bubbleSort(A : list of sortable items)
252
+ n := length(A)
253
+ repeat
254
+ swapped := false
255
+ for i := 1 to n-1 inclusive do
256
+ if A[i-1] > A[i] then
257
+ swap(A[i-1], A[i])
258
+ swapped := true
259
+ end if
260
+ end for
261
+ n := n - 1
262
+ until not swapped
263
+ end procedure</pre>
264
+ </div>
265
+ </div>
266
+ </div>
267
+ </div>
268
+ </div>
269
+
270
+ <!-- Algorithm Comparison -->
271
+ <div class="mt-12">
272
+ <h2 class="text-2xl font-semibold mb-6 flex items-center">
273
+ <i class="fas fa-project-diagram mr-3"></i>
274
+ 排序算法比较
275
+ </h2>
276
+
277
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
278
+ <!-- Bubble Sort Card -->
279
+ <div class="algorithm-card bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl p-6 shadow-lg border border-slate-700 cursor-pointer" data-algorithm="bubble">
280
+ <div class="flex items-center mb-4">
281
+ <div class="w-10 h-10 rounded-full bg-indigo-600 flex items-center justify-center mr-3">
282
+ <i class="fas fa-sort-amount-down"></i>
283
+ </div>
284
+ <h3 class="text-lg font-semibold">冒泡排序</h3>
285
+ </div>
286
+ <p class="text-sm text-gray-400 mb-4">最简单的排序算法,通过重复交换相邻元素实现排序。</p>
287
+ <div class="flex justify-between text-xs">
288
+ <span class="bg-slate-700 px-2 py-1 rounded">O(n²)</span>
289
+ <span class="bg-slate-700 px-2 py-1 rounded">O(1)</span>
290
+ <span class="bg-slate-700 px-2 py-1 rounded">稳定</span>
291
+ </div>
292
+ </div>
293
+
294
+ <!-- Selection Sort Card -->
295
+ <div class="algorithm-card bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl p-6 shadow-lg border border-slate-700 cursor-pointer" data-algorithm="selection">
296
+ <div class="flex items-center mb-4">
297
+ <div class="w-10 h-10 rounded-full bg-purple-600 flex items-center justify-center mr-3">
298
+ <i class="fas fa-mouse-pointer"></i>
299
+ </div>
300
+ <h3 class="text-lg font-semibold">选择排序</h3>
301
+ </div>
302
+ <p class="text-sm text-gray-400 mb-4">每次选择最小元素放到已排序部分的末尾。</p>
303
+ <div class="flex justify-between text-xs">
304
+ <span class="bg-slate-700 px-2 py-1 rounded">O(n²)</span>
305
+ <span class="bg-slate-700 px-2 py-1 rounded">O(1)</span>
306
+ <span class="bg-slate-700 px-2 py-1 rounded">不稳定</span>
307
+ </div>
308
+ </div>
309
+
310
+ <!-- Insertion Sort Card -->
311
+ <div class="algorithm-card bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl p-6 shadow-lg border border-slate-700 cursor-pointer" data-algorithm="insertion">
312
+ <div class="flex items-center mb-4">
313
+ <div class="w-10 h-10 rounded-full bg-pink-600 flex items-center justify-center mr-3">
314
+ <i class="fas fa-arrow-right-to-bracket"></i>
315
+ </div>
316
+ <h3 class="text-lg font-semibold">插入排序</h3>
317
+ </div>
318
+ <p class="text-sm text-gray-400 mb-4">构建最终排序数组,一次插入一个元素。</p>
319
+ <div class="flex justify-between text-xs">
320
+ <span class="bg-slate-700 px-2 py-1 rounded">O(n²)</span>
321
+ <span class="bg-slate-700 px-2 py-1 rounded">O(1)</span>
322
+ <span class="bg-slate-700 px-2 py-1 rounded">稳定</span>
323
+ </div>
324
+ </div>
325
+
326
+ <!-- Merge Sort Card -->
327
+ <div class="algorithm-card bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl p-6 shadow-lg border border-slate-700 cursor-pointer" data-algorithm="merge">
328
+ <div class="flex items-center mb-4">
329
+ <div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center mr-3">
330
+ <i class="fas fa-code-merge"></i>
331
+ </div>
332
+ <h3 class="text-lg font-semibold">归并排序</h3>
333
+ </div>
334
+ <p class="text-sm text-gray-400 mb-4">分治算法,将数组分成两半,分别排序后合并。</p>
335
+ <div class="flex justify-between text-xs">
336
+ <span class="bg-slate-700 px-2 py-1 rounded">O(n log n)</span>
337
+ <span class="bg-slate-700 px-2 py-1 rounded">O(n)</span>
338
+ <span class="bg-slate-700 px-2 py-1 rounded">稳定</span>
339
+ </div>
340
+ </div>
341
+
342
+ <!-- Quick Sort Card -->
343
+ <div class="algorithm-card bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl p-6 shadow-lg border border-slate-700 cursor-pointer" data-algorithm="quick">
344
+ <div class="flex items-center mb-4">
345
+ <div class="w-10 h-10 rounded-full bg-green-600 flex items-center justify-center mr-3">
346
+ <i class="fas fa-bolt"></i>
347
+ </div>
348
+ <h3 class="text-lg font-semibold">快速排序</h3>
349
+ </div>
350
+ <p class="text-sm text-gray-400 mb-4">分治算法,选择一个基准元素将数组分成两部分。</p>
351
+ <div class="flex justify-between text-xs">
352
+ <span class="bg-slate-700 px-2 py-1 rounded">O(n log n)</span>
353
+ <span class="bg-slate-700 px-2 py-1 rounded">O(log n)</span>
354
+ <span class="bg-slate-700 px-2 py-1 rounded">不稳定</span>
355
+ </div>
356
+ </div>
357
+
358
+ <!-- Heap Sort Card -->
359
+ <div class="algorithm-card bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl p-6 shadow-lg border border-slate-700 cursor-pointer" data-algorithm="heap">
360
+ <div class="flex items-center mb-4">
361
+ <div class="w-10 h-10 rounded-full bg-yellow-600 flex items-center justify-center mr-3">
362
+ <i class="fas fa-layer-group"></i>
363
+ </div>
364
+ <h3 class="text-lg font-semibold">堆排序</h3>
365
+ </div>
366
+ <p class="text-sm text-gray-400 mb-4">利用二叉堆数据结构进行排序。</p>
367
+ <div class="flex justify-between text-xs">
368
+ <span class="bg-slate-700 px-2 py-1 rounded">O(n log n)</span>
369
+ <span class="bg-slate-700 px-2 py-1 rounded">O(1)</span>
370
+ <span class="bg-slate-700 px-2 py-1 rounded">不稳定</span>
371
+ </div>
372
+ </div>
373
+ </div>
374
+ </div>
375
+ </main>
376
+
377
+ <!-- Footer -->
378
+ <footer class="bg-slate-900 py-8 mt-12">
379
+ <div class="container mx-auto px-4">
380
+ <div class="flex flex-col md:flex-row justify-between items-center">
381
+ <div class="mb-4 md:mb-0">
382
+ <h3 class="text-xl font-semibold flex items-center">
383
+ <i class="fas fa-sort-amount-down-alt mr-2"></i>
384
+ 排序算法可视化
385
+ </h3>
386
+ <p class="text-sm text-gray-400 mt-1">通过动画直观理解排序算法</p>
387
+ </div>
388
+ <div class="flex space-x-4">
389
+ <a href="#" class="text-gray-400 hover:text-white transition">
390
+ <i class="fab fa-github text-xl"></i>
391
+ </a>
392
+ <a href="#" class="text-gray-400 hover:text-white transition">
393
+ <i class="fab fa-twitter text-xl"></i>
394
+ </a>
395
+ <a href="#" class="text-gray-400 hover:text-white transition">
396
+ <i class="fas fa-envelope text-xl"></i>
397
+ </a>
398
+ </div>
399
+ </div>
400
+ <div class="border-t border-slate-800 mt-6 pt-6 text-center text-sm text-gray-500">
401
+ <p>© 2023 排序算法可视化. 所有权利保留.</p>
402
+ </div>
403
+ </div>
404
+ </footer>
405
+
406
+ <script>
407
+ // DOM Elements
408
+ const arrayContainer = document.getElementById('array-container');
409
+ const startBtn = document.getElementById('start-btn');
410
+ const resetBtn = document.getElementById('reset-btn');
411
+ const randomizeBtn = document.getElementById('randomize-btn');
412
+ const arraySizeSlider = document.getElementById('array-size');
413
+ const speedSlider = document.getElementById('speed');
414
+ const algorithmSelect = document.getElementById('algorithm');
415
+ const algorithmName = document.getElementById('algorithm-name');
416
+
417
+ // Algorithm info elements
418
+ const timeComplexity = document.getElementById('time-complexity');
419
+ const spaceComplexity = document.getElementById('space-complexity');
420
+ const stability = document.getElementById('stability');
421
+ const algorithmDescription = document.getElementById('algorithm-description');
422
+ const pseudoCode = document.getElementById('pseudo-code');
423
+
424
+ // Algorithm cards
425
+ const algorithmCards = document.querySelectorAll('.algorithm-card');
426
+
427
+ // Global variables
428
+ let array = [];
429
+ let arraySize = parseInt(arraySizeSlider.value);
430
+ let speed = parseInt(speedSlider.value);
431
+ let algorithm = algorithmSelect.value;
432
+ let isSorting = false;
433
+ let animationSpeed = 1000 - (speed * 100); // Convert speed to delay in ms
434
+
435
+ // Algorithm information
436
+ const algorithms = {
437
+ bubble: {
438
+ name: '冒泡排序',
439
+ time: 'O(n²) - 最坏和平均情况',
440
+ space: 'O(1) - 原地排序',
441
+ stable: '稳定',
442
+ description: '冒泡排序通过重复地遍历要排序的列表,比较相邻的元素并交换它们的位置来完成排序。每一轮遍历都会将当前未排序部分的最大元素"冒泡"到正确的位置。',
443
+ pseudoCode: `procedure bubbleSort(A : list of sortable items)
444
+ n := length(A)
445
+ repeat
446
+ swapped := false
447
+ for i := 1 to n-1 inclusive do
448
+ if A[i-1] > A[i] then
449
+ swap(A[i-1], A[i])
450
+ swapped := true
451
+ end if
452
+ end for
453
+ n := n - 1
454
+ until not swapped
455
+ end procedure`
456
+ },
457
+ selection: {
458
+ name: '选择排序',
459
+ time: 'O(n²) - 所有情况',
460
+ space: 'O(1) - 原地排序',
461
+ stable: '不稳定',
462
+ description: '选择排序将数组分为已排序和未排序两部分,每次从未排序部分选择最小元素,放到已排序部分的末尾。',
463
+ pseudoCode: `procedure selectionSort(A : list of sortable items)
464
+ n := length(A)
465
+ for i := 0 to n-2 inclusive do
466
+ minIndex := i
467
+ for j := i+1 to n-1 inclusive do
468
+ if A[j] < A[minIndex] then
469
+ minIndex := j
470
+ end if
471
+ end for
472
+ if minIndex != i then
473
+ swap(A[i], A[minIndex])
474
+ end if
475
+ end for
476
+ end procedure`
477
+ },
478
+ insertion: {
479
+ name: '插入排序',
480
+ time: 'O(n²) - 最坏和平均情况',
481
+ space: 'O(1) - 原地排序',
482
+ stable: '稳定',
483
+ description: '插入排序构建最终排序数组,一次插入一个元素。对于几乎排序好的数据效率很高。',
484
+ pseudoCode: `procedure insertionSort(A : list of sortable items)
485
+ n := length(A)
486
+ for i := 1 to n-1 inclusive do
487
+ key := A[i]
488
+ j := i - 1
489
+ while j >= 0 and A[j] > key do
490
+ A[j+1] := A[j]
491
+ j := j - 1
492
+ end while
493
+ A[j+1] := key
494
+ end for
495
+ end procedure`
496
+ },
497
+ merge: {
498
+ name: '归并排序',
499
+ time: 'O(n log n) - 所有情况',
500
+ space: 'O(n) - 需要额外空间',
501
+ stable: '稳定',
502
+ description: '归并排序是分治算法,将数组分成两半,分别排序后合并。高效且稳定,但需要额外空间。',
503
+ pseudoCode: `procedure mergeSort(A : list of sortable items)
504
+ if length(A) <= 1 then
505
+ return A
506
+ end if
507
+
508
+ middle := length(A) / 2
509
+ left := A[0..middle-1]
510
+ right := A[middle..length(A)-1]
511
+
512
+ left := mergeSort(left)
513
+ right := mergeSort(right)
514
+
515
+ return merge(left, right)
516
+ end procedure
517
+
518
+ procedure merge(left, right)
519
+ result := []
520
+ while left not empty and right not empty do
521
+ if left[0] <= right[0] then
522
+ append left[0] to result
523
+ left := left[1..]
524
+ else
525
+ append right[0] to result
526
+ right := right[1..]
527
+ end if
528
+ end while
529
+
530
+ while left not empty do
531
+ append left[0] to result
532
+ left := left[1..]
533
+ end while
534
+
535
+ while right not empty do
536
+ append right[0] to result
537
+ right := right[1..]
538
+ end while
539
+
540
+ return result
541
+ end procedure`
542
+ },
543
+ quick: {
544
+ name: '快速排序',
545
+ time: 'O(n log n) - 平均情况, O(n²) - 最坏情况',
546
+ space: 'O(log n) - 递归栈空间',
547
+ stable: '不稳定',
548
+ description: '快速排序是分治算法,选择一个基准元素将数组分成两部分,小于基准的放左边,大于基准的放右边,然后递归排序两部分。',
549
+ pseudoCode: `procedure quickSort(A : list of sortable items, low, high)
550
+ if low < high then
551
+ p := partition(A, low, high)
552
+ quickSort(A, low, p - 1)
553
+ quickSort(A, p + 1, high)
554
+ end if
555
+ end procedure
556
+
557
+ procedure partition(A, low, high)
558
+ pivot := A[high]
559
+ i := low - 1
560
+
561
+ for j := low to high-1 inclusive do
562
+ if A[j] < pivot then
563
+ i := i + 1
564
+ swap(A[i], A[j])
565
+ end if
566
+ end for
567
+
568
+ swap(A[i + 1], A[high])
569
+ return i + 1
570
+ end procedure`
571
+ },
572
+ heap: {
573
+ name: '堆排序',
574
+ time: 'O(n log n) - 所有情况',
575
+ space: 'O(1) - 原地排序',
576
+ stable: '不稳定',
577
+ description: '堆排序利用二叉堆数据结构进行排序。首先构建最大堆,然后重复从堆中提取最大元素放到数组末尾。',
578
+ pseudoCode: `procedure heapSort(A : list of sortable items)
579
+ n := length(A)
580
+
581
+ // Build max heap
582
+ for i := n/2 - 1 downto 0 inclusive do
583
+ heapify(A, n, i)
584
+ end for
585
+
586
+ // Extract elements from heap
587
+ for i := n-1 downto 1 inclusive do
588
+ swap(A[0], A[i])
589
+ heapify(A, i, 0)
590
+ end for
591
+ end procedure
592
+
593
+ procedure heapify(A, n, i)
594
+ largest := i
595
+ left := 2*i + 1
596
+ right := 2*i + 2
597
+
598
+ if left < n and A[left] > A[largest] then
599
+ largest := left
600
+ end if
601
+
602
+ if right < n and A[right] > A[largest] then
603
+ largest := right
604
+ end if
605
+
606
+ if largest != i then
607
+ swap(A[i], A[largest])
608
+ heapify(A, n, largest)
609
+ end if
610
+ end procedure`
611
+ }
612
+ };
613
+
614
+ // Initialize the array and visualization
615
+ function initArray() {
616
+ arrayContainer.innerHTML = '';
617
+ array = [];
618
+
619
+ // Generate random array
620
+ for (let i = 0; i < arraySize; i++) {
621
+ array.push(Math.floor(Math.random() * 100) + 10);
622
+ }
623
+
624
+ // Create bars for visualization
625
+ for (let i = 0; i < array.length; i++) {
626
+ const bar = document.createElement('div');
627
+ bar.className = 'array-bar';
628
+ bar.style.height = `${array[i]}%`;
629
+ bar.style.width = `${100 / arraySize}%`;
630
+ bar.setAttribute('data-value', array[i]);
631
+ bar.textContent = array[i];
632
+ arrayContainer.appendChild(bar);
633
+ }
634
+
635
+ // Update algorithm info
636
+ updateAlgorithmInfo();
637
+ }
638
+
639
+ // Update algorithm information
640
+ function updateAlgorithmInfo() {
641
+ const algo = algorithms[algorithm];
642
+ algorithmName.textContent = algo.name;
643
+ timeComplexity.textContent = algo.time;
644
+ spaceComplexity.textContent = algo.space;
645
+ stability.textContent = algo.stable;
646
+ algorithmDescription.textContent = algo.description;
647
+ pseudoCode.innerHTML = `<pre>${algo.pseudoCode}</pre>`;
648
+ }
649
+
650
+ // Reset the array to its initial state
651
+ function resetArray() {
652
+ if (isSorting) return;
653
+
654
+ const bars = arrayContainer.querySelectorAll('.array-bar');
655
+ bars.forEach((bar, i) => {
656
+ bar.className = 'array-bar';
657
+ bar.style.height = `${array[i]}%`;
658
+ bar.textContent = array[i];
659
+ });
660
+ }
661
+
662
+ // Randomize the array
663
+ function randomizeArray() {
664
+ if (isSorting) return;
665
+ initArray();
666
+ }
667
+
668
+ // Change array size
669
+ function changeArraySize() {
670
+ if (isSorting) return;
671
+ arraySize = parseInt(arraySizeSlider.value);
672
+ initArray();
673
+ }
674
+
675
+ // Change speed
676
+ function changeSpeed() {
677
+ speed = parseInt(speedSlider.value);
678
+ animationSpeed = 1000 - (speed * 100);
679
+ }
680
+
681
+ // Change algorithm
682
+ function changeAlgorithm() {
683
+ if (isSorting) return;
684
+ algorithm = algorithmSelect.value;
685
+ updateAlgorithmInfo();
686
+ }
687
+
688
+ // Visualize the sorting algorithm
689
+ async function visualizeSort() {
690
+ if (isSorting) return;
691
+
692
+ isSorting = true;
693
+ startBtn.disabled = true;
694
+ startBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> 排序中...';
695
+
696
+ // Get all bars
697
+ const bars = arrayContainer.querySelectorAll('.array-bar');
698
+
699
+ // Perform the selected algorithm
700
+ switch (algorithm) {
701
+ case 'bubble':
702
+ await bubbleSort([...array], bars);
703
+ break;
704
+ case 'selection':
705
+ await selectionSort([...array], bars);
706
+ break;
707
+ case 'insertion':
708
+ await insertionSort([...array], bars);
709
+ break;
710
+ case 'merge':
711
+ await mergeSort([...array], bars, 0, array.length - 1);
712
+ break;
713
+ case 'quick':
714
+ await quickSort([...array], bars, 0, array.length - 1);
715
+ break;
716
+ case 'heap':
717
+ await heapSort([...array], bars);
718
+ break;
719
+ }
720
+
721
+ // Mark all bars as sorted
722
+ for (let i = 0; i < bars.length; i++) {
723
+ bars[i].classList.add('sorted');
724
+ await sleep(animationSpeed / 10);
725
+ }
726
+
727
+ isSorting = false;
728
+ startBtn.disabled = false;
729
+ startBtn.innerHTML = '<i class="fas fa-play mr-2"></i> 开始排序';
730
+ }
731
+
732
+ // Sleep function for animations
733
+ function sleep(ms) {
734
+ return new Promise(resolve => setTimeout(resolve, ms));
735
+ }
736
+
737
+ // Swap two elements in the array and visualize it
738
+ async function swapElements(arr, bars, i, j) {
739
+ // Highlight the elements being swapped
740
+ bars[i].classList.add('swapping');
741
+ bars[j].classList.add('swapping');
742
+
743
+ await sleep(animationSpeed);
744
+
745
+ // Swap the values
746
+ const temp = arr[i];
747
+ arr[i] = arr[j];
748
+ arr[j] = temp;
749
+
750
+ // Update the bars
751
+ bars[i].style.height = `${arr[i]}%`;
752
+ bars[i].setAttribute('data-value', arr[i]);
753
+ bars[i].textContent = arr[i];
754
+
755
+ bars[j].style.height = `${arr[j]}%`;
756
+ bars[j].setAttribute('data-value', arr[j]);
757
+ bars[j].textContent = arr[j];
758
+
759
+ // Remove the highlighting
760
+ bars[i].classList.remove('swapping');
761
+ bars[j].classList.remove('swapping');
762
+ }
763
+
764
+ // Compare two elements and visualize it
765
+ async function compareElements(bars, i, j) {
766
+ bars[i].classList.add('comparing');
767
+ bars[j].classList.add('comparing');
768
+
769
+ await sleep(animationSpeed);
770
+
771
+ bars[i].classList.remove('comparing');
772
+ bars[j].classList.remove('comparing');
773
+ }
774
+
775
+ // Mark an element as pivot
776
+ async function markPivot(bars, i) {
777
+ bars[i].classList.add('pivot');
778
+ await sleep(animationSpeed * 2);
779
+ bars[i].classList.remove('pivot');
780
+ }
781
+
782
+ // Mark an element as min
783
+ async function markMin(bars, i) {
784
+ bars[i].classList.add('min');
785
+ await sleep(animationSpeed);
786
+ bars[i].classList.remove('min');
787
+ }
788
+
789
+ // Bubble Sort algorithm
790
+ async function bubbleSort(arr, bars) {
791
+ let n = arr.length;
792
+ let swapped;
793
+
794
+ do {
795
+ swapped = false;
796
+ for (let i = 0; i < n - 1; i++) {
797
+ await compareElements(bars, i, i + 1);
798
+
799
+ if (arr[i] > arr[i + 1]) {
800
+ await swapElements(arr, bars, i, i + 1);
801
+ swapped = true;
802
+ }
803
+ }
804
+ n--;
805
+
806
+ // Mark the last element as sorted
807
+ bars[n].classList.add('sorted');
808
+ } while (swapped);
809
+ }
810
+
811
+ // Selection Sort algorithm
812
+ async function selectionSort(arr, bars) {
813
+ const n = arr.length;
814
+
815
+ for (let i = 0; i < n - 1; i++) {
816
+ let minIndex = i;
817
+
818
+ // Mark current min
819
+ await markMin(bars, minIndex);
820
+
821
+ for (let j = i + 1; j < n; j++) {
822
+ await compareElements(bars, minIndex, j);
823
+
824
+ if (arr[j] < arr[minIndex]) {
825
+ minIndex = j;
826
+ await markMin(bars, minIndex);
827
+ }
828
+ }
829
+
830
+ if (minIndex !== i) {
831
+ await swapElements(arr, bars, i, minIndex);
832
+ }
833
+
834
+ // Mark the sorted element
835
+ bars[i].classList.add('sorted');
836
+ }
837
+
838
+ // Mark the last element as sorted
839
+ bars[n - 1].classList.add('sorted');
840
+ }
841
+
842
+ // Insertion Sort algorithm
843
+ async function insertionSort(arr, bars) {
844
+ const n = arr.length;
845
+
846
+ for (let i = 1; i < n; i++) {
847
+ const key = arr[i];
848
+ let j = i - 1;
849
+
850
+ // Highlight the current element being inserted
851
+ bars[i].classList.add('comparing');
852
+ await sleep(animationSpeed);
853
+
854
+ while (j >= 0 && arr[j] > key) {
855
+ // Move the larger element one position ahead
856
+ arr[j + 1] = arr[j];
857
+ bars[j + 1].style.height = `${arr[j + 1]}%`;
858
+ bars[j + 1].setAttribute('data-value', arr[j + 1]);
859
+ bars[j + 1].textContent = arr[j + 1];
860
+
861
+ // Highlight the comparison
862
+ bars[j].classList.add('comparing');
863
+ await sleep(animationSpeed);
864
+ bars[j].classList.remove('comparing');
865
+
866
+ j--;
867
+ }
868
+
869
+ // Insert the key in its correct position
870
+ arr[j + 1] = key;
871
+ bars[j + 1].style.height = `${arr[j + 1]}%`;
872
+ bars[j + 1].setAttribute('data-value', arr[j + 1]);
873
+ bars[j + 1].textContent = arr[j + 1];
874
+
875
+ // Remove highlighting
876
+ bars[i].classList.remove('comparing');
877
+
878
+ // Mark the sorted portion
879
+ for (let k = 0; k <= i; k++) {
880
+ bars[k].classList.add('sorted');
881
+ }
882
+ await sleep(animationSpeed / 2);
883
+ for (let k = 0; k <= i; k++) {
884
+ bars[k].classList.remove('sorted');
885
+ }
886
+ }
887
+
888
+ // Mark all as sorted at the end
889
+ for (let i = 0; i < n; i++) {
890
+ bars[i].classList.add('sorted');
891
+ }
892
+ }
893
+
894
+ // Merge Sort algorithm
895
+ async function mergeSort(arr, bars, l, r) {
896
+ if (l >= r) return;
897
+
898
+ const m = l + Math.floor((r - l) / 2);
899
+
900
+ // Visualize the division
901
+ for (let i = l; i <= r; i++) {
902
+ bars[i].classList.add('comparing');
903
+ }
904
+ await sleep(animationSpeed);
905
+ for (let i = l; i <= r; i++) {
906
+ bars[i].classList.remove('comparing');
907
+ }
908
+
909
+ await mergeSort(arr, bars, l, m);
910
+ await mergeSort(arr, bars, m + 1, r);
911
+ await merge(arr, bars, l, m, r);
912
+ }
913
+
914
+ // Merge helper function for Merge Sort
915
+ async function merge(arr, bars, l, m, r) {
916
+ const n1 = m - l + 1;
917
+ const n2 = r - m;
918
+
919
+ // Create temp arrays
920
+ const L = new Array(n1);
921
+ const R = new Array(n2);
922
+
923
+ // Copy data to temp arrays
924
+ for (let i = 0; i < n1; i++) {
925
+ L[i] = arr[l + i];
926
+ }
927
+ for (let j = 0; j < n2; j++) {
928
+ R[j] = arr[m + 1 + j];
929
+ }
930
+
931
+ // Merge the temp arrays back into arr[l..r]
932
+ let i = 0, j = 0, k = l;
933
+
934
+ while (i < n1 && j < n2) {
935
+ // Highlight the elements being compared
936
+ if (l + i <= m) bars[l + i].classList.add('comparing');
937
+ if (m + 1 + j <= r) bars[m + 1 + j].classList.add('comparing');
938
+ await sleep(animationSpeed);
939
+
940
+ if (L[i] <= R[j]) {
941
+ arr[k] = L[i];
942
+ bars[k].style.height = `${arr[k]}%`;
943
+ bars[k].setAttribute('data-value', arr[k]);
944
+ bars[k].textContent = arr[k];
945
+ i++;
946
+ } else {
947
+ arr[k] = R[j];
948
+ bars[k].style.height = `${arr[k]}%`;
949
+ bars[k].setAttribute('data-value', arr[k]);
950
+ bars[k].textContent = arr[k];
951
+ j++;
952
+ }
953
+
954
+ // Remove highlighting
955
+ if (l + i - 1 <= m) bars[l + i - 1].classList.remove('comparing');
956
+ if (m + j <= r) bars[m + j].classList.remove('comparing');
957
+
958
+ k++;
959
+ }
960
+
961
+ // Copy the remaining elements of L[], if any
962
+ while (i < n1) {
963
+ arr[k] = L[i];
964
+ bars[k].style.height = `${arr[k]}%`;
965
+ bars[k].setAttribute('data-value', arr[k]);
966
+ bars[k].textContent = arr[k];
967
+ i++;
968
+ k++;
969
+ }
970
+
971
+ // Copy the remaining elements of R[], if any
972
+ while (j < n2) {
973
+ arr[k] = R[j];
974
+ bars[k].style.height = `${arr[k]}%`;
975
+ bars[k].setAttribute('data-value', arr[k]);
976
+ bars[k].textContent = arr[j];
977
+ j++;
978
+ k++;
979
+ }
980
+
981
+ // Visualize the merged portion
982
+ for (let i = l; i <= r; i++) {
983
+ bars[i].classList.add('sorted');
984
+ }
985
+ await sleep(animationSpeed / 2);
986
+ for (let i = l; i <= r; i++) {
987
+ bars[i].classList.remove('sorted');
988
+ }
989
+ }
990
+
991
+ // Quick Sort algorithm
992
+ async function quickSort(arr, bars, low, high) {
993
+ if (low < high) {
994
+ // Partition the array and get the pivot index
995
+ const pi = await partition(arr, bars, low, high);
996
+
997
+ // Recursively sort elements before and after partition
998
+ await quickSort(arr, bars, low, pi - 1);
999
+ await quickSort(arr, bars, pi + 1, high);
1000
+ }
1001
+
1002
+ // Mark as sorted when done
1003
+ if (low === 0 && high === arr.length - 1) {
1004
+ for (let i = 0; i < arr.length; i++) {
1005
+ bars[i].classList.add('sorted');
1006
+ await sleep(animationSpeed / 10);
1007
+ }
1008
+ }
1009
+ }
1010
+
1011
+ // Partition helper function for Quick Sort
1012
+ async function partition(arr, bars, low, high) {
1013
+ // Choose the rightmost element as pivot
1014
+ const pivot = arr[high];
1015
+
1016
+ // Mark the pivot
1017
+ bars[high].classList.add('pivot');
1018
+ await sleep(animationSpeed * 2);
1019
+
1020
+ // Index of smaller element
1021
+ let i = low - 1;
1022
+
1023
+ for (let j = low; j < high; j++) {
1024
+ // If current element is smaller than the pivot
1025
+ await compareElements(bars, j, high);
1026
+
1027
+ if (arr[j] < pivot) {
1028
+ i++;
1029
+ await swapElements(arr, bars, i, j);
1030
+ }
1031
+ }
1032
+
1033
+ // Swap the pivot element with the element at i+1
1034
+ await swapElements(arr, bars, i + 1, high);
1035
+
1036
+ // Remove pivot marking
1037
+ bars[i + 1].classList.remove('pivot');
1038
+
1039
+ // Return the partition index
1040
+ return i + 1;
1041
+ }
1042
+
1043
+ // Heap Sort algorithm
1044
+ async function heapSort(arr, bars) {
1045
+ const n = arr.length;
1046
+
1047
+ // Build max heap
1048
+ for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
1049
+ await heapify(arr, bars, n, i);
1050
+ }
1051
+
1052
+ // Extract elements from heap one by one
1053
+ for (let i = n - 1; i > 0; i--) {
1054
+ // Move current root to end
1055
+ await swapElements(arr, bars, 0, i);
1056
+
1057
+ // Mark the sorted element
1058
+ bars[i].classList.add('sorted');
1059
+
1060
+ // Call max heapify on the reduced heap
1061
+ await heapify(arr, bars, i, 0);
1062
+ }
1063
+
1064
+ // Mark the last element as sorted
1065
+ bars[0].classList.add('sorted');
1066
+ }
1067
+
1068
+ // Heapify helper function for Heap Sort
1069
+ async function heapify(arr, bars, n, i) {
1070
+ let largest = i; // Initialize largest as root
1071
+ const left = 2 * i + 1;
1072
+ const right = 2 * i + 2;
1073
+
1074
+ // If left child is larger than root
1075
+ if (left < n) {
1076
+ await compareElements(bars, largest, left);
1077
+ if (arr[left] > arr[largest]) {
1078
+ largest = left;
1079
+ }
1080
+ }
1081
+
1082
+ // If right child is larger than largest so far
1083
+ if (right < n) {
1084
+ await compareElements(bars, largest, right);
1085
+ if (arr[right] > arr[largest]) {
1086
+ largest = right;
1087
+ }
1088
+ }
1089
+
1090
+ // If largest is not root
1091
+ if (largest !== i) {
1092
+ await swapElements(arr, bars, i, largest);
1093
+
1094
+ // Recursively heapify the affected sub-tree
1095
+ await heapify(arr, bars, n, largest);
1096
+ }
1097
+ }
1098
+
1099
+ // Event Listeners
1100
+ startBtn.addEventListener('click', visualizeSort);
1101
+ resetBtn.addEventListener('click', resetArray);
1102
+ randomizeBtn.addEventListener('click', randomizeArray);
1103
+ arraySizeSlider.addEventListener('input', changeArraySize);
1104
+ speedSlider.addEventListener('input', changeSpeed);
1105
+ algorithmSelect.addEventListener('change', changeAlgorithm);
1106
+
1107
+ // Algorithm card click events
1108
+ algorithmCards.forEach(card => {
1109
+ card.addEventListener('click', () => {
1110
+ const algo = card.getAttribute('data-algorithm');
1111
+ algorithmSelect.value = algo;
1112
+ algorithm = algo;
1113
+ updateAlgorithmInfo();
1114
+ });
1115
+ });
1116
+
1117
+ // Initialize the app
1118
+ initArray();
1119
+ </script>
1120
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=1bo/sort-animal" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
1121
+ </html>