<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Algorithm on Mer's Blog</title><link>https://merisky.top/tags/algorithm/</link><description>Recent content in Algorithm on Mer's Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Mon, 29 May 2023 11:38:32 +0800</lastBuildDate><atom:link href="https://merisky.top/tags/algorithm/index.xml" rel="self" type="application/rss+xml"/><item><title>Paxos 算法以及 Ceph 实现</title><link>https://merisky.top/posts/3640854188/</link><pubDate>Wed, 05 Apr 2023 14:57:58 +0000</pubDate><guid>https://merisky.top/posts/3640854188/</guid><description>&lt;p&gt;本文包含 Paxos、Multi-Paxos 算法的原理以及 Ceph 中对 Paxos 算法的实现。&lt;/p&gt;&#10;&lt;h2 id="Basic-Paxos-和-Multi-Paxos"&gt;&lt;a href="#Basic-Paxos-和-Multi-Paxos" class="headerlink" title="Basic Paxos 和 Multi-Paxos"&gt;&lt;/a&gt;Basic Paxos 和 Multi-Paxos&lt;/h2&gt;&lt;p&gt;Paxos 和 raft 算法看过不少次，但是始终属于一知半解，也没有个记录，这次把 Paxos 和 Multi-Paxos 的原理和 ceph 中 Paxos 的实现都记录一下：&lt;/p&gt;&#10;&lt;p&gt;首先是 Paxos 算法，朴素的 Paxos 算法是不包含 leader 角色的：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;proposer (提议者): 提出提案，包含提案编号（proposal ID）和一个要协商的值（Val）&lt;/li&gt;&#10;&lt;li&gt;acceptor (决策者)：参与决策，回应收到的来自 proposer 的提案，当多数 acceptor 赞成时提案通过，一般来说一个 proposer 同时也是一个 acceptor&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Basic Paxos 算法通过两阶段通过一个决议：&lt;/p&gt;</description></item><item><title>如何实现一个最小堆</title><link>https://merisky.top/posts/2906464195/</link><pubDate>Sat, 25 Mar 2023 17:36:41 +0000</pubDate><guid>https://merisky.top/posts/2906464195/</guid><description>&lt;p&gt;本文介绍如何使用 C++ 实现一个通用的、线程安全的最小堆&lt;/p&gt;&#10;&lt;p&gt;顺便一提，写此文的时候突然想到了多年以前（16、17年）盛行的 Mooc，当时国内有很多类似的慕课网站，也有很多优秀的课程，我的基础数据结构和算法就是一位 ACM 铜牌的老师教的，至今受用，但是现在好像很少看到此类网站了，还是比较可惜的。&lt;/p&gt;&#10;&lt;p&gt;进入正题，最小堆本身是一个完全二叉树，保证每一个节点都不会大于其左右子节点，要实现一个最小堆的两个核心函数是 &lt;code&gt;sift_up&lt;/code&gt; 和 &lt;code&gt;sift_down&lt;/code&gt;，用于调整最小堆结构以符合定义。&lt;/p&gt;&#10;&lt;p&gt;首先给出 &lt;code&gt;MinHeap&lt;/code&gt; 的基本定义和成员变量：&lt;/p&gt;&#10;&lt;figure class="highlight cpp"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;template&lt;/span&gt; &amp;lt;std::three_way_comparable T&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;class&lt;/span&gt; &lt;span class="title class_"&gt;MinHeap&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt; std::shared_mutex mtx;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt; std::vector&amp;lt;T&amp;gt; vec;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&amp;#125;;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p&gt;这里 &lt;code&gt;vec&lt;/code&gt; 用于保存最小堆的各个节点（完全二叉树很适合用数组保存），而 &lt;code&gt;std::three_way_comparable&lt;/code&gt; 则是对容器元素类型的 &lt;code&gt;concept&lt;/code&gt; 约束，要求元素类型必须是可比较的，毕竟不可比较的话也就没有“最小”的概念了。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;sift_down&lt;/code&gt; 和 &lt;code&gt;sift_up&lt;/code&gt; 是相反的一组用于调整堆的操作，&lt;code&gt;sift_down&lt;/code&gt; 用于将一个元素向下调整至满足最小堆的条件，&lt;code&gt;sift_up&lt;/code&gt; 则相反，由此可以知道对于任何一个完全二叉数我们只需要上到下执行 &lt;code&gt;sift_down&lt;/code&gt; 或者从下到上执行 &lt;code&gt;sift_up&lt;/code&gt; 就可以使得堆中的每一个节点都满足最小堆的条件&lt;/p&gt;</description></item><item><title>Manacher's Algorithm（求最长回文子串）</title><link>https://merisky.top/posts/4278205636/</link><pubDate>Sat, 25 Jul 2020 09:47:41 +0000</pubDate><guid>https://merisky.top/posts/4278205636/</guid><description>&lt;p&gt;本文讲述 Manacher 算法（马拉车算法）的原理以及如何利用 Manacher 算法获取最长回文子串。&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;给定一个字符串s，找到这个字符串的最长回文子串&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Example 1:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;figure class="highlight plaintext"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;Input: &amp;quot;babad&amp;quot;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;Output: &amp;quot;bab&amp;quot;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;Note: &amp;quot;aba&amp;quot; is also a valid answer.&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p&gt;&lt;strong&gt;Example 2:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;figure class="highlight plaintext"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;Input: &amp;quot;cbbd&amp;quot;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;Output: &amp;quot;bb&amp;quot;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;要找到一个字符串中的最长回文子串有以下几种方法：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;暴力搜索，算法复杂度O(N&lt;sup&gt;3&lt;/sup&gt;)&lt;/li&gt;&#10;&lt;li&gt;动态规划，算法复杂度O(N&lt;sup&gt;2&lt;/sup&gt;)&lt;/li&gt;&#10;&lt;li&gt;Manacher算法，算法复杂度O(N)&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;而本文的主角就是Manacher’s algorithm，一起来看看它的实现&lt;/p&gt;&#10;&lt;h2 id="核心思想"&gt;&lt;a href="#核心思想" class="headerlink" title="核心思想"&gt;&lt;/a&gt;核心思想&lt;/h2&gt;&lt;p&gt;Manacher算法的核心思想在于搜索以每个字符为中心的回文子串长度，并利用先前搜索的结果加快后续回文子串长度的计算&lt;/p&gt;&#10;&lt;p&gt;其中从中心向两边搜索是Manacher和动态规划方法相比暴力搜索降低复杂度的关键，而利用先前的搜索结果加快后续回文子串计算则是Manacher算法能够以不可思议的O(N)复杂度完成回文串查找的关键&lt;/p&gt;&#10;&lt;h2 id="过程"&gt;&lt;a href="#过程" class="headerlink" title="过程"&gt;&lt;/a&gt;过程&lt;/h2&gt;&lt;p&gt;以Manacher算法的一个中间过程为例&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="https://merisky.top/images/Manacher-s-Algorithm/%E6%88%AA%E5%B1%8F2020-07-24%2023.54.30.png" loading="lazy" decoding="async" alt="截屏2020-07-24 23.54.30"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;s：&lt;/strong&gt;给定的字符串&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;P：&lt;/strong&gt;手动维护，&lt;code&gt;P[i]&lt;/code&gt;保存以i位置为中心的最长子串长度&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Center：&lt;/strong&gt;当前最近的回文子串中心&lt;/p&gt;</description></item></channel></rss>