纯 CSS 实现冒泡排序?[无需 JS] 😱
想象一下,你在面试时被问到“你能实现冒泡排序吗?”,你回答面试官“当然可以,你想要用 JavaScript 还是 CSS 实现?”
那该有多牛啊!
我知道你在想什么。“面试官不会对你制作的模拟冒泡排序的动画印象深刻”。你说得对!
但如果我们能用纯 CSS创建一个可运行的冒泡排序算法,并为其添加可视化效果呢?
恭喜你,你来对地方了!
演示
说明:元素顶部有 5 个值:root:
:root{
--val1: 12;
--val2: 16;
--val3: 9;
--val4: 14;
--val5: 7;
这是我们的未排序数组!
所以以上内容代表:[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));
看起来很复杂,但其实不然,我们正在执行以下操作:
- 用数组中位置 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.
交换数组位置
那么我们如何交换“数组”中的位置呢?
为了使冒泡排序正常工作,我们需要能够在第一个值大于第二个值时交换这两个值。
我们不能像在 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));
然而,看起来很复杂,但实际上原理相当简单。
在我们之前的“函数”中,我们创建了一个布尔值来判断 1 是否大于 2。所以那里要么是 1,要么是 0。
我们也可以很容易地得到这个结论的逆命题:
--is-2-greater-1-step-1: (1 - var(--is-1-greater-2-step-1));
妙处在于,我们现在可以做到以下操作:
// 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
很巧妙的技巧吧?如果将oneIsGreater和twoIsGreater互换,它就会返回原始值!
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
这就是我们进行冒泡排序所需的全部内容!
之所以需要这么多 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