
教程文档示例工程【免费下载链接】website-archiveArchive of the Coding Train website (first version)项目地址https://gitcode.com/gh_mirrors/we/website-archive点击查看免费下载导读本文以 Coding Train本仓库第 114 号编程挑战为骨架完整拆解如何在 ProcessingJava与 p5.js 两种环境中实现冒泡排序可视化用随机生成的竖线代表待排序数据让每一帧动画完成一次冒泡遍历直观呈现O(n²)排序过程。读完本文你将掌握挑战的核心算法实现、逐帧动画驱动方式、两种语言版本的结构差异以及如何在本地运行和扩展这套可视化方案。挑战背景在动画中看见排序算法本挑战的官方条目位于 _CodingChallenges/114-bubble-sort.md其 front matter 记录了关键元数据视频编号114video_id:67k3I2GxTH8发布日期2018-08-27对应仓库CC_114_BubbleSortViz即 CodingChallenges/CC_114_BubbleSortVizp5.js Web Editor 草图 ID3HVrL9m36挑战摘要原文In this coding challenge, I implement a bubble sort algorithm in Processing (Java) and sort randomly generated lines.也就是说挑战目标非常聚焦用 Processing 的 Java 语法实现冒泡排序并对随机生成的竖线数组进行可视化排序并同步提供 p5.js 版本。条目中还引用了 Mike Bostock 的Visualizing Algorithms作为可视化思路参考并以#SortingTrain作为系列话题标签即本仓库中连续多期排序类挑战的统称例如后续的 143-quicksort 等。算法核心一帧完成一次冒泡遍历冒泡排序的原理是把数组视为一列气泡每一轮遍历从前往后比较相邻元素若前者大于后者则交换从而把当前范围内最大的元素浮到末尾。仓库中的 Processing 实现位于 CodingChallenges/CC_114_BubbleSortViz/Processing/CC_114_BubbleSortViz/CC_114_BubbleSortViz.pde其核心排序逻辑如下void draw() { background(0); if (i values.length) { for (int j 0; j values.length-i-1; j) { float a values[j]; float b values[j1]; if (a b) { swap(values, j, j1); } } } else { println(finished); noLoop(); } i; // ... 绘制竖线 }这段代码有三个关键设计点值得逐条展开一帧只做一整轮遍历外层用全局计数i表示已完成多少轮冒泡每调用一次draw()就执行一轮完整的相邻比较与交换内层循环j从0到values.length-i-1随后i。由于 Processing / p5.js 默认每秒绘制 60 帧排序过程被自然地慢放为动画这正是可视化的核心技巧。边界收缩内层循环上限values.length-i-1是冒泡排序的经典优化——第i轮完成后数组末尾的i个元素已经是最大的且有序无需再参与比较。结束控制当i values.length时输出finished并调用noLoop()停止动画循环避免空转浪费 CPU。交换辅助函数同样标准void swap(float[] arr, int a, int b) { float temp arr[a]; arr[a] arr[b]; arr[b] temp; }从源码结构可以观察到一个小细节文件顶部声明了全局变量int i 0; int j 0;但draw()中的内层循环用for (int j ...)重新声明了局部j因此全局j实际未被使用真正驱动排序进度的是全局i。这并不影响正确性属于可以顺手清理的冗余声明。可视化渲染用一根竖线代表一个数据点排序只是前半场可视化的另一半在于如何把数组画出来。Processing 版本在setup()中完成了数据初始化与画布配置void setup() { fullScreen(P2D); // 全屏 P2D 渲染器 //size(800, 300); // 备选固定窗口尺寸被注释 values new float[width]; for (int i 0; i values.length; i) { values[i] random(height); //values[i] noise(i/100.0)*height; // 备选柏林噪声分布被注释 } }数据量与画布宽度强相关values的长度等于width每个元素取random(height)0 到画布高度之间的随机浮点数。这意味着画布越宽参与排序的竖线越多——全屏模式下例如 1920 像素宽就有约 1920 根线。被注释的两行代码透露出两个可选的实验方向用size(800, 300)固定窗口以获得更少的竖线或改用noise(i/100.0)*height生成柏林噪声分布的数据让初始状态呈现波浪形而非完全随机。每帧绘制逻辑见 CC_114_BubbleSortViz.pde 第 45-48 行for (int i 0; i values.length; i) { stroke(255); line(i, height, i, height - values[i]); }即以x i处画一条从画布底部(i, height)延伸到(i, height - values[i])的白色竖线。values[i]越大竖线越高因此肉眼可以直接读出高的线在向左/右移动的交换过程。p5.js 版本把同一套逻辑搬进浏览器p5.js 版本位于 CodingChallenges/CC_114_BubbleSortViz/P5/sketch.js与 Processing 版几乎逐行对应let values []; let i 0; let j 0; function setup() { createCanvas(windowWidth, windowHeight); values new Array(width); for (let i 0; i values.length; i) { values[i] random(height); //values[i] noise(i/100.0)*height; } } function draw() { background(0); if (i values.length) { for (let j 0; j values.length - i - 1; j) { let a values[j]; let b values[j 1]; if (a b) { swap(values, j, j 1); } } } else { console.log(finished); noLoop(); } i; for (let i 0; i values.length; i) { stroke(255); line(i, height, i, height - values[i]); } } function swap(arr, a, b) { let temp arr[a]; arr[a] arr[b]; arr[b] temp; }对应的页面骨架 CodingChallenges/CC_114_BubbleSortViz/P5/index.html 非常简单通过 jsDelivr CDN 引入p51.4.1的p5.min.js再加载本地的sketch.jsbody留空即可p5.js 会自动创建画布。运行方式有两种本地打开直接用浏览器打开index.html或任意静态服务器托管该目录Web Editor在 p5.js Web Editor 中新建草图将sketch.js内容粘贴进编辑器即可挑战条目记录的草图 ID 为3HVrL9m36可直接搜索参考。两种实现的差异对照将两份源码并列Processing .pde 与 P5 sketch.js可以看到语言层面的机械替换之外还有几处环境差异值得记录维度ProcessingJavap5.jsJavaScript画布fullScreen(P2D)默认全屏createCanvas(windowWidth, windowHeight)跟随窗口数据类型float[] values定长数组values []/new Array(width)随机数random(height)返回 floatrandom(height)返回 Number结束输出println(finished)console.log(finished)停止动画noLoop()noLoop()渲染 APIstroke(255); line(...)完全相同p5.js 兼容 Processing 绘图 API正是因为 p5.js 的绘图 API 与 Processing 高度一致这段代码才能做到近乎零改写地跨环境移植——这是 p5.js 作为 Processing 浏览器移植版的最大优势。复杂度与运行表现观察冒泡排序的时间复杂度为O(n²)、空间复杂度为O(1)原地交换。结合本实现的帧驱动方式可以推导出几个有意思的量化结论以下基于源码结构推断非官方数据总帧数每帧完成一轮遍历共n轮因此动画恰好持续n帧60 FPS 下约n/60秒。总比较次数第i轮比较n-i-1次累计约n²/2次。以全屏 1920 根线为例全程约 184 万次比较、约 32 秒完成——这恰好让观众既能看清交换过程又不至于等待过久。若改为size(800, 300)则只需约 32 万次比较、约 13 秒两种画布尺寸的体验差异由此可以预见。值得说明的是挑战源码没有实现提前终止优化即某轮无任何交换时直接结束。你可以自行加上一个swapped标志位在数组已接近有序时提前触发noLoop()这是把该挑战升级为带优化的冒泡排序可视化的第一步。社区衍生作品一场挑战的多种玩法_CodingChallenges/114-bubble-sort.md 的contributions字段记录了社区围绕本挑战提交的 16 份衍生作品这些条目展示了同一核心算法可以延伸出的丰富变体以下仅按条目标题归纳玩法不含外部链接视觉增强类可变柱密度variable bar density、彩虹渐变配色的 Rainbow Bubble Sort、把排序过程呈现为频谱Spectrum、用图片像素作为排序对象Sorting Visualization using a Picture、按算法输出可视化 GIF 等工程实现类基于生成器Generators与定时器的 p5.js 实现、Python pygame 实现、同时覆盖快速排序/冒泡排序/插入排序的多算法可视化页面衍生扩展类Sorting Algorithm Visualizations集成多种排序算法、Alex Mansfield 的多算法排序可视化器带算法选择参数等。这些作品印证了本挑战的教学价值冒泡排序只是入口可视化框架一旦搭好换算法、换数据分布、换配色都只是局部改动。本地运行与扩展建议要在本地复现本挑战只需两步Processing 版本用 Processing IDE 打开 CodingChallenges/CC_114_BubbleSortViz/Processing/CC_114_BubbleSortViz/CC_114_BubbleSortViz.pde直接点击运行P2D渲染器随fullScreen自动启用p5.js 版本用浏览器打开 CodingChallenges/CC_114_BubbleSortViz/P5/index.html或将 sketch.js 内容粘贴到 p5.js Web Editor 中运行。如果希望在此基础上做进一步练习比较自然的扩展路径包括高亮当前正在比较的两根线改变其stroke颜色、加入速度调节控制每帧执行的遍历轮数、引入提前终止优化、把noLoop()替换为完成后重新洗牌再排序的循环演示以及参考本仓库后续的 143-quicksort 挑战用同一套竖线可视化框架实现其他排序算法。无论是作为算法入门还是可视化编程练习这个挑战都是成本极低、收益直观的起点。赞分享教程文档示例工程【免费下载链接】website-archiveArchive of the Coding Train website (first version)项目地址https://gitcode.com/gh_mirrors/we/website-archive点击查看免费下载相关推荐洛伦兹吸引子可视化实战用 Processing 与 p5.js 实现 Lorenz 混沌系统Coding Challenge 12洛伦兹吸引子可视化实战用 Processing 与 p5.js 实现 Lorenz 混沌系统Coding Challenge 12 本文以 The Cod教程文档示例工程Coding Challenge 28 解析从零实现 MetaBalls等值面——Processing 与 p5.js 逐像素渲染实战Coding Challenge 28 解析从零实现 MetaBalls等值面——Processing 与 p5.js 逐像素渲染实战 本文以仓库归档的教程文档示例工程用 p5.js 实现粒子吸引与排斥力Coding Challenge 56 源码深度解析用 p5.js 实现粒子吸引与排斥力Coding Challenge 56 源码深度解析 本指南围绕 Coding Train 第 56 期编程挑战「Attr教程文档示例工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考