<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Data-Structures on IT Comparison</title><link>https://comparison.metacog.co.kr/tags/data-structures/</link><description>Recent content in Data-Structures on IT Comparison</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 06 Sep 2026 09:42:56 +0900</lastBuildDate><atom:link href="https://comparison.metacog.co.kr/tags/data-structures/index.xml" rel="self" type="application/rss+xml"/><item><title>B-Tree vs LSM Tree: In-Place Updates vs Log-Structured Merges</title><link>https://comparison.metacog.co.kr/posts/2026-09-06-b-tree-vs-lsm-tree-in-place-updates-vs-log-structured-merges/</link><pubDate>Sun, 06 Sep 2026 09:42:56 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-09-06-b-tree-vs-lsm-tree-in-place-updates-vs-log-structured-merges/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;B-Trees and LSM Trees are the two dominant on-disk index structures used by databases, and they diverge on how they handle writes. A B-Tree performs &lt;strong class="kw"&gt;in-place updates&lt;/strong&gt; on a balanced page structure to keep reads fast, while an LSM Tree buffers writes in memory and reconciles them later through &lt;strong class="kw"&gt;background compaction&lt;/strong&gt;, trading read simplicity for write throughput.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;text x="160" y="24" text-anchor="middle" font-size="16" style="fill:var(--primary)"&gt;B-Tree&lt;/text&gt;&lt;text x="480" y="24" text-anchor="middle" font-size="16" style="fill:var(--primary)"&gt;LSM Tree&lt;/text&gt;&lt;rect x="120" y="40" width="80" height="30" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="59" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;root&lt;/text&gt;&lt;rect x="60" y="110" width="70" height="30" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="95" y="129" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;node&lt;/text&gt;&lt;rect x="180" y="110" width="70" height="30" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="215" y="129" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;node&lt;/text&gt;&lt;rect x="15" y="180" width="55" height="28" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="42" y="198" text-anchor="middle" font-size="10" style="fill:var(--content)"&gt;leaf&lt;/text&gt;&lt;rect x="80" y="180" width="55" height="28" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="107" y="198" text-anchor="middle" font-size="10" style="fill:var(--content)"&gt;leaf&lt;/text&gt;&lt;rect x="165" y="180" width="55" height="28" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="192" y="198" text-anchor="middle" font-size="10" style="fill:var(--content)"&gt;leaf&lt;/text&gt;&lt;rect x="230" y="180" width="55" height="28" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="257" y="198" text-anchor="middle" font-size="10" style="fill:var(--content)"&gt;leaf&lt;/text&gt;&lt;line x1="160" y1="70" x2="95" y2="110" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="160" y1="70" x2="215" y2="110" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="95" y1="140" x2="42" y2="180" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="95" y1="140" x2="107" y2="180" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="215" y1="140" x2="192" y2="180" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="215" y1="140" x2="257" y2="180" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="107" y1="194" x2="150" y2="194" style="stroke:var(--compare-a)" stroke-width="1.5" stroke-dasharray="3,2"/&gt;&lt;text x="152" y="197" font-size="9" style="fill:var(--secondary)"&gt;update overwrites here&lt;/text&gt;&lt;text x="160" y="330" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;in-place updates, balanced traversal&lt;/text&gt;&lt;line x1="320" y1="30" x2="320" y2="340" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4,4"/&gt;&lt;defs&gt;&lt;marker id="arrow" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto"&gt;&lt;path d="M0,0 L8,4 L0,8 z" style="fill:var(--compare-b)"/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;rect x="400" y="45" width="160" height="34" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="66" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;memtable (in-memory)&lt;/text&gt;&lt;line x1="480" y1="79" x2="480" y2="98" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrow)"/&gt;&lt;rect x="400" y="100" width="160" height="28" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="118" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;L0 SSTables&lt;/text&gt;&lt;line x1="480" y1="128" x2="480" y2="147" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrow)"/&gt;&lt;rect x="400" y="149" width="160" height="28" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="167" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;L1 SSTables&lt;/text&gt;&lt;line x1="480" y1="177" x2="480" y2="196" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrow)"/&gt;&lt;rect x="400" y="198" width="160" height="28" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="216" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;L2 SSTables&lt;/text&gt;&lt;text x="480" y="248" text-anchor="middle" font-size="10" style="fill:var(--secondary)"&gt;compaction merges levels&lt;/text&gt;&lt;text x="480" y="330" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;sequential writes, background merge&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;B-Tree&lt;/th&gt;
&lt;th&gt;LSM Tree&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Write path&lt;/td&gt;
&lt;td&gt;Traverses the tree to locate the target page and updates it in place, splitting nodes as needed&lt;/td&gt;
&lt;td&gt;Appends the entry to an in-memory memtable plus a write-ahead log; no seek to the record&amp;rsquo;s final location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read path&lt;/td&gt;
&lt;td&gt;Single root-to-leaf traversal, O(log n) page reads from one location&lt;/td&gt;
&lt;td&gt;Checks the memtable then potentially multiple SSTables across levels, often aided by bloom filters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update/Delete handling&lt;/td&gt;
&lt;td&gt;Overwrites the existing value directly at its page&lt;/td&gt;
&lt;td&gt;Writes a new version or a tombstone; the old entry is only removed later during compaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-disk structure&lt;/td&gt;
&lt;td&gt;One mutable, balanced tree of fixed-size pages, always sorted&lt;/td&gt;
&lt;td&gt;Immutable sorted SSTable files organized into levels of increasing size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background maintenance&lt;/td&gt;
&lt;td&gt;Node splits and merges happen incrementally as part of each write&lt;/td&gt;
&lt;td&gt;Periodic compaction merges SSTables across levels and drops stale versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write amplification&lt;/td&gt;
&lt;td&gt;Low to moderate; occasional page rewrites and splits&lt;/td&gt;
&lt;td&gt;Higher; the same record can be rewritten multiple times as it moves through levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read amplification &amp;amp; space reclaim&lt;/td&gt;
&lt;td&gt;Minimal read amplification; deleted space is reclaimed immediately&lt;/td&gt;
&lt;td&gt;Higher read amplification from scanning multiple levels; space reclaimed only after compaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Range scans&lt;/td&gt;
&lt;td&gt;Efficient via sorted leaf pages linked in order&lt;/td&gt;
&lt;td&gt;Efficient within a level but requires merging sorted runs across levels&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A B-Tree updates data &lt;strong class="kw"&gt;in place&lt;/strong&gt;, while an LSM Tree defers changes through &lt;strong class="kw"&gt;append-only&lt;/strong&gt; writes to a memtable&lt;/li&gt;
&lt;li&gt;LSM Trees gain higher &lt;strong class="kw"&gt;write throughput&lt;/strong&gt; by avoiding random disk seeks, at the cost of ongoing &lt;strong class="kw"&gt;compaction&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;B-Trees give more predictable &lt;strong class="kw"&gt;read latency&lt;/strong&gt; since each key lives in exactly one place&lt;/li&gt;
&lt;li&gt;LSM read and space overhead comes from having to consult &lt;strong class="kw"&gt;multiple SSTable levels&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Deletes in an LSM Tree are recorded as &lt;strong class="kw"&gt;tombstones&lt;/strong&gt; rather than removed immediately&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;B-Tree&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Recursion vs Iteration: Two Ways to Repeat Work</title><link>https://comparison.metacog.co.kr/posts/2026-08-02-recursion-vs-iteration-two-ways-to-repeat-work/</link><pubDate>Sun, 02 Aug 2026 23:45:29 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-02-recursion-vs-iteration-two-ways-to-repeat-work/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Both techniques repeat a computation until some condition is met, but they do it through fundamentally different mechanisms. &lt;strong class="kw"&gt;Recursion&lt;/strong&gt; repeats by having a function call itself on the call stack, while &lt;strong class="kw"&gt;iteration&lt;/strong&gt; repeats by looping over the same stack frame. The choice affects memory usage, readability, and how deep a computation can safely go.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;defs&gt;&lt;marker id="arrA" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto"&gt;&lt;path d="M0,0 L8,4 L0,8 z" style="fill:var(--compare-a)"/&gt;&lt;/marker&gt;&lt;marker id="arrB" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto"&gt;&lt;path d="M0,0 L8,4 L0,8 z" style="fill:var(--compare-b)"/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;line x1="320" y1="20" x2="320" y2="340" style="stroke:var(--border)" stroke-width="1.5" stroke-dasharray="4 4"/&gt;&lt;text x="160" y="36" text-anchor="middle" style="fill:var(--primary)" font-size="18" font-weight="bold"&gt;Recursion&lt;/text&gt;&lt;text x="480" y="36" text-anchor="middle" style="fill:var(--primary)" font-size="18" font-weight="bold"&gt;Iteration&lt;/text&gt;&lt;text x="160" y="58" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;call stack&lt;/text&gt;&lt;rect x="60" y="66" width="200" height="32" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="87" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;f(n)&lt;/text&gt;&lt;rect x="60" y="104" width="200" height="32" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="125" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;f(n-1)&lt;/text&gt;&lt;rect x="60" y="142" width="200" height="32" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="163" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;f(n-2)&lt;/text&gt;&lt;rect x="60" y="180" width="200" height="26" rx="4" style="fill:none;stroke:var(--border)" stroke-width="1.5" stroke-dasharray="4 3"/&gt;&lt;text x="160" y="197" text-anchor="middle" style="fill:var(--secondary)" font-size="13"&gt;...&lt;/text&gt;&lt;line x1="278" y1="70" x2="278" y2="200" style="stroke:var(--compare-a)" stroke-width="1.5" marker-end="url(#arrA)"/&gt;&lt;text x="160" y="230" text-anchor="middle" style="fill:var(--secondary)" font-size="12"&gt;new frame per call&lt;/text&gt;&lt;text x="160" y="300" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;O(n) stack memory&lt;/text&gt;&lt;text x="160" y="318" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;risk: stack overflow&lt;/text&gt;&lt;text x="480" y="58" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;loop body (single frame)&lt;/text&gt;&lt;rect x="390" y="140" width="180" height="40" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="165" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;while / for&lt;/text&gt;&lt;path d="M 560 185 C 560 225 400 225 400 185" style="stroke:var(--compare-b);fill:none" stroke-width="1.5" marker-end="url(#arrB)"/&gt;&lt;text x="480" y="245" text-anchor="middle" style="fill:var(--secondary)" font-size="12"&gt;i++, same frame reused&lt;/text&gt;&lt;text x="480" y="300" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;O(1) stack memory&lt;/text&gt;&lt;text x="480" y="318" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;no growth per cycle&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Recursion&lt;/th&gt;
&lt;th&gt;Iteration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core mechanism&lt;/td&gt;
&lt;td&gt;Function calls itself with a smaller subproblem&lt;/td&gt;
&lt;td&gt;Explicit loop (for/while) repeats a block of code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Termination condition&lt;/td&gt;
&lt;td&gt;A base case stops further calls&lt;/td&gt;
&lt;td&gt;A loop condition evaluates to false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State storage&lt;/td&gt;
&lt;td&gt;Held implicitly in parameters and locals of each stack frame&lt;/td&gt;
&lt;td&gt;Held explicitly in variables updated each pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory usage&lt;/td&gt;
&lt;td&gt;O(n) call stack space, one new frame per call&lt;/td&gt;
&lt;td&gt;O(1) auxiliary space, the same frame is reused&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure mode&lt;/td&gt;
&lt;td&gt;Stack overflow on deep or unbounded recursion&lt;/td&gt;
&lt;td&gt;Infinite loop if the condition never turns false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance overhead&lt;/td&gt;
&lt;td&gt;Function-call overhead per level unless tail-call optimized&lt;/td&gt;
&lt;td&gt;No call overhead, just a branch/jump back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best-fit problems&lt;/td&gt;
&lt;td&gt;Tree/graph traversal, divide-and-conquer, backtracking&lt;/td&gt;
&lt;td&gt;Linear, bounded repetition like counting or array scans&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Recursion breaks a problem into &lt;strong class="kw"&gt;self-similar subcalls&lt;/strong&gt;; iteration repeats a block via an explicit loop.&lt;/li&gt;
&lt;li&gt;Recursion grows the &lt;strong class="kw"&gt;call stack&lt;/strong&gt; by one frame per call; iteration reuses a single frame.&lt;/li&gt;
&lt;li&gt;Deep recursion risks &lt;strong class="kw"&gt;stack overflow&lt;/strong&gt;, while iteration&amp;rsquo;s main failure mode is an infinite loop.&lt;/li&gt;
&lt;li&gt;Some languages apply &lt;strong class="kw"&gt;tail-call optimization&lt;/strong&gt; to turn tail recursion into iteration under the hood.&lt;/li&gt;
&lt;li&gt;Recursion maps naturally onto &lt;strong class="kw"&gt;trees and graphs&lt;/strong&gt;; iteration suits flat, bounded repetition.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Recursion&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>BFS vs DFS: Traversal Order and Data Structure</title><link>https://comparison.metacog.co.kr/posts/2026-08-02-bfs-vs-dfs-traversal-order-and-data-structure/</link><pubDate>Sun, 02 Aug 2026 23:44:09 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-02-bfs-vs-dfs-traversal-order-and-data-structure/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Both are algorithms for visiting every node in a tree or graph, but they differ in which node they explore next. &lt;strong class="kw"&gt;BFS&lt;/strong&gt; spreads outward level by level using a queue, while &lt;strong class="kw"&gt;DFS&lt;/strong&gt; plunges down one path as far as possible before backtracking, using a stack.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;line x1="320" y1="20" x2="320" y2="340" style="stroke:var(--border)" stroke-width="1.5" stroke-dasharray="5,5"/&gt;&lt;text x="160" y="28" text-anchor="middle" style="fill:var(--primary)" font-size="18" font-weight="bold"&gt;BFS&lt;/text&gt;&lt;text x="480" y="28" text-anchor="middle" style="fill:var(--primary)" font-size="18" font-weight="bold"&gt;DFS&lt;/text&gt;&lt;line x1="160" y1="50" x2="100" y2="120" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="160" y1="50" x2="220" y2="120" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="100" y1="120" x2="70" y2="190" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="100" y1="120" x2="130" y2="190" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="220" y1="120" x2="190" y2="190" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="220" y1="120" x2="250" y2="190" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;circle cx="160" cy="50" r="16" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="55" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;1&lt;/text&gt;&lt;circle cx="100" cy="120" r="16" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="100" y="125" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;2&lt;/text&gt;&lt;circle cx="220" cy="120" r="16" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="220" y="125" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;3&lt;/text&gt;&lt;circle cx="70" cy="190" r="16" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="70" y="195" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;4&lt;/text&gt;&lt;circle cx="130" cy="190" r="16" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="130" y="195" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;5&lt;/text&gt;&lt;circle cx="190" cy="190" r="16" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="190" y="195" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;6&lt;/text&gt;&lt;circle cx="250" cy="190" r="16" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="250" y="195" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;7&lt;/text&gt;&lt;line x1="480" y1="50" x2="420" y2="120" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="480" y1="50" x2="540" y2="120" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="420" y1="120" x2="390" y2="190" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="420" y1="120" x2="450" y2="190" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="540" y1="120" x2="510" y2="190" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="540" y1="120" x2="570" y2="190" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;circle cx="480" cy="50" r="16" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="55" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;1&lt;/text&gt;&lt;circle cx="420" cy="120" r="16" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="420" y="125" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;2&lt;/text&gt;&lt;circle cx="540" cy="120" r="16" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="540" y="125" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;5&lt;/text&gt;&lt;circle cx="390" cy="190" r="16" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="390" y="195" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;3&lt;/text&gt;&lt;circle cx="450" cy="190" r="16" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="450" y="195" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;4&lt;/text&gt;&lt;circle cx="510" cy="190" r="16" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="510" y="195" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;6&lt;/text&gt;&lt;circle cx="570" cy="190" r="16" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="570" y="195" text-anchor="middle" style="fill:var(--content)" font-size="13"&gt;7&lt;/text&gt;&lt;rect x="60" y="260" width="28" height="24" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="92" y="260" width="28" height="24" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="124" y="260" width="28" height="24" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="156" y="260" width="28" height="24" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="188" y="260" width="28" height="24" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="20" y="277" style="fill:var(--secondary)" font-size="11"&gt;out&lt;/text&gt;&lt;text x="232" y="277" style="fill:var(--secondary)" font-size="11"&gt;in&lt;/text&gt;&lt;text x="140" y="305" text-anchor="middle" style="fill:var(--secondary)" font-size="13"&gt;Queue (FIFO)&lt;/text&gt;&lt;rect x="466" y="228" width="56" height="22" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="466" y="252" width="56" height="22" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="466" y="276" width="56" height="22" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="466" y="300" width="56" height="22" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="535" y="243" style="fill:var(--secondary)" font-size="11"&gt;push/pop&lt;/text&gt;&lt;text x="494" y="340" text-anchor="middle" style="fill:var(--secondary)" font-size="13"&gt;Stack (LIFO)&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;BFS&lt;/th&gt;
&lt;th&gt;DFS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Underlying structure&lt;/td&gt;
&lt;td&gt;Queue (FIFO)&lt;/td&gt;
&lt;td&gt;Stack (FILO), often via recursion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traversal pattern&lt;/td&gt;
&lt;td&gt;Explores all neighbors at current depth before going deeper&lt;/td&gt;
&lt;td&gt;Follows one branch to its end before backtracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Order nodes are visited&lt;/td&gt;
&lt;td&gt;Level by level (breadth-first)&lt;/td&gt;
&lt;td&gt;Branch by branch (depth-first)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory usage&lt;/td&gt;
&lt;td&gt;O(width) — can be large for wide/bushy graphs&lt;/td&gt;
&lt;td&gt;O(depth) — can be large for deep graphs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shortest path guarantee&lt;/td&gt;
&lt;td&gt;Yes, on unweighted graphs (first visit = shortest path)&lt;/td&gt;
&lt;td&gt;No, may find a longer path first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation style&lt;/td&gt;
&lt;td&gt;Iterative with explicit queue&lt;/td&gt;
&lt;td&gt;Recursive, or iterative with explicit stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk of infinite loop&lt;/td&gt;
&lt;td&gt;Low with visited-set on cyclic graphs&lt;/td&gt;
&lt;td&gt;Higher on cyclic graphs without visited-set, or infinite depth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical use cases&lt;/td&gt;
&lt;td&gt;Shortest path, level-order processing, web crawling by hops&lt;/td&gt;
&lt;td&gt;Topological sort, cycle detection, maze/backtracking problems&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong class="kw"&gt;BFS&lt;/strong&gt; uses a queue and expands outward level by level, while &lt;strong class="kw"&gt;DFS&lt;/strong&gt; uses a stack (or recursion) and dives deep before backtracking.&lt;/li&gt;
&lt;li&gt;BFS guarantees the &lt;strong class="kw"&gt;shortest path&lt;/strong&gt; on unweighted graphs; DFS does not.&lt;/li&gt;
&lt;li&gt;BFS memory cost scales with graph &lt;strong class="kw"&gt;width&lt;/strong&gt;, while DFS memory cost scales with graph &lt;strong class="kw"&gt;depth&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;DFS naturally supports &lt;strong class="kw"&gt;backtracking&lt;/strong&gt; algorithms like maze solving and topological sort.&lt;/li&gt;
&lt;li&gt;Both require a &lt;strong class="kw"&gt;visited set&lt;/strong&gt; to avoid infinite loops on cyclic graphs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;BFS&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Two Pointers vs Sliding Window: Choosing the Right Array Scanning Technique</title><link>https://comparison.metacog.co.kr/posts/2026-08-02-two-pointers-vs-sliding-window-choosing-the-right-array-scan/</link><pubDate>Sun, 02 Aug 2026 23:43:16 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-02-two-pointers-vs-sliding-window-choosing-the-right-array-scan/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Two Pointers and Sliding Window are both O(n) techniques for scanning arrays or strings, but they solve different shapes of problems: Two Pointers tracks two independent &lt;strong class="kw"&gt;indices&lt;/strong&gt; that move toward, away from, or alongside each other, while Sliding Window maintains a contiguous &lt;strong class="kw"&gt;subrange&lt;/strong&gt; that expands and contracts as it scans. Picking the wrong one usually means either overcomplicating a pair-search problem or missing the running aggregate a window naturally provides.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;defs&gt;&lt;marker id="arrowA" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto"&gt;&lt;path d="M0,0 L6,3 L0,6 Z" style="fill:var(--compare-a)"/&gt;&lt;/marker&gt;&lt;marker id="arrowB" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto"&gt;&lt;path d="M0,0 L6,3 L0,6 Z" style="fill:var(--compare-b)"/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;text x="160" y="36" text-anchor="middle" font-size="18" style="fill:var(--primary)"&gt;Two Pointers&lt;/text&gt;&lt;text x="480" y="36" text-anchor="middle" font-size="18" style="fill:var(--primary)"&gt;Sliding Window&lt;/text&gt;&lt;line x1="320" y1="20" x2="320" y2="340" stroke-width="1" stroke-dasharray="4,4" style="stroke:var(--border)"/&gt;&lt;g&gt;&lt;rect x="40" y="150" width="28" height="40" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="72" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="104" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="136" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="168" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="200" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="232" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="264" y="150" width="28" height="40" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="54" y="176" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;L&lt;/text&gt;&lt;text x="278" y="176" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;R&lt;/text&gt;&lt;line x1="60" y1="215" x2="130" y2="215" stroke-width="2" marker-end="url(#arrowA)" style="stroke:var(--compare-a)"/&gt;&lt;line x1="272" y1="215" x2="202" y2="215" stroke-width="2" marker-end="url(#arrowA)" style="stroke:var(--compare-a)"/&gt;&lt;text x="166" y="270" text-anchor="middle" font-size="12" style="fill:var(--secondary)"&gt;indices converge inward&lt;/text&gt;&lt;text x="166" y="288" text-anchor="middle" font-size="12" style="fill:var(--secondary)"&gt;over sorted data&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x="424" y="150" width="92" height="40" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="360" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="392" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="424" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="456" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="488" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="520" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="552" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;rect x="584" y="150" width="28" height="40" style="fill:none;stroke:var(--border)" stroke-width="1"/&gt;&lt;text x="424" y="176" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;L&lt;/text&gt;&lt;text x="512" y="176" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;R&lt;/text&gt;&lt;line x1="522" y1="170" x2="552" y2="170" stroke-width="2" marker-end="url(#arrowB)" style="stroke:var(--compare-b)" stroke-dasharray="3,3"/&gt;&lt;text x="486" y="270" text-anchor="middle" font-size="12" style="fill:var(--secondary)"&gt;contiguous range expands/&lt;/text&gt;&lt;text x="486" y="288" text-anchor="middle" font-size="12" style="fill:var(--secondary)"&gt;contracts, tracking an aggregate&lt;/text&gt;&lt;/g&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Two Pointers&lt;/th&gt;
&lt;th&gt;Sliding Window&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core mechanism&lt;/td&gt;
&lt;td&gt;Two independent indices scan or converge across the data&lt;/td&gt;
&lt;td&gt;Two indices (left/right) define a contiguous range that grows and shrinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pointer movement&lt;/td&gt;
&lt;td&gt;Move toward each other, away, or in lockstep at a fixed offset&lt;/td&gt;
&lt;td&gt;Right pointer expands the range forward, left pointer contracts it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input requirement&lt;/td&gt;
&lt;td&gt;Usually needs sorted data or a paired structure&lt;/td&gt;
&lt;td&gt;Works on any unsorted array or string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State tracked&lt;/td&gt;
&lt;td&gt;Just the two positions and the values being compared&lt;/td&gt;
&lt;td&gt;A running aggregate of window contents (sum, count, frequency map)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Problem signature&lt;/td&gt;
&lt;td&gt;Pair-sum, palindrome check, merging two sorted arrays&lt;/td&gt;
&lt;td&gt;Longest/shortest substring or max/min sum under a constraint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relationship between pointers&lt;/td&gt;
&lt;td&gt;No notion of a range between them, only the two positions matter&lt;/td&gt;
&lt;td&gt;The range between the pointers IS the answer candidate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time and space complexity&lt;/td&gt;
&lt;td&gt;O(n) time, O(1) space&lt;/td&gt;
&lt;td&gt;O(n) time, O(1) to O(k) space for the aggregate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure mode&lt;/td&gt;
&lt;td&gt;Breaks if data isn&amp;rsquo;t sorted or orderable for the comparison&lt;/td&gt;
&lt;td&gt;Breaks if the target condition isn&amp;rsquo;t monotonic, so the window can&amp;rsquo;t shrink safely&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Two Pointers tracks two independent &lt;strong class="kw"&gt;indices&lt;/strong&gt;; Sliding Window tracks a contiguous &lt;strong class="kw"&gt;range&lt;/strong&gt; between them.&lt;/li&gt;
&lt;li&gt;Two Pointers typically requires &lt;strong class="kw"&gt;sorted input&lt;/strong&gt;; Sliding Window works fine on unsorted sequences.&lt;/li&gt;
&lt;li&gt;Sliding Window maintains a running &lt;strong class="kw"&gt;aggregate&lt;/strong&gt; as it moves; Two Pointers usually just compares individual values.&lt;/li&gt;
&lt;li&gt;Sliding Window breaks down when the target condition isn&amp;rsquo;t &lt;strong class="kw"&gt;monotonic&lt;/strong&gt;, since the window can&amp;rsquo;t be safely shrunk.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Two Pointers&lt;/strong&gt;&lt;/p&gt;</description></item></channel></rss>