IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

算法

共 589 篇文章

IT 2013-09-02 13:14:59 / 累计浏览 2,485

五种常用基数估计算法效果实验及实践建议

这篇讲的是作者对五种常用基数估计算法——Linear Counting、LogLog Counting、Adaptive Counting、HyperLogLog Counting和HyperLogLog++ Counting——进行的系统性实验对比。作者依托团队的开源库ccard-lib,在均匀哈希的数据集上,对它们在不同数据规模下的估计误差、内存占用及收敛速度进行了详尽的图表化展示。 实验揭示了每种算法独特的性能区间与权衡。例如,Linear Counting在基数较小时精度高但内存消耗大;而HyperLogLog++在处理海量数据时展现了卓越的稳定性与空间效率。文章不仅直观呈现了算法从理论走向实践时的表现差异,更基于这些一手数据,提炼出了极具参考价值的选型与调优建议。 如果你正在为特定业务场景(如实时流统计、大规模日志分析)选择基数估算方案,或是想理解不同算法在工程实现中的真实效能,这篇结合了定量实验与实用结论的深度对比,能为你提供清晰的技术路线参考。

本机暂存
IT 2013-08-29 13:42:02 / 累计浏览 3,308

Reddit排名算法工作原理

这篇讲的是Reddit两大排名算法的实现原理——文章热榜与评论置顶,它们背后的数学逻辑截然不同。 文章排名算法旨在让新内容快速脱颖而出。它用对数函数弱化后期高票数的权重,使得前10票的影响力堪比后续100票,这让早期获得一定认同的内容能迅速升至顶部。同时,算法将提交时间直接纳入公式,新提交的文章天然享有更高的初始分数,确保社区内容的时效性。有趣的是,该算法对争议性内容“不友好”,因为得票数计算为净赞数,导致高赞高踩的激烈讨论反而可能排名靠后。 评论排序则采用了完全不同的“信任评级”算法。它由xkcd作者提出,基于统计学中的Wilson得分区间,旨在找出最受读者信任、而不仅是最早出现的评论。该算法将投票视为对真实支持率的一次抽样,即使投票数少,也能给出一个相对可靠的置信评分。这种设计巧妙地忽略了发布时间的影响,让一条优质评论无论何时提交,都有机会在获得足够投票后登顶。 两种算法体现了不同的设计目标:文章算法追求社区活跃度与新内容的曝光,评论算法则致力于挖掘经得起数据验证的最佳讨论。

本机暂存
IT 2013-08-29 13:36:59 / 累计浏览 7,407

Hacker News 排名算法工作原理

这篇深入剖析了Hacker News标志性的排名算法。作者从HN开源代码中提取出核心公式:得分 = (投票数-1) / (提交时间+2)^比重。这个简洁的公式,通过“比重”参数G(默认值1.8)巧妙地平衡了热门内容和时效性——G越大,老内容得分衰减越快,新文章越容易获得曝光。 文章不仅解读了公式,还通过Wolfram Alpha绘制的曲线图,直观展示了时间T和比重G如何影响分数衰减。它进一步揭示了算法中针对不同类型内容(如无链接帖子、轻量级内容)的系数调整,以及如何用Python几行代码实现它。最后,文章还附上了Paul Graham公布的、更为复杂的修正版算法,展示了实际工程中的权衡。 这篇文章的价值在于,它拆解了一个看似简单却极其有效的排名系统,揭示了如何用数学方法同时解决内容冷启动和热度衰减这两个社区产品的核心难题,对任何想构建内容推荐或排序系统的人都有直接的启发。

本机暂存
IT 2013-08-26 22:54:50 / 累计浏览 3,383

线性代数的妙用:怎样在Windows画图软件中实现28度旋转?

这篇讲的是如何在Windows画图软件中实现28度旋转。作者从画图软件通常只支持90度整数倍旋转的限制出发,展示了如何利用“扭曲”功能近似实现任意角度旋转。具体方法是连续执行三次扭曲操作:先水平扭曲-14度,然后垂直扭曲25度,最后再水平扭曲-14度,这样就能让选中区域逆时针旋转28度。 背后的实现思路基于线性代数。水平扭曲相当于对图像各行进行平移,对应一个切变矩阵;垂直扭曲类似,但矩阵形式略有不同。通过将这三次操作连续应用,其复合矩阵近似于标准的旋转矩阵。由于垂直扭曲需要使用正切值来模拟旋转矩阵中的sin值,当θ=28°时,sin(28°)≈0.469,而最接近的正切值是tan(25°)≈0.466,因此第二步填入了25度作为垂直扭曲角度。 这种方法的巧妙之处在于高效且无需额外内存:每次扭曲只涉及像素行或列的平移操作,算法简单易实现。文章提到,这是Alan Paeth在1986年提出的经典算法,展示了线性代数在简单软件中的实用妙用。尽管存在微小误差,但结合画图软件的缩放功能,还能设计更灵活的旋转方案,为读者提供了进一步探索的空间。

本机暂存
IT 2013-08-21 13:17:04 / 累计浏览 2,603

广告从业者的良心

这篇讲的是计算广告从业者的职业价值与良心困境。 作者从Facebook技术高管那句“我们这一代最聪明的人都在思考如何让人点击广告”的感慨出发,探讨了行业现状。他认为,顶尖人才聚集于计算广告领域有其必然性:广告是互联网公司最主要的生存之本,优化广告效果直接关系到企业收入,这本身无可厚非。 更重要的是,作者从“阳光”的一面阐述了计算广告的正面价值。其本质是高效的信息匹配:将特定信息送达有需求的受众,创造多方共赢。例如,维基百科通过精准的广告被更多人发现,用户获得了有用信息,广告平台也履行了连接责任。从业者提升的关键,是让广告信息对用户更有用,而非单纯增加广告量。 文章也明确了行业的“节操”底线:不能欺骗广告主与用户,不能传播违法内容。作者认为,技术可以有强弱,但良心不能泯灭,最终回归到“有节操地改善人类信息获取方式”这一初心。

本机暂存
IT 2013-08-13 13:08:27 / 累计浏览 7,262

Python程序的执行原理

这篇讲的是Python代码从源文件到运行背后的核心机制——字节码与虚拟机如何协同工作。文章从最简单的“Python先把代码编译成字节码”这一概述出发,层层深入,带我们看清了执行过程的每个关键环节。 作者详细拆解了字节码在Python内部的具体形态——PyCodeObject对象,并剖析了其结构体定义,如co_code、co_consts等字段如何承载代码信息。对于开发者日常可能遇到的.pyc文件,文章也理清了它的生成时机(模块import时)与Python的加载更新策略,解开了不少常见疑惑。 文章的精彩之处在于将理论落地到可操作的层面。它展示了如何利用内置的compile函数和dis模块,去实际“解剖”一段代码对应的字节码指令序列,让抽象概念变得可视、可调试。最后,文章将视角拉升到虚拟机执行层面,通过类比X86的栈帧,讲解了Python如何通过PyFrameObject管理函数调用和作用域,完整模拟了一个程序的运行世界。 整篇文章就像一份精心绘制的内部结构蓝图,不仅告诉你Python“怎么做”,更展示了它是“如何做到”的,非常适合希望突破语法层面、理解Python执行本质的开发者。

本机暂存
IT 2013-08-12 13:35:08 / 累计浏览 4,305

淘宝搜索中Query下拉推荐技术

这篇讲的是淘宝搜索下拉推荐系统如何从基础算法演进到更智能的方案。下拉推荐能帮用户快速明确搜索意图,是提升搜索体验的关键。 文章从最基础的基于查询词历史PV的推荐策略说起,指出其存在长尾覆盖不足、推荐结果语义重复以及低质或作弊查询容易被推高排序等问题。为解决这些问题,作者介绍了两轮核心迭代:第一步,引入“查询词静态分”这一综合质量指标,它融合了流量、点击、交易转化等多维度数据,用它来排序,能让交易质量高的查询词获得更多机会,有效打压了作弊查询。第二步,则进一步建立了搜索词与候选查询词的动态联系,通过CTR预估模型来预测用户对推荐词的点击率,模型综合考虑了搜索词与候选词的内容相关性、类目匹配度以及结果页特征等,让排序更具个性化和预见性。 文章最后还提到了拼音搜索、拼写纠错、作弊清理及个性化等进阶方向,展现了淘宝搜索推荐系统从简单排序到多维度、动态智能化的完整演进路径。

本机暂存
IT 2013-08-12 13:32:35 / 累计浏览 4,505

Learning to rank在淘宝的应用

这篇讲的是淘宝搜索排序系统如何从传统手工调参进化到机器学习自动化调整的实践。作者从排序优化的核心难点切入:传统方法依赖人工特征调优和反复AB测试,效率低且难达最优。为此,团队在已有特征体系上应用了Learning to Rank技术,项目内部命名为Jazz。 其核心方案是采用pairwise方法来构建训练数据,但做法很有淘宝特色:没有像常规那样做耗时耗力的人工标注,而是直接利用用户的点击和购买行为数据自动生成商品对。同时,为了保证排序稳定性,还混合了部分原始排序的样本进行分层抽样。模型训练后,通过计算NDCG指标在线下评估效果,显著缩短了测试周期。 文章详细拆解了从数据生产、模型训练到效果评估的全流程架构,并坦诚分析了pairwise方法在具体实施中遇到的挑战,比如与传统论文中描述不同的样本构建思路。这种将工业级实践与算法原理结合的分享,清晰地展示了机器学习技术如何解决真实业务中的复杂排序问题。

本机暂存
IT 2013-07-15 13:23:33 / 累计浏览 2,221

CFS中的虚拟运行时间

这篇讲的是Linux内核CFS调度器中最核心也最容易让人困惑的一个概念:虚拟运行时间(vruntime)。作者从对vruntime的不理解出发,在研究cgroup的CPU子系统时,才真正理清了它的原理。 CFS追求的是理想中的“完全公平”,但现实中同一时刻一个CPU核心只能跑一个进程。因此,算法需要一种机制来惩罚当前占用CPU的进程,从而照顾那些等待的进程。这个机制,就是vruntime。简单说,vruntime越小的进程,越值得被调度。 它的精妙之处在于计算方式:vruntime并非进程实际运行的时间,而是结合了进程“权重”后的换算值。权重越大(对应用户态优先级nice值越低),进程实际运行一毫秒所产生的vruntime就越小,这样它在调度队列中的位置就越靠前(内核用一棵红黑树管理,vruntime小的在左端),从而获得更多的CPU时间。 文章还揭示了内核是如何将用户熟悉的nice值映射到内部权重的,那就是通过一个叫`prio_to_weight`的静态数组进行转换。这套机制将“优先级”这个概念,巧妙地转化为“需要运行的紧迫度”,从而在动态调度中实现了对不同重要性进程的公平分配。

本机暂存
IT 2013-07-15 13:18:51 / 累计浏览 2,447

如何通过数据来指导产品进行优化

这篇讲的是如何用数据驱动产品优化,以登录体验的实战为例。 文章先点出登录成功率是衡量体验的核心指标,通过数据分析发现,密码、账户名和校验码出错是导致登录失败的三大原因。作者没有停留在表面,而是深挖“校验码为什么出错”,定位到“识别度低”这个根本问题。 优化方案很有层次感,围绕校验码提出了“事前、事中、事后”的解决思路。比如“事前”通过技术提前识别真人,直接减少不必要的校验码出现;“事中”则降低易混淆字符(如0和O)的出现概率,并增加输入即时反馈;“事后”为输错的用户强化刷新指引和语音备选。这些具体手段都带来了可衡量的成功率提升。 最后,文章总结出一套通用方法:先确定可量化的体验指标,再通过数据精准定位问题症结,最后通过迭代优化并用数据验证效果。整个过程强调用数据说话,而非主观臆断,对产品经理和设计师都有直接的参考价值。

本机暂存
IT 2013-07-15 13:03:13 / 累计浏览 4,044

二叉树迭代器算法

这篇文章探讨了如何为二叉树设计迭代器,从而将遍历算法与具体数据结构解耦,实现如通用求和函数这样的抽象操作。作者指出,直接转换递归遍历行不通,因为其依赖编译器管理的隐式调用栈。核心思路是通过显式栈结构来手动控制遍历流程。 文章详细展示了如何基于栈实现一个非递归的中序遍历,并将其封装为包含`next()`方法的迭代器。关键设计在于,迭代器的状态完全由栈的内容决定,每次调用`next()`对应一次栈操作。作者还澄清了一个常见误区:尽管单次`next()`调用可能涉及多次栈操作,但由于每个节点在整个迭代过程中仅入栈和出栈一次,因此总时间复杂度仍是线性的O(n),与递归遍历一致。 最后,文章简要对比了在支持`yield`语义的语言(如Python)中,一种更直观的生成器实现方式,并提示读者思考其背后的变换原理。

本机暂存
IT 2013-07-07 21:46:52 / 累计浏览 2,266

通信复杂度问题:确定双方手中所有数的中位数

这篇讲的是通信复杂度中一个经典问题的算法设计:两地的两个人各自持有一个数字集合,他们想用尽可能少的通信来共同确定两个集合合并后的中位数,而不是笨拙地传输全部数据。 作者从问题背景出发,清晰地展示了从“暴力传输”到“极精巧算法”的优化路径。最初,A把全部数据传给B,通信量是O(n)比特;随后,通过在区间上进行多轮二分查找,算法被优化至O(log²n)。文章的高潮在于将复杂度降至O(logn)的精妙改进。核心思路是让双方比较各自数列的中位数a和b,根据大小关系丢弃一半不可能成为答案的数据。但关键在于,双方不需要完整传输a和b的数值,而是从高位到低位逐位比较并发送比特。一旦某一位不同就能立即停止本轮比较;同时,由于数据集在每轮都被减半,之前比过的公共前缀位在未来轮次中可以直接跳过。这种逐位比较与信息复用,将总通信量压到了O(logn)。 文章不仅给出了算法,还从信息论角度推导了Ω(logn)的下界,完整勾勒出问题的解空间。其价值在于,通过一个看似简单的游戏,生动展现了通信复杂度的理论力量与算法设计的艺术。

本机暂存
IT 2013-07-07 17:56:41 / 累计浏览 2,603

与Google拼音的工程师聊聊中文滑行输入

这篇讲的是作者因Google拼音输入法新增中文滑行功能,与负责该产品的工程师在微博上展开的一场产品辩论。讨论从实际体验出发,核心聚焦于中文输入法的创新路径:是追求如“搜狗拼音”般能改变用户习惯的质变,还是应尊重既有输入习惯进行渐进优化。 作者认为,滑行输入若想取代根深蒂固的九宫格习惯,效率需有颠覆性提升(如两倍以上)。而工程师则澄清,滑行输入的目标用户是全键盘群体,并非为替代九宫格;创新的关键在于“在不彻底变革用户习惯的前提下,一小步提升效率”,并以QWERTY键盘沿用至今为例,说明习惯的顽固性。 这场对话生动展现了产品经理与用户视角的差异:前者关注现有用户群的体验优化与市场细分,后者则从颠覆性创新和新商业可能的角度出发。最终,双方都认同微博是收集真实反馈的宝贵渠道。这段交锋也让读者思考:技术功能迭代时,如何平衡提升效率与尊重用户固有习惯,这或许比单纯追求算法先进性更值得琢磨。

本机暂存
IT 2013-06-17 23:45:27 / 累计浏览 4,122

cpp智能指针的简单实现

这篇讲的是如何从零开始实现一个C++智能指针。文章直指C++没有垃圾回收导致的内存管理痛点——手动配对`new`和`delete`极易出错和内存泄漏,随后切入智能指针如何通过引用计数来自动化这一过程。 作者的实现核心在于一个巧妙的设计:使用一个在栈上自动管理生命周期的包装类`Ptr`,其内部持有一个指向堆上辅助类`SmartPtr`的指针。这个辅助类负责记录引用计数和实际的数据。当`Ptr`对象被复制时,引用计数增加;当其析构时,引用计数减少。只有当引用计数降为零,意味着没有`Ptr`实例再指向它时,辅助类及其管理的内存才会被释放。 这种“栈对象包装堆对象”的思路,正是智能指针将语言特性(栈自动回收)与手动内存管理相结合的关键。文章通过一段可运行的代码清晰地展示了引用计数的增减时机,让抽象的原理变得直观。理解了这个手动实现,也就真正理解了智能指针在C++内存模型中的运作基石。

本机暂存
IT 2013-06-02 19:43:32 / 累计浏览 3,743

由原子操作引起的关于Cache的讨论

这篇讲的是一个实际的性能排查案例:在MPI集群上,当PLDA算法与MLR或PLSA同时运行时,后者效率会大幅下降。问题最初被指向PLDA中频繁使用的原子操作——`lock incl`指令。用户担心这个`lock`前缀会锁死内存总线,拖垮整台机器。 作者澄清了一个常见误解:在现代CPU(如Nehalem架构)上,`lock`前缀在绝大多数情况下并不会锁总线,而是通过一种被称为“cache lock”的机制,在cache line级别实现原子性。他结合Intel手册与同行讨论,进一步指出硬件上并不存在真正的“cache lock”,而是依赖MESI这类缓存一致性协议来保证原子性。例如,带有写意图的原子读操作会触发RFO,导致其他核心的相关缓存失效,但这并不等同于锁住整个总线。 基于这个理解,问题的优化方向就清晰了:为了最小化不同任务之间的干扰,可以通过cgroup将它们绑定到不同的物理CPU上,从而隔离L1缓存。最终,作者通过共享内存和原子操作,替代了原先为每个线程分配独立大内存的做法,得以在限制内存占用的同时,启动更多线程将CPU利用满,反而获得了整体性能的提升。 对读者而言,这是一次从具体现象深入到底层硬件原理(CPU缓存一致性协议)的实用分析,有助于理解并发编程中原子操作的真实开销与优化思路。

本机暂存
IT 2013-06-02 19:42:39 / 累计浏览 6,662

无锁HashMap的原理与实现

这篇讲的是如何绕过传统锁机制,实现一个能在多线程环境下高性能运行的HashMap。作者从Java中HashMap的线程安全痛点出发,指出常用的锁替代方案都存在性能或复杂性问题,从而引出了基于CAS(比较并交换)指令的无锁编程思路。 文章的核心是清晰地拆解了无锁HashMap的实现蓝图。它先带你理解了更基础的无锁链表如何利用CAS保证插入和删除操作的原子性,然后直面HashMap最大的挑战——ReHash(扩容)。作者巧妙地借鉴了“分裂有序链表”的思想,通过一种预先对节点哈希值进行位翻转排序并引入哨兵节点的方法,让整个链表在逻辑上始终有序。这样一来,数组扩容时节点只需要确认自己在新链表中的归属,而无需物理移动,从而破解了传统实现中需要同时原子修改多个指针的难题。 此外,文章还提到了为了提升效率而采用的数组懒加载、分块初始化等工程细节。整体而言,这是一篇从原理到实现都讲解得非常扎实的文章,把一个复杂的并发数据结构设计问题,梳理得条理分明。

本机暂存
IT 2013-05-20 23:30:33 / 累计浏览 2,946

算法分析中递推式的一般代数解法

这篇讲的是算法分析中一个关键但常被绕开的数学工具:如何用特征方程法,系统地求解递推关系式。文章作者直接切入,以经典的汉诺塔问题 T(n) = 2T(n-1) + 1 为例,演示了如何将这个递推式转化为封闭形式 T(n) = 2ⁿ - 1 的完整代数过程。 这种技巧是理解递归算法(如分治法)真实复杂度的基石。它超越了仅靠“主定理”快速查表的层面,让你能亲手推导并理解那些复杂度结论的由来。文章不仅给出了步骤,更重要的是展现了从递归定义到显式公式的逻辑链条,让你在遇到新的递推关系时,能有章可循地求解,而不仅仅是猜测或依赖现成结论。 对于需要分析自定义算法复杂度,或想更深入理解算法导论中数学原理的开发者来说,这篇文章提供了一套清晰、可操作的代数解法框架。

本机暂存
IT 2013-05-17 13:47:17 / 累计浏览 5,881

经典证明:任意三角形都能被分成n≥4个等腰三角形

这篇讲的是一个经典的几何分割问题:如何把任意一个三角形分成任意多个(n≥4)等腰三角形。问题源自1976年的数学期刊,而1977年由Gali Salvatore给出了一套非常巧妙的通用证明。 作者从最基础的分割方法入手:先作高线把原三角形分成两个直角三角形,再对每个直角三角形作斜边中线,即可得到4个等腰三角形。基于这个“单元”,通过递归地对其中一个等腰三角形进行同样操作,就能以每次+3的增量,解决所有形如 n=4, 7, 10, 13… 的情况。 证明的关键在于处理 n=5 和 n=6 这两个“基例”。n=6 的方案相对直接,而 n=5 则需要一个巧妙的“预留一个等腰三角形,再把剩余部分分成四份”的策略。值得一提的是,这种方法无法直接用于等边三角形,文章为此专门展示了等边三角形分割成5个等腰三角形的独立方案,体现了思考的完备性。 整个证明思路层层递进,从通用构造到处理特殊情况,将一个看似复杂的问题分解为几个清晰可操作的步骤,展现了数学构造中的严谨与美感。

本机暂存
IT 2013-05-01 22:59:07 / 累计浏览 6,464

更快的IP库查找方法以及AWK中的二分查找

这篇讲的是如何用AWK高效处理IP地址定位问题。作者从实际工作中需要将大量用户IP映射到国家的需求出发,手头有12.5万条IP段的数据库和4万条用户记录。 起初,作者采用最直观的遍历方法,即对每个用户IP逐一扫描整个IP库进行匹配。虽然逻辑简单,但面对这个规模的数据,处理耗时长达40分钟,效率堪忧。 为了提速,作者在AWK中引入了二分查找算法。核心思路是将IP段数据预先加载到数组,然后对每个用户IP,通过比较中点值快速缩小搜索范围,而不是逐条检查。这个改造带来了惊人的性能提升:全部检索时间从40分钟骤降至不到2分钟,效率提高了20倍。 这个案例不仅解决了具体问题,也打破了作者原先认为“在AWK这类脚本语言中不适合实现算法”的固有印象,展示了选择合适算法对数据处理效率的决定性影响。

本机暂存
IT 2013-05-01 22:55:34 / 累计浏览 14,348

为什么你写不好一个快速排序? 谈程序员的职业发展

一位资深程序员的自我拷问:为什么我写不好一个快速排序了?作者从自己的真实经历出发,讲述了工作六七年、title和薪水都提升后,却发现自己的基础编码能力(如实现快速排序)甚至不如一些应届生的困惑。他坦诚地反思,这源于过去听信“不要重复造轮子”而忽视了基础训练,以及在职业上升期,作为程序员最核心的“把想法快速变成正确代码”的能力被逐渐淡忘。 文章将程序员与医生类比——主任医师依然需要主刀,以此尖锐地指出技术岗位的核心竞争力所在。作者并非否定项目经验的价值,而是强调,若没有扎实的底层编码能力作为基石,那些“牛B的经历”可能只是平台与顺境带来的附加值。他最终将职业梦想落回原点:用扎实的编码能力赢得同行的尊重。这篇反思为所有走技术路线的人提了个醒:无论走得多远,别忘了那个让你成为程序员的起点。

本机暂存