算法可视化:把难懂的代码画进梵高的星空

本文探讨了算法可视化的价值,通过实例展示了不同算法的可视化效果,如最佳候选采样、泊松盘采样和随机比较器洗牌等。文章强调了可视化在娱乐、教学、调试和学习方面的益处,并通过比较展示了不同算法的行为,如快速排序和归并排序。通过对算法的静态和动态展示,突出了可视化在理解和评估算法性能方面的作用。
摘要由CSDN通过智能技术生成

转自:大数据文摘 | bigdatadigest

O'ReillyData获转载授权


独立心灵的力量被高估了……真正的力量源自于
外部能提高认知能力的帮助。

——唐纳德


本文重点研究算法。然而,这里讨论的技术适用于更广泛的问题空间:数学公式、动态系统、过程等。基本上,任何需要理解代码的地方。


那么,为什么要可视化算法呢?甚至为什么要去可视化呢?这篇文章将告诉你,如何利用视觉去思考。


算法是可视化中一种迷人的用例。要将一种算法可视化,我们不只是将数据拟合到图表中,况且也没有主要的数据集。相反的是有描述行为的逻辑规则。这可能是算法可视化是如此不寻常的原因,因为设计师可以尝试这种新奇的形式来更好地沟通。这就是来研究它们的充分的理由。


但是,算法也提醒人们——可视化不仅仅只是一种在数据中寻找模式的工具。可视化利用人类的视觉系统,以增加人类的智慧。这样,我们就可以用它来更好地了解这些重要的抽象过程以及其他事情。


采样


在解释第一个算法之前,我首先需要解释它要解决的问题



梵高的《星夜》


光(电磁辐射),从这个屏幕上发出的光,穿过空气,由你的晶状体聚焦,并投射到视网膜上,这是一个连续的信号。要被感知,我们必须通过测量其在空间中的不同点的强度和频率分布把光信号降低到离散脉冲。


这种还原过程被称为采样,它对视觉至关重要。你可以把它理解为——一个画家应用不同的颜色,采用离散的笔触形成图像(特别是点画或点彩派)。采样其实是计算机图形学的核心关注点,例如,为了通过光线追踪来栅格化3D场景,我们必须确定在何处拍摄光线。甚至调整图像大小也需要采样。


采样会因为各种因素的矛盾性而变得困难。一方面要保证采样点要均匀分布,不要有间隙,另一方面要避免重复采样或有规律地采样(否则会产生混叠)。这就是为什么你不应该在照相时穿细条纹衬衫:条纹与相机传感器中的像素网格产生共振,从而造成莫尔条纹(Moiré patterns)。



图片来源:retinalmicroscopy.com


这是一张人类视网膜周边的显微照片。较大的锥形细胞检测颜色,而较小的杆细胞改善低光视觉。


人类的视网膜有一个出色的解决方案,在其感光细胞的位置取样。细胞密集和均匀地覆盖着视网膜(除了视神经上方的盲点),然而细胞的相对位置是不规则的。这被称为泊松盘分布,因为它保持了细胞之间的最小距离,避免遮挡而浪费光感受器。


但是构造一个泊松盘分布是困难的,因此有一个简单的叫做 Mitchel的近似算法,它是最佳候选算法。




从这些点可以看出,最佳候选采样产生了让人愉快的随机分布。这不是没有缺陷:在一些地区有太多的样本(过采样),而在其他地区是不够的(欠采样)。但它相当好,同样重要的是容易实施。


以下是它的工作原理:




对于每个新样本,最佳候选算法生成固定数量的候选采样点,用灰色表示(在这里,这个数为10)。从采样区域均匀地选择每个候选采样点。


最佳候选者,以红色显示,是离所有先前样本(以黑色显示)最远的一个。从每个候选采样点到最接近的样本的距离由相关联的线和圆圈表示:注意在灰色或红色圆圈内部没有其他样本。在创建所有候选采样点并测量距离之后,最佳候选采样点成为新样本,并且丢弃剩余候选采样点。


代码如下所示:

function sample() {

  varbestCandidate, bestDistance = 0;

  for(var i = 0; i < numCandidates; ++i) {

   var c = [Math.random() * width, Math.random() * height],

       d = distance(findClosest(samples, c), c);

   if (d > bestDistance) {

       bestDistance = d;

        bestCandidate = c;

}

  }

 return bestCandidate;

}


正如我解释了上面的算法,我会让代码独立出来。(另外,这篇文章的目的是让你通过可视化学习代码)。但我会明确一些细节:


其中numCandidates表示一次生成的候选采样点个数。这个参数让你以质量换取速度。numCandidates越小,算法运行速度越快。相反,numCandidates越大,算法运行速度越慢,但是采样质量越高。


distance函数是简单几何:

function distance(a, b) {

  vardx = a[0] - b[0],

     dy = a[1] - b[1];

 return Math.sqrt(dx * dx + dy * dy);

}


如果你想的话,在这里可以忽略开平方(sqrt),因为它是一个单调函数,并且,它不改变最佳候选采样点的结果。


findClosest函数返回距离当前候选采样点最近的采样点。我们可以使用暴力搜索来实现,即对每一个现有的采样点进行迭代。或者,可以让搜索加速,如利用四叉树搜索算法。暴力搜索实现简单,但非常慢(时间复杂度太高)。而加速方式要快得多,但需要做更多的工作来实现。


谈到权衡——在决定是否使用一个算法,我们不是凭空评估它,而是将其与其他方法进行比较。作为一个实际问题,权衡实施的复杂性:需要多久来实现、维护难度,对于衡量它的性能和质量是十分有用的。


最简单的替代方法是均匀随机采样——

function sample() {

 return [random() * width, random() * height];

}


它看起来是这样的:


  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值