发布于 2026-01-06 5 阅读
0

纯 CSS 实现冒泡排序?[无需 JS] 😱

纯 CSS 实现冒泡排序?[无需 JS] 😱

想象一下,你在面试时被问到“你能实现冒泡排序吗?”,你回答面试官“当然可以,你想要用 JavaScript 还是 CSS 实现?”

那该有多牛啊!

我知道你在想什么。“面试官不会对你制作的模拟冒泡排序的动画印象深刻”。你说得对!

但如果我们能用纯 CSS创建一个可运行的冒泡排序算法,并为其添加可视化效果呢?

恭喜你,你来对地方了!

演示

说明:元素顶部有 5 个值:root

:root{
    --val1: 12;
    --val2: 16;
    --val3: 9;
    --val4: 14;
    --val5: 7;

Enter fullscreen mode Exit fullscreen mode

这是我们的未排序数组!

所以以上内容代表:[12,16,9,14,7]

您可以更改这些值(0 到 20 之间的任何值),然后在 Codepen UI 中按“运行”,它实际上会为您进行排序!

警告:在移动设备上,最后几个动画可能无法播放,屏幕会显示空白。在电脑上,风扇可能会高速运转!

这是使用太多依赖于先前计算的计算所带来的限制……我不确定是内存不足还是其他什么原因,但我肯定已经把 CSS 的性能发挥到了极致!

总之,警告完毕,请尝试一下(由于动画只播放一次,您可能需要按右下角的“重新运行”按钮)!

解释

听着,这很傻,所以我不会做教程,但有几点很有趣:

获取 v2 > v1 的布尔值。

--is-1-greater-2-step-1: Min(1, Max(var(--arr1s0) - var(--arr2s0), 0));
Enter fullscreen mode Exit fullscreen mode

看起来很复杂,但其实不然,我们正在执行以下操作:

  • 用数组中位置 1 的值减去位置 2 的值。(为了方便起见,我们称之为“diff1and2”)
  • 找出“diff1and2”和0中的最大值。我们这样做是为了表达“如果1大于2,我们希望返回一个正值;如果2大于1,我们希望返回0”。我们将结果称为“1greaterOrZero”。
  • 然后我们取“OneGreaterOrZero”,并使用`.`确保它不大于1。Min所以如果“OneGreaterOrZero”是6,我们会将其减为1,但如果它是0,则返回0。

还是不明白?下面用 JavaScript 实现:

let pos1 = 7;
let pos2 = 15;

let diff1and2 = pos1 - pos2; 
//if "diff1and2" is negative the next step will change it to 0;
let OneGreaterOrZero = Math.max(diff1and2, 0);

let result = Math.min(1, OneGreaterOrZero);

console.log(diff1and2, OneGreaterOrZero, result); //always between 0 and 1 as false / true representation.
Enter fullscreen mode Exit fullscreen mode

交换数组位置

那么我们如何交换“数组”中的位置呢?

为了使冒泡排序正常工作,我们需要能够在第一个值大于第二个值时交换这两个值。

我们不能像在 JS 中那样对临时变量进行任何特殊处理。

嗯,这就是它的用途:

--arr1s1: calc(var(--is-2-greater-1-step-1) * var(--arr1s0) + var(--is-1-greater-2-step-1) * var(--arr2s0));
--arr2s1: calc(var(--is-1-greater-2-step-1) * var(--arr1s0) + var(--is-2-greater-1-step-1) * var(--arr2s0)); 
Enter fullscreen mode Exit fullscreen mode

然而,看起来很复杂,但实际上原理相当简单。

在我们之前的“函数”中,我们创建了一个布尔值来判断 1 是否大于 2。所以那里要么是 1,要么是 0。

我们也可以很容易地得到这个结论的逆命题:

--is-2-greater-1-step-1: (1 - var(--is-1-greater-2-step-1));
Enter fullscreen mode Exit fullscreen mode

妙处在于,我们现在可以做到以下操作:


// in bubble sort, if 1 
origArray = [7,2];

// we run our previous functions to get our 2 variables:

oneIsGreater = 1;
twoIsGreater = 0;

// we can now multiply the values together. If [2] is greater than one then we will return the same value. But if [1] is greater than [2] then we will swap the values.

newArray[0] = (twoIsGreater * origArray[0]) + (oneIsGreater * origArray[1]);  
newArray[1] = (oneIsGreater * origArray[0]) + (twoIsGreater * origArray[1]); 

// which is the same as this:
newArray[0] = 0 * 7 + 1 * 2;  //2 
newArray[1] = 1 * 7 + 0 * 2;  //7

Enter fullscreen mode Exit fullscreen mode

很巧妙的技巧吧?如果将oneIsGreatertwoIsGreater互换,它就会返回原始值!

origArray = [7,2];
oneIsGreater = 0;
twoIsGreater = 1;

//same "function"
newArray[0] = (twoIsGreater * origArray[0]) + (oneIsGreater * origArray[1]);  
newArray[1] = (oneIsGreater * origArray[0]) + (twoIsGreater * origArray[1]); 

// which is the same as this:
newArray[0] = 1 * 7 + 0 * 2;  //7 
newArray[1] = 0 * 7 + 1 * 2;  //2

Enter fullscreen mode Exit fullscreen mode

这就是我们进行冒泡排序所需的全部内容!

之所以需要这么多 CSS 代码,唯一的原因是原生 CSS 目前还不支持循环。所以我们必须手动编写冒泡排序每个阶段的交换操作:

  • 检查一下,如果需要,交换1和2。
  • 检查一下,如果需要,交换2和3。
  • 检查一下,如果需要,交换3和4。
  • 检查一下,如果需要,交换4和5。
  • 检查一下,如果需要,交换1和2。
  • 检查一下,如果需要,交换2和3。
  • 检查一下,如果需要,交换3和4。
  • 检查一下,如果需要,交换1和2。
  • 检查一下,如果需要,交换2和3。
  • 检查一下,如果需要,交换1和2。

就到这里啦!

正如我所说,这不是教程。但我确实想介绍一些有趣的 CSS“开关”和“布尔值”,它们或许在未来某些特殊情况下对你有用!

希望你们喜欢我的傻气。

现在我只需要等有人问我能不能实现冒泡排序,好让我用我的 CSS 小把戏好好炫耀一番!🤣💗

文章来源:https://dev.to/grahamthedev/bubble-sortin-pure-css-no-js-3bb1