<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://program.sonsuz.us/feed.xml" rel="self" type="application/atom+xml" /><link href="https://program.sonsuz.us/" rel="alternate" type="text/html" /><updated>2026-10-15T00:05:39+00:00</updated><id>https://program.sonsuz.us/feed.xml</id><title type="html">SonsuzUs</title><subtitle>Programlama ve Yazılım</subtitle><author><name>Sonsuz Us</name></author><entry><title type="html">2-3 Arama Ağaçları ve Kırmızı-Siyah Ağaçlarla Gizli Akrabalığı</title><link href="https://program.sonsuz.us/posts/2-3-arama-agaclari-ve-kirmizi-siyah-agaclarla-gizli-akrabaligi/" rel="alternate" type="text/html" title="2-3 Arama Ağaçları ve Kırmızı-Siyah Ağaçlarla Gizli Akrabalığı" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/2-3-arama-agaclari-ve-kirmizi-siyah-agaclarla-gizli-akrabaligi</id><content type="html" xml:base="https://program.sonsuz.us/posts/2-3-arama-agaclari-ve-kirmizi-siyah-agaclarla-gizli-akrabaligi/"><![CDATA[<p>İkili arama ağaçları hızlı arama sunar; fakat anahtarlar sıralı geldiğinde ağaç bir çubuk gibi uzayabilir. 2-3 arama ağaçları bu sorunu, her düğümde bir yerine birden fazla anahtar saklayarak çözer. Daha da ilginci, kırmızı-siyah ağaçlar bu çok anahtarlı yapının ikili ağaç kılığına girmiş hâli olarak yorumlanabilir.</p>

<p><img src="/img/2-3-arama-17.svg" alt="2-3-arama-17" /></p>

<p>``</p>

<h2 id="2-3-ağacı-nedir">2-3 ağacı nedir?</h2>

<p>Bir 2-3 ağacındaki iç düğüm iki biçimden birine sahiptir:</p>

<ul>
  <li><strong>2-düğüm:</strong> Bir anahtar ve iki çocuk taşır.</li>
  <li><strong>3-düğüm:</strong> İki sıralı anahtar ve üç çocuk taşır.</li>
</ul>

<p>Bir 3-düğümde anahtarlar $a &lt; b$ ise sol alt ağaçtaki değerler $a$’dan küçük, ortadakiler $a$ ile $b$ arasında, sağdakiler ise $b$’den büyüktür. Böylece ikili arama ağacının sıralama mantığı korunurken tek seviyede daha fazla bilgi tutulur.</p>

<p>Asıl denge garantisi şu değişmezden gelir: <strong>Bütün yapraklar aynı derinliktedir.</strong> Ağacın yüksekliği $h$ ve anahtar sayısı $n$ olduğunda en seyrek durumda her düğüm iki çocukludur:</p>

\[2^h - 1 \leq n\]

<p>En yoğun durumda ise dallanma üçe yaklaşır. Dolayısıyla yükseklik kabaca</p>

\[\log_3(n) \leq h \leq \log_2(n+1)\]

<p>aralığındadır. Arama, ekleme ve silme işlemleri bu nedenle en kötü durumda $O(\log n)$ sürer.</p>

<h2 id="arama-nasıl-ilerler">Arama nasıl ilerler?</h2>

<p>Her düğümde bir veya iki anahtar karşılaştırılır. Aranan değer küçükse sola, iki anahtarın arasındaysa ortaya, büyükse sağa gidilir. Yani bir seviyede daha çok karşılaştırma yapılabilir; buna karşılık ağaç genellikle daha kısadır.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>İkili arama ağacı</th>
      <th>2-3 ağacı</th>
      <th>Kırmızı-siyah ağaç</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Düğümdeki anahtar</td>
      <td>1</td>
      <td>1 veya 2</td>
      <td>1</td>
    </tr>
    <tr>
      <td>Çocuk sayısı</td>
      <td>En fazla 2</td>
      <td>2 veya 3</td>
      <td>En fazla 2</td>
    </tr>
    <tr>
      <td>Denge garantisi</td>
      <td>Yok</td>
      <td>Tam yükseklik dengesi</td>
      <td>Siyah yükseklik dengesi</td>
    </tr>
    <tr>
      <td>En kötü arama</td>
      <td>$O(n)$</td>
      <td>$O(\log n)$</td>
      <td>$O(\log n)$</td>
    </tr>
    <tr>
      <td>Uygulama yaklaşımı</td>
      <td>Basit</td>
      <td>Çok yollu</td>
      <td>Döndürme ve renk değiştirme</td>
    </tr>
  </tbody>
</table>

<h2 id="ekleme-ve-düğüm-bölme">Ekleme ve düğüm bölme</h2>

<p>Yeni anahtar uygun yaprağa eklenir. Yaprak bir 2-düğümse anahtarlar sıralanır ve düğüm 3-düğüme dönüşür. Zaten iki anahtarı varsa geçici olarak üç anahtarlı bir taşma oluşur. Ortadaki anahtar ebeveyne gönderilir; küçük ve büyük anahtarlar iki ayrı düğüme bölünür. Ebeveyn de taşarsa işlem köke kadar devam eder. Kökün bölünmesi ağacın yüksekliğini yalnızca bir artırır.</p>

<p>Aşağıdaki Python kodu bu bölmenin özünü gösterir:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">split_keys</span><span class="p">(</span><span class="n">keys</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Üç sıralı anahtarı iki düğüm ve bir terfi anahtarına ayırır.</span><span class="sh">"""</span>
    <span class="k">if</span> <span class="nf">len</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">"</span><span class="s">Bölme için tam olarak üç anahtar gerekir</span><span class="sh">"</span><span class="p">)</span>

    <span class="n">left</span> <span class="o">=</span> <span class="p">[</span><span class="n">keys</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
    <span class="n">promoted</span> <span class="o">=</span> <span class="n">keys</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
    <span class="n">right</span> <span class="o">=</span> <span class="p">[</span><span class="n">keys</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
    <span class="k">return</span> <span class="n">left</span><span class="p">,</span> <span class="n">promoted</span><span class="p">,</span> <span class="n">right</span>

<span class="n">keys</span> <span class="o">=</span> <span class="nf">sorted</span><span class="p">([</span><span class="mi">40</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">25</span><span class="p">])</span>
<span class="n">left</span><span class="p">,</span> <span class="n">promoted</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="nf">split_keys</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">promoted</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span>  <span class="c1"># [10] 25 [40]
</span></code></pre></div></div>

<p>Gerçek uygulamada çocuk işaretçileri de uygun yeni düğümlere dağıtılır. Kodun önemli fikri, ortanca anahtarın yukarı çıkarak sıralamayı ve eşit yaprak derinliğini korumasıdır.</p>

<h2 id="kırmızı-siyah-bağlantısı">Kırmızı-siyah bağlantısı</h2>

<p>Bir 2-3 ağacını sıradan ikili bağlantılarla temsil etmek için 3-düğümdeki iki anahtar birbirine <strong>kırmızı bağlantıyla</strong> bağlanabilir. Tek başına duran 2-düğüm ise siyah bir düğüm olur:</p>

<ul>
  <li>Siyah düğüm, bir 2-düğümü temsil eder.</li>
  <li>Siyah düğüm ile kırmızı çocuğu birlikte, bir 3-düğümü temsil eder.</li>
  <li>Kökten yapraklara eşit siyah düğüm sayısı, 2-3 ağacındaki eşit derinliğe karşılık gelir.</li>
</ul>

<p>Özellikle sola yatık kırmızı-siyah ağaçlarda kırmızı bağlantı yalnızca sola eğilir. Ekleme sırasında yapılan sola döndürme, sağa döndürme ve renk değiştirme işlemleri; 2-3 ağacındaki düğüm birleştirme, bölme ve anahtar terfisinin ikili ağaç üzerindeki karşılıklarıdır.</p>

<p>Sonuç olarak 2-3 ağaçları dengeyi kavramsal olarak zarif biçimde garanti ederken kırmızı-siyah ağaçlar aynı fikri tek anahtarlı düğümlerle, pratik programlama ortamlarına daha uygun şekilde uygular. Renkler süs değil; görünmez 3-düğümleri işaretleyen küçük trafik lambalarıdır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="2-3 ağaçları" /><category term="kırmızı-siyah ağaçlar" /><category term="veri yapıları" /><category term="algoritmalar" /><category term="dengeli ağaçlar" /><summary type="html"><![CDATA[İkili arama ağaçları hızlı arama sunar; fakat anahtarlar sıralı geldiğinde ağaç bir çubuk gibi uzayabilir. 2-3 arama ağaçları bu sorunu, her düğümde bir yerine birden fazla anahtar saklayarak çözer. Daha da ilginci, kırmızı-siyah ağaçlar bu çok anahtarlı yapının ikili ağaç kılığına girmiş hâli olarak yorumlanabilir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/2-3-arama-17.png" /><media:content medium="image" url="https://program.sonsuz.us/img/2-3-arama-17.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">A* Arama Algoritması: Sezgilerle En Kısa Yolu Bulmak</title><link href="https://program.sonsuz.us/posts/a-arama-algoritmasi-sezgilerle-en-kisa-yolu-bulmak/" rel="alternate" type="text/html" title="A* Arama Algoritması: Sezgilerle En Kısa Yolu Bulmak" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/a-arama-algoritmasi-sezgilerle-en-kisa-yolu-bulmak</id><content type="html" xml:base="https://program.sonsuz.us/posts/a-arama-algoritmasi-sezgilerle-en-kisa-yolu-bulmak/"><![CDATA[<p>Bir labirentte çıkışı aradığınızı düşünün. Dijkstra algoritması, hedefin hangi yönde olduğunu önemsemeden çevresindeki yolları sabırla inceler. A* ise aynı işi yaparken hedefe doğru ne kadar yaklaştığını tahmin eden bir pusula kullanır. Bu sezgisel yaklaşım, doğru koşullarda en kısa yolu korurken gereksiz düğümleri ziyaret etmeyi azaltabilir.</p>

<p>``</p>

<h2 id="a-algoritmasının-temel-fikri">A* algoritmasının temel fikri</h2>

<p>A*, ağırlıklı bir graf üzerinde başlangıç düğümünden hedef düğüme giden en düşük maliyetli yolu arar. Her düğüm için üç önemli değer kullanır:</p>

\[f(n) = g(n) + h(n)\]

<ul>
  <li>$g(n)$: Başlangıçtan $n$ düğümüne kadar ödenen gerçek maliyettir.</li>
  <li>$h(n)$: $n$ düğümünden hedefe kalan maliyetin tahminidir.</li>
  <li>$f(n)$: Düğüm üzerinden geçen yolun tahmini toplam maliyetidir.</li>
</ul>

<p>Algoritma, sıradaki adım olarak $f(n)$ değeri en küçük olan düğümü seçer. Başka bir deyişle geçmişte ödediği maliyet ile gelecekte ödeyeceğini düşündüğü maliyeti birlikte değerlendirir.</p>

<table>
  <thead>
    <tr>
      <th>Algoritma</th>
      <th style="text-align: right">Kullanılan değer</th>
      <th>Hedef bilgisi</th>
      <th>Genel davranış</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Dijkstra</td>
      <td style="text-align: right">$g(n)$</td>
      <td>Kullanmaz</td>
      <td>Her yöne dengeli yayılır</td>
    </tr>
    <tr>
      <td>Greedy Best-First</td>
      <td style="text-align: right">$h(n)$</td>
      <td>Kullanır</td>
      <td>Hedefe koşar, en kısa yolu garanti etmeyebilir</td>
    </tr>
    <tr>
      <td>A*</td>
      <td style="text-align: right">$g(n)+h(n)$</td>
      <td>Kullanır</td>
      <td>Maliyet ile yön tahminini dengeler</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/a-arama-algoritmasi-25.svg" alt="a-arama-algoritmasi-25" /></p>

<p>Aslında $h(n)=0$ seçilirse A<em>, Dijkstra algoritmasına dönüşür. Dolayısıyla A</em> için Dijkstra’nın hedef bilgisiyle güçlendirilmiş hâli denebilir.</p>

<h2 id="sezgisel-fonksiyon-nasıl-seçilir">Sezgisel fonksiyon nasıl seçilir?</h2>

<p>Kareli ve dört yönde hareket edilen bir haritada Manhattan uzaklığı kullanılabilir:</p>

\[h(n)=\vert x_n-x_h\vert +\vert y_n-y_h\vert\]

<p>Çapraz hareket mümkünse Öklid uzaklığı daha uygun olabilir. A*‘ın en kısa yolu garanti etmesi için sezgisel fonksiyonun gerçek kalan maliyeti aşmaması gerekir. Bu özelliğe <strong>kabul edilebilirlik</strong> denir. Ayrıca tutarlı bir sezgi için her kenarda şu koşul sağlanır:</p>

\[h(n) \leq c(n,m)+h(m)\]

<p>Tahmin çok küçükse algoritma güvenli fakat Dijkstra’ya yakın çalışır. Tahmin gereğinden büyükse daha hızlı görünebilir, ancak en kısa yol garantisi kaybolabilir.</p>

<h2 id="python-ile-a-uygulaması">Python ile A* uygulaması</h2>

<p>Aşağıdaki kod, sözlük biçiminde tanımlanmış ağırlıklı bir graf üzerinde çalışır. Öncelik kuyruğu, tahmini toplam maliyeti en düşük düğümü verimli biçimde seçer.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">heapq</span> <span class="kn">import</span> <span class="n">heappush</span><span class="p">,</span> <span class="n">heappop</span>

<span class="k">def</span> <span class="nf">a_star</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">goal</span><span class="p">,</span> <span class="n">heuristic</span><span class="p">):</span>
    <span class="c1"># Kuyruk elemanları: (f maliyeti, düğüm)
</span>    <span class="n">open_set</span> <span class="o">=</span> <span class="p">[(</span><span class="nf">heuristic</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">goal</span><span class="p">),</span> <span class="n">start</span><span class="p">)]</span>
    <span class="n">came_from</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="n">g_score</span> <span class="o">=</span> <span class="p">{</span><span class="n">start</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>
    <span class="n">visited</span> <span class="o">=</span> <span class="nf">set</span><span class="p">()</span>

    <span class="k">while</span> <span class="n">open_set</span><span class="p">:</span>
        <span class="n">_</span><span class="p">,</span> <span class="n">current</span> <span class="o">=</span> <span class="nf">heappop</span><span class="p">(</span><span class="n">open_set</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current</span> <span class="ow">in</span> <span class="n">visited</span><span class="p">:</span>
            <span class="k">continue</span>
        <span class="k">if</span> <span class="n">current</span> <span class="o">==</span> <span class="n">goal</span><span class="p">:</span>
            <span class="n">path</span> <span class="o">=</span> <span class="p">[</span><span class="n">current</span><span class="p">]</span>
            <span class="k">while</span> <span class="n">current</span> <span class="ow">in</span> <span class="n">came_from</span><span class="p">:</span>
                <span class="n">current</span> <span class="o">=</span> <span class="n">came_from</span><span class="p">[</span><span class="n">current</span><span class="p">]</span>
                <span class="n">path</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">current</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">path</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">g_score</span><span class="p">[</span><span class="n">goal</span><span class="p">]</span>

        <span class="n">visited</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">current</span><span class="p">)</span>

        <span class="k">for</span> <span class="n">neighbor</span><span class="p">,</span> <span class="n">edge_cost</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">[</span><span class="n">current</span><span class="p">]:</span>
            <span class="n">tentative</span> <span class="o">=</span> <span class="n">g_score</span><span class="p">[</span><span class="n">current</span><span class="p">]</span> <span class="o">+</span> <span class="n">edge_cost</span>

            <span class="k">if</span> <span class="n">tentative</span> <span class="o">&lt;</span> <span class="n">g_score</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">neighbor</span><span class="p">,</span> <span class="nf">float</span><span class="p">(</span><span class="sh">"</span><span class="s">inf</span><span class="sh">"</span><span class="p">)):</span>
                <span class="n">came_from</span><span class="p">[</span><span class="n">neighbor</span><span class="p">]</span> <span class="o">=</span> <span class="n">current</span>
                <span class="n">g_score</span><span class="p">[</span><span class="n">neighbor</span><span class="p">]</span> <span class="o">=</span> <span class="n">tentative</span>
                <span class="n">f_score</span> <span class="o">=</span> <span class="n">tentative</span> <span class="o">+</span> <span class="nf">heuristic</span><span class="p">(</span><span class="n">neighbor</span><span class="p">,</span> <span class="n">goal</span><span class="p">)</span>
                <span class="nf">heappush</span><span class="p">(</span><span class="n">open_set</span><span class="p">,</span> <span class="p">(</span><span class="n">f_score</span><span class="p">,</span> <span class="n">neighbor</span><span class="p">))</span>

    <span class="k">return</span> <span class="bp">None</span><span class="p">,</span> <span class="nf">float</span><span class="p">(</span><span class="sh">"</span><span class="s">inf</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div>

<p>Örnek olarak düğümlerin koordinatlarını ve bağlantılarını tanımlayabiliriz:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">graph</span> <span class="o">=</span> <span class="p">{</span>
    <span class="sh">"</span><span class="s">A</span><span class="sh">"</span><span class="p">:</span> <span class="p">[(</span><span class="sh">"</span><span class="s">B</span><span class="sh">"</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">C</span><span class="sh">"</span><span class="p">,</span> <span class="mi">4</span><span class="p">)],</span>
    <span class="sh">"</span><span class="s">B</span><span class="sh">"</span><span class="p">:</span> <span class="p">[(</span><span class="sh">"</span><span class="s">A</span><span class="sh">"</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">D</span><span class="sh">"</span><span class="p">,</span> <span class="mi">3</span><span class="p">)],</span>
    <span class="sh">"</span><span class="s">C</span><span class="sh">"</span><span class="p">:</span> <span class="p">[(</span><span class="sh">"</span><span class="s">A</span><span class="sh">"</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">D</span><span class="sh">"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)],</span>
    <span class="sh">"</span><span class="s">D</span><span class="sh">"</span><span class="p">:</span> <span class="p">[(</span><span class="sh">"</span><span class="s">B</span><span class="sh">"</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">C</span><span class="sh">"</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">E</span><span class="sh">"</span><span class="p">,</span> <span class="mi">2</span><span class="p">)],</span>
    <span class="sh">"</span><span class="s">E</span><span class="sh">"</span><span class="p">:</span> <span class="p">[]</span>
<span class="p">}</span>

<span class="n">coords</span> <span class="o">=</span> <span class="p">{</span>
    <span class="sh">"</span><span class="s">A</span><span class="sh">"</span><span class="p">:</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="sh">"</span><span class="s">B</span><span class="sh">"</span><span class="p">:</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="sh">"</span><span class="s">C</span><span class="sh">"</span><span class="p">:</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span>
    <span class="sh">"</span><span class="s">D</span><span class="sh">"</span><span class="p">:</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="sh">"</span><span class="s">E</span><span class="sh">"</span><span class="p">:</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">def</span> <span class="nf">manhattan</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
    <span class="n">x1</span><span class="p">,</span> <span class="n">y1</span> <span class="o">=</span> <span class="n">coords</span><span class="p">[</span><span class="n">a</span><span class="p">]</span>
    <span class="n">x2</span><span class="p">,</span> <span class="n">y2</span> <span class="o">=</span> <span class="n">coords</span><span class="p">[</span><span class="n">b</span><span class="p">]</span>
    <span class="k">return</span> <span class="nf">abs</span><span class="p">(</span><span class="n">x1</span> <span class="o">-</span> <span class="n">x2</span><span class="p">)</span> <span class="o">+</span> <span class="nf">abs</span><span class="p">(</span><span class="n">y1</span> <span class="o">-</span> <span class="n">y2</span><span class="p">)</span>

<span class="n">path</span><span class="p">,</span> <span class="n">cost</span> <span class="o">=</span> <span class="nf">a_star</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="sh">"</span><span class="s">A</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">E</span><span class="sh">"</span><span class="p">,</span> <span class="n">manhattan</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">cost</span><span class="p">)</span>
</code></pre></div></div>

<p>Bu uygulama yolu <code class="language-plaintext highlighter-rouge">A, B, D, E</code> veya aynı maliyetli uygun bir alternatif olarak döndürebilir. A* özellikle oyun haritaları, robot navigasyonu ve rota planlama sistemlerinde güçlüdür. Yine de hız avantajı otomatik değildir: kötü bir sezgisel fonksiyon, büyük bellek tüketimi veya düzensiz graf yapısı performansı azaltabilir. İyi bir $h(n)$ seçimi ise A*‘ın gerçek süper gücüdür.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="a-star" /><category term="arama-algoritmaları" /><category term="python" /><category term="yapay-zeka" /><category term="graf-teorisi" /><category term="algoritma" /><summary type="html"><![CDATA[Bir labirentte çıkışı aradığınızı düşünün. Dijkstra algoritması, hedefin hangi yönde olduğunu önemsemeden çevresindeki yolları sabırla inceler. A* ise aynı işi yaparken hedefe doğru ne kadar yaklaştığını tahmin eden bir pusula kullanır. Bu sezgisel yaklaşım, doğru koşullarda en kısa yolu korurken gereksiz düğümleri ziyaret etmeyi azaltabilir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/a-arama-algoritmasi-25.png" /><media:content medium="image" url="https://program.sonsuz.us/img/a-arama-algoritmasi-25.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Ağırlıklı Hızlı-Birleşme: Union-Find Ağaçlarını Dengede Tutmak</title><link href="https://program.sonsuz.us/posts/agirlikli-hizli-birlesme-union-find-agaclarini-dengede-tutmak/" rel="alternate" type="text/html" title="Ağırlıklı Hızlı-Birleşme: Union-Find Ağaçlarını Dengede Tutmak" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/agirlikli-hizli-birlesme-union-find-agaclarini-dengede-tutmak</id><content type="html" xml:base="https://program.sonsuz.us/posts/agirlikli-hizli-birlesme-union-find-agaclarini-dengede-tutmak/"><![CDATA[<p>Union-Find, elemanların hangi gruba ait olduğunu hızlıca belirlemek ve iki grubu birleştirmek için kullanılan klasik bir veri yapısıdır. Ancak grupları düşünmeden birleştirirsek ortaya uzun, ince ve performans düşmanı ağaçlar çıkabilir. Ağırlıklı Hızlı-Birleşme (Weighted Quick-Union), küçük ağacı büyük ağacın altına bağlayarak bu sorunu oldukça zarif biçimde çözer.</p>

<p>``</p>

<h2 id="union-find-hangi-problemi-çözer">Union-Find hangi problemi çözer?</h2>

<p>Elimizde başlangıçta birbirinden bağımsız $N$ eleman bulunduğunu düşünelim. Union-Find iki temel işlemi destekler:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">find(p)</code>: <code class="language-plaintext highlighter-rouge">p</code> elemanının bağlı olduğu kümenin kökünü bulur.</li>
  <li><code class="language-plaintext highlighter-rouge">union(p, q)</code>: <code class="language-plaintext highlighter-rouge">p</code> ve <code class="language-plaintext highlighter-rouge">q</code> elemanlarının kümelerini birleştirir.</li>
</ul>

<p>Bu yapı; sosyal ağ bağlantıları, bilgisayar ağları, görüntü işleme, labirent üretimi ve Kruskal’ın minimum kapsayan ağaç algoritması gibi birçok alanda kullanılır.</p>

<p>Quick-Union yaklaşımında her eleman, ebeveyninin indeksini saklar. Bir kökte <code class="language-plaintext highlighter-rouge">parent[i] == i</code> olur. <code class="language-plaintext highlighter-rouge">find</code>, ebeveyn bağlantılarını köke ulaşıncaya kadar takip eder. Ne var ki birleşimler kötü sırayla yapılırsa ağaç bir zincire dönüşebilir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Birleştirme stratejisi</th>
      <th style="text-align: right">Olası ağaç yüksekliği</th>
      <th style="text-align: right">En kötü <code class="language-plaintext highlighter-rouge">find</code></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Quick-Union</td>
      <td>Bir kökü diğerine rastgele bağlar</td>
      <td style="text-align: right">$N-1$</td>
      <td style="text-align: right">$O(N)$</td>
    </tr>
    <tr>
      <td>Weighted Quick-Union</td>
      <td>Küçük ağacı büyük ağaca bağlar</td>
      <td style="text-align: right">$log_2 N$</td>
      <td style="text-align: right">$O(log N)$</td>
    </tr>
    <tr>
      <td>Yol sıkıştırmalı ağırlıklı sürüm</td>
      <td>Düğümleri köke yaklaştırır</td>
      <td style="text-align: right">Çok düşük</td>
      <td style="text-align: right">Yaklaşık $O(α(N))$</td>
    </tr>
  </tbody>
</table>

<p>Buradaki $α(N)$, ters Ackermann fonksiyonudur ve pratik veri boyutlarında neredeyse sabit kabul edilir.</p>

<h2 id="ağırlık-neden-işe-yarar">Ağırlık neden işe yarar?</h2>

<p>Her kök için ağacındaki eleman sayısını tutan bir <code class="language-plaintext highlighter-rouge">size</code> dizisi kullanılır. İki küme birleştirilirken küçük ağacın kökü, büyük ağacın köküne bağlanır. Böylece büyük ağaçtaki düğümlerin derinliği hiç değişmez; yalnızca küçük ağaçtaki düğümlerin derinliği bir artabilir.</p>

<p>Bir düğümün derinliği her arttığında, içinde bulunduğu ağacın büyüklüğü en az iki katına çıkar. Derinlik $h$ ise ağacın en az $2^h$ elemanı olmalıdır:</p>

\[2^h ≤ N \Rightarrow h ≤ log_2 N\]

<p>İşte performans garantisinin kalbi budur. Örneğin $N=1.000.000$ olduğunda zincir biçimli ağaç yaklaşık bir milyon adım gerektirebilirken ağırlıklı ağacın yüksekliği yaklaşık 20 ile sınırlıdır. Algoritmik diyet işe yarıyor: küçük ağaç, büyük ağacın sırtına biniyor!</p>

<h2 id="java-ile-uygulama">Java ile uygulama</h2>

<p>Aşağıdaki sınıf, ebeveynleri <code class="language-plaintext highlighter-rouge">parent</code>, ağaç büyüklüklerini ise <code class="language-plaintext highlighter-rouge">size</code> dizisinde saklar:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">WeightedQuickUnion</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">parent</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">size</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">WeightedQuickUnion</span><span class="o">(</span><span class="kt">int</span> <span class="n">n</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">parent</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">n</span><span class="o">];</span>
        <span class="n">size</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">n</span><span class="o">];</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="n">parent</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">i</span><span class="o">;</span>
            <span class="n">size</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">find</span><span class="o">(</span><span class="kt">int</span> <span class="n">p</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">validate</span><span class="o">(</span><span class="n">p</span><span class="o">);</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">p</span> <span class="o">!=</span> <span class="n">parent</span><span class="o">[</span><span class="n">p</span><span class="o">])</span> <span class="o">{</span>
            <span class="n">p</span> <span class="o">=</span> <span class="n">parent</span><span class="o">[</span><span class="n">p</span><span class="o">];</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">p</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">connected</span><span class="o">(</span><span class="kt">int</span> <span class="n">p</span><span class="o">,</span> <span class="kt">int</span> <span class="n">q</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">return</span> <span class="nf">find</span><span class="o">(</span><span class="n">p</span><span class="o">)</span> <span class="o">==</span> <span class="n">find</span><span class="o">(</span><span class="n">q</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">union</span><span class="o">(</span><span class="kt">int</span> <span class="n">p</span><span class="o">,</span> <span class="kt">int</span> <span class="n">q</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">rootP</span> <span class="o">=</span> <span class="n">find</span><span class="o">(</span><span class="n">p</span><span class="o">);</span>
        <span class="kt">int</span> <span class="n">rootQ</span> <span class="o">=</span> <span class="n">find</span><span class="o">(</span><span class="n">q</span><span class="o">);</span>

        <span class="k">if</span> <span class="o">(</span><span class="n">rootP</span> <span class="o">==</span> <span class="n">rootQ</span><span class="o">)</span> <span class="k">return</span><span class="o">;</span>

        <span class="k">if</span> <span class="o">(</span><span class="n">size</span><span class="o">[</span><span class="n">rootP</span><span class="o">]</span> <span class="o">&lt;</span> <span class="n">size</span><span class="o">[</span><span class="n">rootQ</span><span class="o">])</span> <span class="o">{</span>
            <span class="n">parent</span><span class="o">[</span><span class="n">rootP</span><span class="o">]</span> <span class="o">=</span> <span class="n">rootQ</span><span class="o">;</span>
            <span class="n">size</span><span class="o">[</span><span class="n">rootQ</span><span class="o">]</span> <span class="o">+=</span> <span class="n">size</span><span class="o">[</span><span class="n">rootP</span><span class="o">];</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">parent</span><span class="o">[</span><span class="n">rootQ</span><span class="o">]</span> <span class="o">=</span> <span class="n">rootP</span><span class="o">;</span>
            <span class="n">size</span><span class="o">[</span><span class="n">rootP</span><span class="o">]</span> <span class="o">+=</span> <span class="n">size</span><span class="o">[</span><span class="n">rootQ</span><span class="o">];</span>
        <span class="o">}</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">validate</span><span class="o">(</span><span class="kt">int</span> <span class="n">p</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">p</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">p</span> <span class="o">&gt;=</span> <span class="n">parent</span><span class="o">.</span><span class="na">length</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">();</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">find</code> yalnızca köke yürür. <code class="language-plaintext highlighter-rouge">union</code> önce iki kökü bulur, ardından <code class="language-plaintext highlighter-rouge">size</code> değerlerini karşılaştırarak küçük ağacı büyük ağaca bağlar. Boyut bilgisinin yalnızca köklerde anlamlı olduğuna dikkat edilmelidir.</p>

<h2 id="bir-adım-daha-yol-sıkıştırma">Bir adım daha: yol sıkıştırma</h2>

<p>Performansı daha da artırmak için <code class="language-plaintext highlighter-rouge">find</code> döngüsüne şu satır eklenebilir:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">parent</span><span class="o">[</span><span class="n">p</span><span class="o">]</span> <span class="o">=</span> <span class="n">parent</span><span class="o">[</span><span class="n">parent</span><span class="o">[</span><span class="n">p</span><span class="o">]];</span>
</code></pre></div></div>

<p>Bu işlem, ziyaret edilen düğümü büyük ebeveynine bağlayarak yolu kısaltır. Ağırlıklandırma ağacın baştan fazla uzamasını önlerken yol sıkıştırma mevcut yolları düzleştirir. Birlikte kullanıldıklarında Union-Find işlemleri pratikte sabit zamana yakın çalışır. Sonuç olarak Weighted Quick-Union, küçük bir ek bellek maliyeti karşılığında kontrolsüz ağaç büyümesini engelleyen, basit ama son derece güçlü bir optimizasyondur.</p>

<p><img src="/img/agirlikli-hizli-birlesme-21.svg" alt="agirlikli-hizli-birlesme-21" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="algoritma" /><category term="union-find" /><category term="veri-yapıları" /><category term="java" /><category term="weighted-quick-union" /><summary type="html"><![CDATA[Union-Find, elemanların hangi gruba ait olduğunu hızlıca belirlemek ve iki grubu birleştirmek için kullanılan klasik bir veri yapısıdır. Ancak grupları düşünmeden birleştirirsek ortaya uzun, ince ve performans düşmanı ağaçlar çıkabilir. Ağırlıklı Hızlı-Birleşme (Weighted Quick-Union), küçük ağacı büyük ağacın altına bağlayarak bu sorunu oldukça zarif biçimde çözer.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/agirlikli-hizli-birlesme-21.png" /><media:content medium="image" url="https://program.sonsuz.us/img/agirlikli-hizli-birlesme-21.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Amortize Analiz: Pahalı İşlemleri Uzun Vadede Ucuzlatmak</title><link href="https://program.sonsuz.us/posts/amortize-analiz-pahali-islemleri-uzun-vadede-ucuzlatmak/" rel="alternate" type="text/html" title="Amortize Analiz: Pahalı İşlemleri Uzun Vadede Ucuzlatmak" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/amortize-analiz-pahali-islemleri-uzun-vadede-ucuzlatmak</id><content type="html" xml:base="https://program.sonsuz.us/posts/amortize-analiz-pahali-islemleri-uzun-vadede-ucuzlatmak/"><![CDATA[<p>Bir algoritmadaki tek bir işlemin pahalı olması, algoritmanın genel olarak verimsiz olduğu anlamına gelmez. Bazen nadiren gerçekleşen maliyetli işlemler, çok sayıdaki ucuz işlem arasında kaybolur. Amortize analiz, tam da bu tabloya bakarak bir işlem dizisinin uzun vadeli ortalama maliyetini hesaplamamızı sağlar.</p>

<p>``</p>

<h2 id="amortize-analiz-nedir">Amortize analiz nedir?</h2>

<p>Amortize analiz, bir işlemin olasılıksal ortalamasını değil, <strong>en kötü durumda oluşabilecek işlem dizisinin ortalama maliyetini</strong> inceler. Bu nedenle ortalama durum analizinden farklıdır: Kullanıcı davranışı veya rastgele veri dağılımı hakkında varsayım yapmaz.</p>

<p>$n$ işlemden oluşan bir dizinin toplam maliyeti $T(n)$ ise işlem başına amortize maliyet şöyle hesaplanır:</p>

\[A(n) = \frac{T(n)}{n}\]

<p>Örneğin toplam maliyet $T(n)=3n+10$ ise amortize maliyet:</p>

\[A(n)=\frac{3n+10}{n}=3+\frac{10}{n}=O(1)\]

<p>Burada bazı işlemler tek başına pahalı olsa bile uzun vadede her işlem sabit maliyetli kabul edilebilir.</p>

<table>
  <thead>
    <tr>
      <th>Analiz türü</th>
      <th>İncelenen durum</th>
      <th style="text-align: right">Varsayım gerekir mi?</th>
      <th style="text-align: right">Sonuç örneği</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>En iyi durum</td>
      <td>En avantajlı girdi</td>
      <td style="text-align: right">Hayır</td>
      <td style="text-align: right">$\Omega(1)$</td>
    </tr>
    <tr>
      <td>En kötü durum</td>
      <td>En maliyetli tek işlem</td>
      <td style="text-align: right">Hayır</td>
      <td style="text-align: right">$O(n)$</td>
    </tr>
    <tr>
      <td>Ortalama durum</td>
      <td>Olası girdilerin ortalaması</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Beklenen maliyet</td>
    </tr>
    <tr>
      <td>Amortize analiz</td>
      <td>En kötü işlem dizisinin ortalaması</td>
      <td style="text-align: right">Hayır</td>
      <td style="text-align: right">İşlem başına $O(1)$</td>
    </tr>
  </tbody>
</table>

<h2 id="klasik-örnek-dinamik-dizi">Klasik örnek: Dinamik dizi</h2>

<p>Dinamik bir dizinin kapasitesi dolduğunda daha büyük bir alan ayrılır ve eski elemanlar yeni alana kopyalanır. Normal bir ekleme $O(1)$ sürerken yeniden boyutlandırma işlemi $O(n)$ maliyetli olabilir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">DynamicArray</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">capacity</span> <span class="o">=</span> <span class="mi">1</span>
        <span class="n">self</span><span class="p">.</span><span class="n">size</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">self</span><span class="p">.</span><span class="n">data</span> <span class="o">=</span> <span class="p">[</span><span class="bp">None</span><span class="p">]</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">capacity</span>

    <span class="k">def</span> <span class="nf">append</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">self</span><span class="p">.</span><span class="n">size</span> <span class="o">==</span> <span class="n">self</span><span class="p">.</span><span class="n">capacity</span><span class="p">:</span>
            <span class="n">self</span><span class="p">.</span><span class="nf">_resize</span><span class="p">()</span>

        <span class="n">self</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">size</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
        <span class="n">self</span><span class="p">.</span><span class="n">size</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="k">def</span> <span class="nf">_resize</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">capacity</span> <span class="o">*=</span> <span class="mi">2</span>
        <span class="n">new_data</span> <span class="o">=</span> <span class="p">[</span><span class="bp">None</span><span class="p">]</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">capacity</span>

        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">size</span><span class="p">):</span>
            <span class="n">new_data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>

        <span class="n">self</span><span class="p">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">new_data</span>
</code></pre></div></div>

<p>Bu kodda <code class="language-plaintext highlighter-rouge">_resize</code>, mevcut elemanları kopyalayarak kapasiteyi iki katına çıkarır. Boyutlandırmalar $1,2,4,8,\ldots$ elemanda gerçekleşir. $n$ ekleme boyunca yapılan toplam kopyalama sayısı:</p>

\[1+2+4+\cdots+\frac{n}{2}&lt;n\]

<p>Normal eklemelerin maliyeti de $n$ olduğundan toplam maliyet $2n$ civarındadır. Böylece işlem başına maliyet:</p>

\[\frac{2n}{n}=O(1)\]

<p>Tek bir ekleme $O(n)$ sürebilir; ancak <code class="language-plaintext highlighter-rouge">append</code> işleminin amortize maliyeti $O(1)$ olur. Pahalı taşınma masrafı, önceki ucuz eklemelere dağıtılmıştır.</p>

<h2 id="üç-temel-amortize-analiz-yöntemi">Üç temel amortize analiz yöntemi</h2>

<h3 id="1-toplam-maliyet-yöntemi">1. Toplam maliyet yöntemi</h3>

<p>Tüm işlem dizisinin gerçek maliyeti hesaplanır ve işlem sayısına bölünür. Dinamik dizi örneğinde kullandığımız yaklaşım budur.</p>

<h3 id="2-muhasebe-yöntemi">2. Muhasebe yöntemi</h3>

<p>Ucuz işlemlerden gerçek maliyetlerinden biraz daha fazla ücret alınır. Aradaki kredi, gelecekteki pahalı işlemleri karşılamak üzere saklanır. Bir eklemenin gerçek maliyeti $1$ olsa da ona $3$ kredi biçtiğimizi düşünebiliriz. Fazladan kalan krediler yeniden boyutlandırmayı öder; algoritma adeta kendi kumbarasını taşır.</p>

<h3 id="3-potansiyel-yöntemi">3. Potansiyel yöntemi</h3>

<p>Veri yapısında biriken gelecekteki işi matematiksel bir potansiyel fonksiyonuyla gösteririz. Amortize maliyet:</p>

\[\hat{c_i}=c_i+\Phi(D_i)-\Phi(D_{i-1})\]

<p>Burada $c_i$ gerçek maliyet, $\Phi(D_i)$ ise işlemden sonraki potansiyeldir. Potansiyel artıyorsa geleceğe kredi bırakılır; azalıyorsa biriktirilen kredi pahalı işlemi karşılar.</p>

<table>
  <thead>
    <tr>
      <th>Yöntem</th>
      <th>Temel fikir</th>
      <th>Kullanışlı olduğu durum</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Toplam</td>
      <td>Bütün maliyeti işlemlere böl</td>
      <td>Düzenli işlem dizileri</td>
    </tr>
    <tr>
      <td>Muhasebe</td>
      <td>Fazla ücretle kredi biriktir</td>
      <td>Sezgisel açıklamalar</td>
    </tr>
    <tr>
      <td>Potansiyel</td>
      <td>Veri yapısındaki enerjiyi ölç</td>
      <td>Karmaşık yapılar ve ispatlar</td>
    </tr>
  </tbody>
</table>

<p>Amortize analiz, tek bir kötü ana bakıp paniğe kapılmak yerine filmin tamamını izler. Dinamik diziler, hash tabloları, yığıt işlemleri ve birleşim-bulma yapıları bu yöntemle daha doğru değerlendirilir. Kısacası soru yalnızca “Bu işlem ne kadar pahalı?” değil, “Bu maliyet uzun bir yolculuk boyunca kaç işleme paylaşılıyor?” olmalıdır.</p>

<p><img src="/img/amortize-analiz-pahali-93.svg" alt="amortize-analiz-pahali-93" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="amortize analiz" /><category term="algoritma" /><category term="veri yapıları" /><category term="zaman karmaşıklığı" /><category term="dinamik dizi" /><summary type="html"><![CDATA[Bir algoritmadaki tek bir işlemin pahalı olması, algoritmanın genel olarak verimsiz olduğu anlamına gelmez. Bazen nadiren gerçekleşen maliyetli işlemler, çok sayıdaki ucuz işlem arasında kaybolur. Amortize analiz, tam da bu tabloya bakarak bir işlem dizisinin uzun vadeli ortalama maliyetini hesaplamamızı sağlar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/amortize-analiz-pahali-93.png" /><media:content medium="image" url="https://program.sonsuz.us/img/amortize-analiz-pahali-93.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Aynı Seçim, Farklı Kazanan: Borda ve Condorcet Yöntemleri</title><link href="https://program.sonsuz.us/posts/ayni-secim-farkli-kazanan-borda-ve-condorcet-yontemleri/" rel="alternate" type="text/html" title="Aynı Seçim, Farklı Kazanan: Borda ve Condorcet Yöntemleri" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/ayni-secim-farkli-kazanan-borda-ve-condorcet-yontemleri</id><content type="html" xml:base="https://program.sonsuz.us/posts/ayni-secim-farkli-kazanan-borda-ve-condorcet-yontemleri/"><![CDATA[<p>Bir seçimde en çok oyu alan adayın kazanacağını düşünmek doğaldır. Ancak seçmenler yalnızca tek aday belirtmek yerine adayları tercih sırasına koyduğunda işler değişir. Oyları nasıl puanladığımız veya adayları nasıl karşılaştırdığımız, aynı tercihlerden farklı kazananlar çıkarabilir. Borda ve Condorcet yöntemleri, bu şaşırtıcı durumun en güzel örneklerindendir.</p>

<p>``</p>

<h2 id="tercihli-oylamanın-temel-fikri">Tercihli oylamanın temel fikri</h2>

<p>Üç adayımız olsun: Ada, Bora ve Ceren. Seçmenlerden adayları en beğendiklerinden en az beğendiklerine doğru sıralamalarını isteyelim. Sonuçlar şöyle olsun:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: right">Seçmen sayısı</th>
      <th>1. tercih</th>
      <th>2. tercih</th>
      <th>3. tercih</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">4</td>
      <td>Ada</td>
      <td>Bora</td>
      <td>Ceren</td>
    </tr>
    <tr>
      <td style="text-align: right">3</td>
      <td>Bora</td>
      <td>Ceren</td>
      <td>Ada</td>
    </tr>
    <tr>
      <td style="text-align: right">2</td>
      <td>Ceren</td>
      <td>Bora</td>
      <td>Ada</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/ayni-secim-farkli-60.svg" alt="ayni-secim-farkli-60" /></p>

<p>Burada yalnızca birinci tercihlere bakarsak Ada 4, Bora 3, Ceren 2 oy alır. Basit çoğulluk yöntemi Ada’yı kazanan ilan eder. Fakat sıralamanın geri kalanını da hesaba katarsak sonuç değişebilir.</p>

<h2 id="borda-sayımı-her-sıraya-puan">Borda sayımı: Her sıraya puan</h2>

<p>Borda yönteminde adaylar bulundukları sıraya göre puan kazanır. $m$ aday varsa birinci sıraya $m-1$, ikinci sıraya $m-2$ ve son sıraya $0$ puan verilebilir. Üç aday için puanlar sırasıyla $2$, $1$ ve $0$ olur.</p>

<p>Bir adayın toplam Borda puanı şu şekilde ifade edilir:</p>

\[B(a)=\sum_{i=1}^{n} p_i(a)\]

<p>Burada $p_i(a)$, $i$ numaralı seçmenin $a$ adayına verdiği sıra puanıdır. Örneğimizde puanlar şöyledir:</p>

<table>
  <thead>
    <tr>
      <th>Aday</th>
      <th>Puan hesabı</th>
      <th style="text-align: right">Toplam</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Ada</td>
      <td>$4\times2+3\times0+2\times0$</td>
      <td style="text-align: right">8</td>
    </tr>
    <tr>
      <td>Bora</td>
      <td>$4\times1+3\times2+2\times1$</td>
      <td style="text-align: right">12</td>
    </tr>
    <tr>
      <td>Ceren</td>
      <td>$4\times0+3\times1+2\times2$</td>
      <td style="text-align: right">7</td>
    </tr>
  </tbody>
</table>

<p>Borda kazananı Bora’dır. Ada daha fazla seçmenin ilk tercihi olmasına rağmen birçok seçmen tarafından son sıraya konmuştur. Bora ise geniş bir uzlaşma sağlamıştır. Borda, güçlü sevgiyi ödüllendirirken genel kabulü de önemser.</p>

<h2 id="condorcet-bire-bir-düello">Condorcet: Bire bir düello</h2>

<p>Condorcet yaklaşımı puan toplamak yerine adayları ikili karşılaştırır. Bir aday, diğer bütün adayları bire bir seçimlerde yeniyorsa <strong>Condorcet kazananı</strong> olur.</p>

<p>Örneğin Bora ile Ada karşılaştırıldığında ilk gruptaki 4 seçmen Ada’yı, diğer 5 seçmen Bora’yı üstün tutar. Bora, Ada’yı $5$–$4$ yener. Bora ile Ceren karşılaşmasında ise ilk iki grup, yani 7 seçmen Bora’yı Ceren’in önüne koyar. Böylece Bora yine kazanır ve Condorcet kazananı olur.</p>

<table>
  <thead>
    <tr>
      <th>Yöntem</th>
      <th>Neye odaklanır?</th>
      <th>Bu örnekte kazanan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Basit çoğulluk</td>
      <td>Birinci tercihler</td>
      <td>Ada</td>
    </tr>
    <tr>
      <td>Borda</td>
      <td>Tüm sıraların puanı</td>
      <td>Bora</td>
    </tr>
    <tr>
      <td>Condorcet</td>
      <td>İkili karşılaşmalar</td>
      <td>Bora</td>
    </tr>
  </tbody>
</table>

<p>Borda ve Condorcet her zaman aynı sonucu vermez. Ayrıca Condorcet kazananı bulunmayabilir: Ada Bora’yı, Bora Ceren’i, Ceren de Ada’yı yenebilir. Bu duruma <strong>Condorcet döngüsü</strong> denir; tercihler taş-kâğıt-makas oyununa dönüşür.</p>

<h2 id="küçük-bir-python-uygulaması">Küçük bir Python uygulaması</h2>

<p>Aşağıdaki kod, sıralı oyların Borda puanlarını hesaplar:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span>

<span class="n">oylar</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="p">[</span><span class="sh">"</span><span class="s">Ada</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">Bora</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">Ceren</span><span class="sh">"</span><span class="p">]),</span>
    <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="p">[</span><span class="sh">"</span><span class="s">Bora</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">Ceren</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">Ada</span><span class="sh">"</span><span class="p">]),</span>
    <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="sh">"</span><span class="s">Ceren</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">Bora</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">Ada</span><span class="sh">"</span><span class="p">]),</span>
<span class="p">]</span>

<span class="n">puanlar</span> <span class="o">=</span> <span class="nf">defaultdict</span><span class="p">(</span><span class="nb">int</span><span class="p">)</span>
<span class="n">aday_sayisi</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">oylar</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span>

<span class="k">for</span> <span class="n">secmen</span><span class="p">,</span> <span class="n">siralama</span> <span class="ow">in</span> <span class="n">oylar</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">sira</span><span class="p">,</span> <span class="n">aday</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">siralama</span><span class="p">):</span>
        <span class="n">puanlar</span><span class="p">[</span><span class="n">aday</span><span class="p">]</span> <span class="o">+=</span> <span class="n">secmen</span> <span class="o">*</span> <span class="p">(</span><span class="n">aday_sayisi</span> <span class="o">-</span> <span class="n">sira</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">dict</span><span class="p">(</span><span class="n">puanlar</span><span class="p">))</span>
<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Kazanan:</span><span class="sh">"</span><span class="p">,</span> <span class="nf">max</span><span class="p">(</span><span class="n">puanlar</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">puanlar</span><span class="p">.</span><span class="n">get</span><span class="p">))</span>
</code></pre></div></div>

<p>Döngü, her adayın sıra puanını o tercihi paylaşan seçmen sayısıyla çarpar. Çıktıda Bora 12 puanla kazanır.</p>

<p>Sonuç olarak seçim yöntemi tarafsız bir ayrıntı değil, sonucun parçasıdır. Basit çoğulluk güçlü birinci tercihleri, Borda genel memnuniyeti, Condorcet ise bire bir üstünlüğü ölçer. Bu nedenle “Kim kazandı?” sorusundan önce “Oyları hangi kuralla saydık?” diye sormak gerekir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="oylama" /><category term="borda" /><category term="condorcet" /><category term="sosyal-seçim" /><category term="algoritma" /><category term="matematik" /><summary type="html"><![CDATA[Bir seçimde en çok oyu alan adayın kazanacağını düşünmek doğaldır. Ancak seçmenler yalnızca tek aday belirtmek yerine adayları tercih sırasına koyduğunda işler değişir. Oyları nasıl puanladığımız veya adayları nasıl karşılaştırdığımız, aynı tercihlerden farklı kazananlar çıkarabilir. Borda ve Condorcet yöntemleri, bu şaşırtıcı durumun en güzel örneklerindendir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/ayni-secim-farkli-60.png" /><media:content medium="image" url="https://program.sonsuz.us/img/ayni-secim-farkli-60.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Bellman-Ford ile Döviz Arbitrajı: Negatif Döngülerden Kâr Fırsatlarına</title><link href="https://program.sonsuz.us/posts/bellman-ford-ile-doviz-arbitraji-negatif-dongulerden-kar-firsatlarina/" rel="alternate" type="text/html" title="Bellman-Ford ile Döviz Arbitrajı: Negatif Döngülerden Kâr Fırsatlarına" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/bellman-ford-ile-doviz-arbitraji-negatif-dongulerden-kar-firsatlarina</id><content type="html" xml:base="https://program.sonsuz.us/posts/bellman-ford-ile-doviz-arbitraji-negatif-dongulerden-kar-firsatlarina/"><![CDATA[<p>Bir para birimini diğerine, onu da başka bir para birimine çevirip başlangıçtaki paranızdan daha fazlasıyla geri dönebilir misiniz? Teorik olarak evet! <strong>Arbitraj</strong>, farklı döviz kurları arasındaki tutarsızlıklardan risksiz kâr elde etme fikridir. Bu finans problemini bir graf problemine dönüştürdüğümüzde ise sahneye Bellman-Ford algoritması ve onun meşhur negatif döngü tespiti çıkar.</p>

<p>``</p>

<h2 id="döviz-piyasasını-graf-olarak-modellemek">Döviz piyasasını graf olarak modellemek</h2>

<p>Her para birimini bir <strong>düğüm</strong>, mümkün olan her döviz dönüşümünü de yönlü bir <strong>kenar</strong> olarak düşünebiliriz. Örneğin USD’den EUR’ya geçiş ayrı, EUR’dan USD’ye geçiş ayrı bir kenardır; çünkü bu iki kur birbirinin tam tersi olmak zorunda değildir.</p>

<p>Elimizde şu dönüşüm zinciri olsun:</p>

\[USD \rightarrow EUR \rightarrow GBP \rightarrow USD\]

<p>Başlangıçta 1 USD varsa zincirin sonunda elde edeceğimiz miktar:</p>

\[1 \times r_{USD,EUR} \times r_{EUR,GBP} \times r_{GBP,USD}\]

<p>Kurların çarpımı 1’den büyükse başlangıçtakinden daha fazla USD elde ederiz:</p>

\[r_1 \times r_2 \times \cdots \times r_n &gt; 1\]

<p>Ancak graf algoritmaları toplama işlemleriyle çalışmayı sever. Çarpımları toplama çevirmek için logaritmadan yararlanırız:</p>

\[w(u,v) = -\ln(r_{u,v})\]

<p>Negatif logaritma uygulandığında kârlılık koşulu şu hâle gelir:</p>

\[\sum w_i &lt; 0\]

<p>Yani arbitraj fırsatı, dönüştürülmüş graf üzerindeki <strong>negatif ağırlıklı bir döngüdür</strong>.</p>

<table>
  <thead>
    <tr>
      <th>Finans kavramı</th>
      <th>Graf karşılığı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Para birimi</td>
      <td>Düğüm</td>
    </tr>
    <tr>
      <td>Döviz dönüşümü</td>
      <td>Yönlü kenar</td>
    </tr>
    <tr>
      <td>Döviz kuru</td>
      <td>Kenar ağırlığının kaynağı</td>
    </tr>
    <tr>
      <td>Kârlı dönüşüm zinciri</td>
      <td>Negatif döngü</td>
    </tr>
    <tr>
      <td>Komisyon</td>
      <td>Efektif kurda azalma</td>
    </tr>
  </tbody>
</table>

<h2 id="neden-bellman-ford">Neden Bellman-Ford?</h2>

<p>Dijkstra algoritması negatif kenar ağırlıklarıyla güvenilir biçimde çalışmaz. Bellman-Ford ise negatif ağırlıkları destekler ve ulaşılabilir negatif döngüleri belirleyebilir.</p>

<p>Algoritma, $V$ düğümlü bir grafta bütün kenarları $V-1$ kez gevşetir. Bu işlemlerden sonra herhangi bir mesafe hâlâ küçültülebiliyorsa negatif döngü vardır. Zaman karmaşıklığı $O(VE)$ seviyesindedir; para birimi sayısının genellikle sınırlı olması nedeniyle pratik bir seçimdir.</p>

<table>
  <thead>
    <tr>
      <th>Algoritma</th>
      <th style="text-align: right">Negatif kenar</th>
      <th style="text-align: right">Negatif döngü tespiti</th>
      <th style="text-align: right">Karmaşıklık</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Dijkstra</td>
      <td style="text-align: right">Hayır</td>
      <td style="text-align: right">Hayır</td>
      <td style="text-align: right">$O(E\log V)$</td>
    </tr>
    <tr>
      <td>Bellman-Ford</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">$O(VE)$</td>
    </tr>
    <tr>
      <td>Floyd-Warshall</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">$O(V^3)$</td>
    </tr>
  </tbody>
</table>

<h2 id="python-ile-arbitraj-tespiti">Python ile arbitraj tespiti</h2>

<p>Aşağıdaki fonksiyon kurları negatif logaritmik ağırlıklara dönüştürür. Bütün düğümlerin başlangıç mesafesini sıfır yapmak, bağlantısız bileşenlerdeki döngüleri de aramamızı sağlar.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">math</span>


<span class="k">def</span> <span class="nf">find_arbitrage</span><span class="p">(</span><span class="n">currencies</span><span class="p">,</span> <span class="n">rates</span><span class="p">):</span>
    <span class="n">n</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">currencies</span><span class="p">)</span>
    <span class="n">edges</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">for</span> <span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="n">rate</span> <span class="ow">in</span> <span class="n">rates</span><span class="p">:</span>
        <span class="n">weight</span> <span class="o">=</span> <span class="o">-</span><span class="n">math</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="n">rate</span><span class="p">)</span>
        <span class="n">edges</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="n">weight</span><span class="p">))</span>

    <span class="n">distance</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span>
    <span class="n">parent</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span>
    <span class="n">changed</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>

    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="n">changed</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
        <span class="k">for</span> <span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="n">weight</span> <span class="ow">in</span> <span class="n">edges</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">distance</span><span class="p">[</span><span class="n">target</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">distance</span><span class="p">[</span><span class="n">source</span><span class="p">]</span> <span class="o">+</span> <span class="n">weight</span><span class="p">:</span>
                <span class="n">distance</span><span class="p">[</span><span class="n">target</span><span class="p">]</span> <span class="o">=</span> <span class="n">distance</span><span class="p">[</span><span class="n">source</span><span class="p">]</span> <span class="o">+</span> <span class="n">weight</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">target</span><span class="p">]</span> <span class="o">=</span> <span class="n">source</span>
                <span class="n">changed</span> <span class="o">=</span> <span class="n">target</span>

    <span class="k">if</span> <span class="n">changed</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">None</span>

    <span class="c1"># Düğümü döngünün içine taşır.
</span>    <span class="n">vertex</span> <span class="o">=</span> <span class="n">changed</span>
    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="n">vertex</span> <span class="o">=</span> <span class="n">parent</span><span class="p">[</span><span class="n">vertex</span><span class="p">]</span>

    <span class="n">cycle</span> <span class="o">=</span> <span class="p">[</span><span class="n">vertex</span><span class="p">]</span>
    <span class="n">current</span> <span class="o">=</span> <span class="n">parent</span><span class="p">[</span><span class="n">vertex</span><span class="p">]</span>
    <span class="k">while</span> <span class="n">current</span> <span class="o">!=</span> <span class="n">vertex</span><span class="p">:</span>
        <span class="n">cycle</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">current</span><span class="p">)</span>
        <span class="n">current</span> <span class="o">=</span> <span class="n">parent</span><span class="p">[</span><span class="n">current</span><span class="p">]</span>

    <span class="n">cycle</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">vertex</span><span class="p">)</span>
    <span class="n">cycle</span><span class="p">.</span><span class="nf">reverse</span><span class="p">()</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">currencies</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">cycle</span><span class="p">]</span>


<span class="n">currencies</span> <span class="o">=</span> <span class="p">[</span><span class="sh">"</span><span class="s">USD</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">EUR</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">GBP</span><span class="sh">"</span><span class="p">]</span>
<span class="n">rates</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.92</span><span class="p">),</span>
    <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mf">0.87</span><span class="p">),</span>
    <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">1.27</span><span class="p">),</span>
<span class="p">]</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">find_arbitrage</span><span class="p">(</span><span class="n">currencies</span><span class="p">,</span> <span class="n">rates</span><span class="p">))</span>
</code></pre></div></div>

<p>Fonksiyon <code class="language-plaintext highlighter-rouge">None</code> döndürürse negatif döngü bulunamamıştır. Bir liste döndürürse listedeki para birimleri olası arbitraj rotasını gösterir. Örnekte kurların çarpımı yaklaşık $0.92 \times 0.87 \times 1.27 = 1.016$ olduğundan teorik olarak yüzde 1,6 civarında brüt kazanç vardır.</p>

<h2 id="gerçek-hayattaki-küçük-ama-önemli-canavarlar">Gerçek hayattaki küçük ama önemli canavarlar</h2>

<p>Teorik arbitraj ile uygulanabilir arbitraj aynı şey değildir. Alış-satış farkı, işlem komisyonu, ağ gecikmesi, likidite ve kur değişimleri kârı yok edebilir. Komisyon oranı $c$ ise dönüşümde çıplak kur yerine efektif kur kullanılmalıdır:</p>

\[r_{efektif} = r(1-c)\]

<p>Ayrıca kayan nokta hataları yüzünden karşılaştırmalara küçük bir tolerans eklemek faydalıdır. Bellman-Ford fırsatı matematiksel olarak bulur; fırsatın gerçekten cüzdanınıza ulaşması ise veri kalitesine ve işlem hızına bağlıdır. Kısacası algoritma hazine haritasını çizer, fakat hazinenin yerinde duracağını garanti etmez!</p>

<p><img src="/img/bellman-ford-ile-81.svg" alt="bellman-ford-ile-81" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="bellman-ford" /><category term="algoritma" /><category term="graf teorisi" /><category term="arbitraj" /><category term="python" /><category term="finans" /><summary type="html"><![CDATA[Bir para birimini diğerine, onu da başka bir para birimine çevirip başlangıçtaki paranızdan daha fazlasıyla geri dönebilir misiniz? Teorik olarak evet! Arbitraj, farklı döviz kurları arasındaki tutarsızlıklardan risksiz kâr elde etme fikridir. Bu finans problemini bir graf problemine dönüştürdüğümüzde ise sahneye Bellman-Ford algoritması ve onun meşhur negatif döngü tespiti çıkar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/bellman-ford-ile-81.png" /><media:content medium="image" url="https://program.sonsuz.us/img/bellman-ford-ile-81.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Boyer-Moore Algoritması: Metni Sondan Başlayarak Akıllıca Aramak</title><link href="https://program.sonsuz.us/posts/boyer-moore-algoritmasi-metni-sondan-baslayarak-akillica-aramak/" rel="alternate" type="text/html" title="Boyer-Moore Algoritması: Metni Sondan Başlayarak Akıllıca Aramak" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/boyer-moore-algoritmasi-metni-sondan-baslayarak-akillica-aramak</id><content type="html" xml:base="https://program.sonsuz.us/posts/boyer-moore-algoritmasi-metni-sondan-baslayarak-akillica-aramak/"><![CDATA[<p>Bir metin içinde kelime ararken her karakteri sırayla karşılaştırmak güvenilir olsa da her zaman akıllıca değildir. Boyer-Moore algoritması, kalıbı sağdan sola inceleyip uyuşmazlıklardan bilgi çıkararak gereksiz karşılaştırmaları atlar. Kısacası yalnızca “eşleşmedi” demez; “buradan birkaç adım öteye sıçrayabilirim” diyerek aramayı hızlandırır.</p>

<p>``</p>

<h2 id="temel-fikir-neden-sondan-başlıyoruz">Temel fikir: Neden sondan başlıyoruz?</h2>

<p>Elimizde uzunluğu $n$ olan bir metin ve uzunluğu $m$ olan bir kalıp bulunsun. Naif arama, kalıbı metindeki her olası konuma yerleştirir ve karakterleri soldan sağa karşılaştırır. En kötü durumda yaklaşık $O(nm)$ işlem yapılabilir.</p>

<p>Boyer-Moore ise kalıbı metnin üzerine yerleştirir, fakat karşılaştırmaya kalıbın son karakterinden başlar. Sağ tarafta oluşan bir uyuşmazlık, kalıbın tamamını birkaç konum birden kaydırmaya izin verebilir. Bu davranış özellikle kalıp uzadıkça ve alfabe genişledikçe etkili olur.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Naif arama</th>
      <th>Boyer-Moore</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tarama yönü</td>
      <td>Soldan sağa</td>
      <td>Kalıp içinde sağdan sola</td>
    </tr>
    <tr>
      <td>Uyuşmazlık sonrası</td>
      <td>Genellikle bir adım kayar</td>
      <td>Birden fazla adım sıçrayabilir</td>
    </tr>
    <tr>
      <td>Ön işleme</td>
      <td>Gerekmez</td>
      <td>Kaydırma tabloları hazırlanır</td>
    </tr>
    <tr>
      <td>Pratik performans</td>
      <td>Küçük girdilerde yeterli</td>
      <td>Uzun metinlerde oldukça hızlı</td>
    </tr>
  </tbody>
</table>

<h2 id="kötü-karakter-sezgisi">Kötü karakter sezgisi</h2>

<p>Algoritmanın en anlaşılır kuralı <strong>kötü karakter kuralıdır</strong>. Kalıbın $j$ indeksindeki karakter ile metindeki karakter uyuşmazsa, karşılaşılan metin karakterinin kalıp içindeki en sağ konumuna bakılır.</p>

<p>Bu konumu $last(c)$ ile gösterirsek kaydırma miktarı şöyle hesaplanabilir:</p>

\[s = max(1, j - last(c))\]

<p>Karakter kalıpta hiç yoksa $last(c)=-1$ kabul edilir. Böylece kalıp, uyuşmayan karakteri tamamen geride bırakacak kadar kaydırılabilir. Örneğin <code class="language-plaintext highlighter-rouge">KOD</code> kalıbını ararken karşılaştırılan metin karakteri <code class="language-plaintext highlighter-rouge">X</code> ise ve <code class="language-plaintext highlighter-rouge">X</code> kalıpta bulunmuyorsa tek tek ilerlemek yerine kalıp birkaç adım ileri taşınır.</p>

<p>Boyer-Moore’un tam sürümünde bir de <strong>iyi sonek kuralı</strong> vardır. Kalıbın sonunda eşleşmiş bir bölüm bulunup daha solda uyuşmazlık yaşanırsa algoritma, eşleşen sonekin kalıptaki başka bir tekrarını veya uygun bir önekini arar. İki kuralın önerdiği kaydırmalardan büyük olanı seçilir. Bu ek mekanizma güçlüdür; ancak kötü karakter kuralı bile tek başına pratik bir hızlanma sağlar.</p>

<h2 id="python-ile-basitleştirilmiş-uygulama">Python ile basitleştirilmiş uygulama</h2>

<p>Aşağıdaki kod yalnızca kötü karakter sezgisini kullanır. Ön işleme aşaması, kalıptaki her karakterin en sağ indeksini bir sözlükte saklar:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">boyer_moore_ara</span><span class="p">(</span><span class="n">metin</span><span class="p">,</span> <span class="n">kalip</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">kalip</span><span class="p">:</span>
        <span class="k">return</span> <span class="mi">0</span>

    <span class="c1"># Her karakterin kalıptaki en sağ konumunu hazırlar.
</span>    <span class="n">son_konum</span> <span class="o">=</span> <span class="p">{</span><span class="n">karakter</span><span class="p">:</span> <span class="n">i</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">karakter</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">kalip</span><span class="p">)}</span>
    <span class="n">n</span><span class="p">,</span> <span class="n">m</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">metin</span><span class="p">),</span> <span class="nf">len</span><span class="p">(</span><span class="n">kalip</span><span class="p">)</span>
    <span class="n">kayma</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">while</span> <span class="n">kayma</span> <span class="o">&lt;=</span> <span class="n">n</span> <span class="o">-</span> <span class="n">m</span><span class="p">:</span>
        <span class="n">j</span> <span class="o">=</span> <span class="n">m</span> <span class="o">-</span> <span class="mi">1</span>

        <span class="c1"># Karakterleri kalıbın sonundan başına doğru karşılaştırır.
</span>        <span class="k">while</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">kalip</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="n">metin</span><span class="p">[</span><span class="n">kayma</span> <span class="o">+</span> <span class="n">j</span><span class="p">]:</span>
            <span class="n">j</span> <span class="o">-=</span> <span class="mi">1</span>

        <span class="k">if</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">kayma</span>

        <span class="n">kotu_karakter</span> <span class="o">=</span> <span class="n">metin</span><span class="p">[</span><span class="n">kayma</span> <span class="o">+</span> <span class="n">j</span><span class="p">]</span>
        <span class="n">kayma</span> <span class="o">+=</span> <span class="nf">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">j</span> <span class="o">-</span> <span class="n">son_konum</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">kotu_karakter</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">))</span>

    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span>

<span class="n">metin</span> <span class="o">=</span> <span class="sh">"</span><span class="s">ALGORITMALARLA METIN ARAMA</span><span class="sh">"</span>
<span class="nf">print</span><span class="p">(</span><span class="nf">boyer_moore_ara</span><span class="p">(</span><span class="n">metin</span><span class="p">,</span> <span class="sh">"</span><span class="s">METIN</span><span class="sh">"</span><span class="p">))</span>
</code></pre></div></div>

<p>Fonksiyon ilk eşleşmenin başlangıç indeksini, eşleşme yoksa <code class="language-plaintext highlighter-rouge">-1</code> değerini döndürür. Sözlüğün hazırlanması $O(m)$ zaman ve kullanılan farklı karakter sayısı kadar ek alan gerektirir.</p>

<h2 id="karmaşıklık-ve-kullanım-alanları">Karmaşıklık ve kullanım alanları</h2>

<p>Basitleştirilmiş sürümün en kötü durumu yine $O(nm)$ olabilir. Bununla birlikte Boyer-Moore, ortalama senaryolarda metnin bütün karakterlerini incelemeden ilerleyebilir. Tam algoritmanın dikkatli hazırlanmış sürümleri daha güçlü teorik garantiler sunar.</p>

<p>Algoritma; metin editörlerinde arama, log analizi, DNA dizilerinin incelenmesi ve güvenlik araçlarında imza tarama gibi alanlarda kullanılır. Kalıp kısa veya metin çok küçükse ön işleme maliyeti avantajı azaltabilir. Fakat uzun metinlerde Boyer-Moore’un sıçramaları, arama sürecini karakter karakter yürüyen bir kaplumbağadan engellerin üzerinden atlayan çevik bir tavşana dönüştürür.</p>

<p><img src="/img/boyer-moore-algoritmasi-21.svg" alt="boyer-moore-algoritmasi-21" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="boyer-moore" /><category term="algoritma" /><category term="metin-arama" /><category term="python" /><category term="dizgi" /><category term="veri-yapıları" /><summary type="html"><![CDATA[Bir metin içinde kelime ararken her karakteri sırayla karşılaştırmak güvenilir olsa da her zaman akıllıca değildir. Boyer-Moore algoritması, kalıbı sağdan sola inceleyip uyuşmazlıklardan bilgi çıkararak gereksiz karşılaştırmaları atlar. Kısacası yalnızca “eşleşmedi” demez; “buradan birkaç adım öteye sıçrayabilirim” diyerek aramayı hızlandırır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/boyer-moore-algoritmasi-21.png" /><media:content medium="image" url="https://program.sonsuz.us/img/boyer-moore-algoritmasi-21.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">DAG’larda En Kısa Yol: Döngüler Olmadan Daha Hızlı Rotalar</title><link href="https://program.sonsuz.us/posts/daglarda-en-kisa-yol-donguler-olmadan-daha-hizli-rotalar/" rel="alternate" type="text/html" title="DAG’larda En Kısa Yol: Döngüler Olmadan Daha Hızlı Rotalar" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/daglarda-en-kisa-yol-donguler-olmadan-daha-hizli-rotalar</id><content type="html" xml:base="https://program.sonsuz.us/posts/daglarda-en-kisa-yol-donguler-olmadan-daha-hizli-rotalar/"><![CDATA[<p>Bir şehir haritasında sürekli aynı kavşağa dönebiliyorsanız rota bulmak biraz baş ağrıtabilir. Yönlendirilmiş Asiklik Graf (Directed Acyclic Graph veya DAG) ise bu karmaşayı ortadan kaldırır: Okları takip ederek başladığınız düğüme geri dönemezsiniz. Bu döngüsüz yapı sayesinde en kısa yolları, Dijkstra’nın öncelik kuyruğuna bile ihtiyaç duymadan oldukça zarif biçimde hesaplayabiliriz.</p>

<p><img src="/img/daglarda-en-kisa-47.svg" alt="daglarda-en-kisa-47" /></p>

<p>``</p>

<h2 id="önce-dag-nedir">Önce DAG nedir?</h2>

<p>Yönlendirilmiş bir grafta kenarlar belirli bir yöne sahiptir. Örneğin $u \rightarrow v$ kenarı, yalnızca $u$ düğümünden $v$ düğümüne geçişi temsil eder. Grafın içinde yönlendirilmiş hiçbir döngü bulunmuyorsa bu yapı bir DAG’dır.</p>

<p>DAG’lar; görev planlama, ders ön koşulları, bağımlılık yönetimi, veri işleme hatları ve sürüm geçmişleri gibi doğal bir ilerleme sırası bulunan problemlerde sıkça görülür.</p>

<p>Döngünün bulunmaması, düğümleri <strong>topolojik olarak sıralayabilmemizi</strong> sağlar. Böyle bir sıralamada her $u \rightarrow v$ kenarı için $u$, listede $v$’den önce gelir. En kısa yol algoritmasının asıl süper gücü de budur.</p>

<h2 id="neden-topolojik-sıralama-yeterli">Neden topolojik sıralama yeterli?</h2>

<p>Başlangıç düğümünün uzaklığını $0$, diğer bütün uzaklıkları $∞$ kabul edelim. Düğümleri topolojik sırayla işlerken her kenar için gevşetme yaparız:</p>

\[d[v] = \min(d[v],\ d[u] + w(u,v))\]

<p>Burada $d[u]$, başlangıçtan $u$ düğümüne bilinen en kısa uzaklık; $w(u,v)$ ise kenarın ağırlığıdır. Bir düğüm işlendiğinde ona gelebilecek bütün önceki düğümler zaten değerlendirilmiştir. Dolayısıyla geriye dönüp uzaklığı tekrar tekrar düzeltmeye gerek kalmaz.</p>

<table>
  <thead>
    <tr>
      <th>Algoritma</th>
      <th style="text-align: right">Negatif kenar</th>
      <th style="text-align: right">Döngü desteği</th>
      <th style="text-align: right">Zaman karmaşıklığı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>DAG en kısa yol</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Hayır</td>
      <td style="text-align: right">$O(V+E)$</td>
    </tr>
    <tr>
      <td>Dijkstra</td>
      <td style="text-align: right">Hayır</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Genellikle $O((V+E)\log V)$</td>
    </tr>
    <tr>
      <td>Bellman-Ford</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">$O(VE)$</td>
    </tr>
  </tbody>
</table>

<p>DAG algoritması negatif ağırlıklı kenarlarla da çalışır. Çünkü negatif bir kenarın uzaklıkları sonradan beklenmedik biçimde değiştireceği döngüsel bir geri dönüş yoktur. Negatif döngü zaten DAG tanımı gereği oluşamaz.</p>

<h2 id="python-ile-uygulama">Python ile uygulama</h2>

<p>Aşağıdaki fonksiyon önce DFS kullanarak topolojik sıralamayı oluşturur, ardından düğümleri bu sırada işleyerek kenarları gevşetir:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">dag_shortest_path</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">start</span><span class="p">):</span>
    <span class="n">visited</span> <span class="o">=</span> <span class="nf">set</span><span class="p">()</span>
    <span class="n">order</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">dfs</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
        <span class="n">visited</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">neighbor</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="p">[]):</span>
            <span class="k">if</span> <span class="n">neighbor</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">visited</span><span class="p">:</span>
                <span class="nf">dfs</span><span class="p">(</span><span class="n">neighbor</span><span class="p">)</span>
        <span class="n">order</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>

    <span class="c1"># Bağlantısız parçalar için tüm düğümleri dolaşır.
</span>    <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">node</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">visited</span><span class="p">:</span>
            <span class="nf">dfs</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>

    <span class="n">order</span><span class="p">.</span><span class="nf">reverse</span><span class="p">()</span>
    <span class="n">distance</span> <span class="o">=</span> <span class="p">{</span><span class="n">node</span><span class="p">:</span> <span class="nf">float</span><span class="p">(</span><span class="sh">'</span><span class="s">inf</span><span class="sh">'</span><span class="p">)</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">}</span>
    <span class="n">distance</span><span class="p">[</span><span class="n">start</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">order</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">distance</span><span class="p">[</span><span class="n">node</span><span class="p">]</span> <span class="o">==</span> <span class="nf">float</span><span class="p">(</span><span class="sh">'</span><span class="s">inf</span><span class="sh">'</span><span class="p">):</span>
            <span class="k">continue</span>

        <span class="k">for</span> <span class="n">neighbor</span><span class="p">,</span> <span class="n">weight</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="p">[]):</span>
            <span class="n">candidate</span> <span class="o">=</span> <span class="n">distance</span><span class="p">[</span><span class="n">node</span><span class="p">]</span> <span class="o">+</span> <span class="n">weight</span>
            <span class="k">if</span> <span class="n">candidate</span> <span class="o">&lt;</span> <span class="n">distance</span><span class="p">[</span><span class="n">neighbor</span><span class="p">]:</span>
                <span class="n">distance</span><span class="p">[</span><span class="n">neighbor</span><span class="p">]</span> <span class="o">=</span> <span class="n">candidate</span>

    <span class="k">return</span> <span class="n">distance</span>


<span class="n">graph</span> <span class="o">=</span> <span class="p">{</span>
    <span class="sh">'</span><span class="s">A</span><span class="sh">'</span><span class="p">:</span> <span class="p">[(</span><span class="sh">'</span><span class="s">B</span><span class="sh">'</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span> <span class="p">(</span><span class="sh">'</span><span class="s">C</span><span class="sh">'</span><span class="p">,</span> <span class="mi">2</span><span class="p">)],</span>
    <span class="sh">'</span><span class="s">B</span><span class="sh">'</span><span class="p">:</span> <span class="p">[(</span><span class="sh">'</span><span class="s">D</span><span class="sh">'</span><span class="p">,</span> <span class="mi">3</span><span class="p">)],</span>
    <span class="sh">'</span><span class="s">C</span><span class="sh">'</span><span class="p">:</span> <span class="p">[(</span><span class="sh">'</span><span class="s">B</span><span class="sh">'</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="sh">'</span><span class="s">D</span><span class="sh">'</span><span class="p">,</span> <span class="mi">5</span><span class="p">)],</span>
    <span class="sh">'</span><span class="s">D</span><span class="sh">'</span><span class="p">:</span> <span class="p">[]</span>
<span class="p">}</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">dag_shortest_path</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="sh">'</span><span class="s">A</span><span class="sh">'</span><span class="p">))</span>
</code></pre></div></div>

<p>Bu örnekte <code class="language-plaintext highlighter-rouge">C → B</code> kenarının ağırlığı negatiftir. Buna rağmen sonuç güvenle hesaplanır: <code class="language-plaintext highlighter-rouge">A → C → B → D</code> rotasının toplam maliyeti $2 + (-1) + 3 = 4$ olur. Doğrudan görünen yollar her zaman en hesaplı yollar değildir!</p>

<h2 id="karmaşıklık-ve-önemli-ayrıntılar">Karmaşıklık ve önemli ayrıntılar</h2>

<p>Topolojik sıralama $O(V+E)$, bütün kenarların gevşetilmesi de $O(V+E)$ sürer. Böylece toplam zaman karmaşıklığı $O(V+E)$, ek alan gereksinimi ise $O(V)$ olur. Bu, grafın tamamını en azından bir kez incelemek zorunda olduğumuz düşünüldüğünde oldukça verimlidir.</p>

<p>Ancak algoritmayı kullanmadan önce grafın gerçekten asiklik olduğu doğrulanmalıdır. Döngü varsa topolojik sıralama üretilemez. Kahn algoritması sonunda işlenen düğüm sayısını kontrol etmek veya DFS sırasında renk tabanlı döngü tespiti yapmak bu doğrulama için uygundur.</p>

<p>Özetle DAG yapısı, “ilerideki bir düğüm geçmişi etkileyemez” garantisi verir. Bu garanti en kısa yol problemini tek yönlü, doğrusal ve hızlı bir hesaplamaya dönüştürür; bazen döngülerin yokluğu gerçekten de hayatı kolaylaştırır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="dag" /><category term="graf teorisi" /><category term="en kısa yol" /><category term="topolojik sıralama" /><category term="algoritmalar" /><category term="python" /><summary type="html"><![CDATA[Bir şehir haritasında sürekli aynı kavşağa dönebiliyorsanız rota bulmak biraz baş ağrıtabilir. Yönlendirilmiş Asiklik Graf (Directed Acyclic Graph veya DAG) ise bu karmaşayı ortadan kaldırır: Okları takip ederek başladığınız düğüme geri dönemezsiniz. Bu döngüsüz yapı sayesinde en kısa yolları, Dijkstra’nın öncelik kuyruğuna bile ihtiyaç duymadan oldukça zarif biçimde hesaplayabiliriz.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/daglarda-en-kisa-47.png" /><media:content medium="image" url="https://program.sonsuz.us/img/daglarda-en-kisa-47.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Dizgi Sıralamada Hızlı İkili: LSD ve MSD Algoritmaları</title><link href="https://program.sonsuz.us/posts/dizgi-siralamada-hizli-ikili-lsd-ve-msd-algoritmalari/" rel="alternate" type="text/html" title="Dizgi Sıralamada Hızlı İkili: LSD ve MSD Algoritmaları" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/dizgi-siralamada-hizli-ikili-lsd-ve-msd-algoritmalari</id><content type="html" xml:base="https://program.sonsuz.us/posts/dizgi-siralamada-hizli-ikili-lsd-ve-msd-algoritmalari/"><![CDATA[<p>Bir sözlükteki milyonlarca kelimeyi sıralamanız gerektiğini düşünün. Klasik algoritmalar kelimeleri tekrar tekrar karşılaştırırken LSD ve MSD, karakterleri doğrudan anahtar olarak kullanır. Böylece “hangisi küçük?” sorusunu sürekli sormak yerine karakterlerin dağılımından yararlanırlar. Sonuç, uygun koşullarda karşılaştırmalı sıralamalardan belirgin biçimde daha hızlı çalışan bir yaklaşımdır.</p>

<p><img src="/img/dizgi-siralamada-hizli-55.svg" alt="dizgi-siralamada-hizli-55" /></p>

<p>``</p>
<h2 id="karşılaştırma-olmadan-sıralama-fikri">Karşılaştırma Olmadan Sıralama Fikri</h2>

<p>Quick Sort, Merge Sort ve Heap Sort gibi klasik algoritmalar karşılaştırma tabanlıdır. Bu algoritmaların genel alt sınırı $\Omega(N \log N)$ karşılaştırmadır. Dizgi sıralamada her karşılaştırma birden fazla karakterin incelenmesini gerektirebildiği için gerçek maliyet daha da büyüyebilir.</p>

<p>Anahtar-indeks sayımı ise karakterleri, örneğin ASCII kodlarını, küçük tam sayılara dönüştürür. Alfabe büyüklüğü $R$, eleman sayısı $N$ olduğunda tek karakter için temel süreç şöyledir:</p>

<ol>
  <li>Her karakterin kaç kez geçtiğini say.</li>
  <li>Sayımları başlangıç indekslerine dönüştür.</li>
  <li>Öğeleri yardımcı diziye dağıt.</li>
  <li>Sonucu ana diziye geri kopyala.</li>
</ol>

<p>Bu işlemin zaman karmaşıklığı $O(N + R)$ olur. Buradaki önemli ayrıntı, dağıtımın <strong>kararlı</strong> olmasıdır: Aynı karaktere sahip öğelerin önceki göreli sırası korunur.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">counting_sort_by_char</span><span class="p">(</span><span class="n">words</span><span class="p">,</span> <span class="n">index</span><span class="p">,</span> <span class="n">alphabet_size</span><span class="o">=</span><span class="mi">256</span><span class="p">):</span>
    <span class="n">count</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="n">alphabet_size</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">output</span> <span class="o">=</span> <span class="p">[</span><span class="bp">None</span><span class="p">]</span> <span class="o">*</span> <span class="nf">len</span><span class="p">(</span><span class="n">words</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">words</span><span class="p">:</span>
        <span class="n">code</span> <span class="o">=</span> <span class="nf">ord</span><span class="p">(</span><span class="n">word</span><span class="p">[</span><span class="n">index</span><span class="p">])</span>
        <span class="n">count</span><span class="p">[</span><span class="n">code</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">alphabet_size</span><span class="p">):</span>
        <span class="n">count</span><span class="p">[</span><span class="n">r</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">count</span><span class="p">[</span><span class="n">r</span><span class="p">]</span>

    <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">words</span><span class="p">:</span>
        <span class="n">code</span> <span class="o">=</span> <span class="nf">ord</span><span class="p">(</span><span class="n">word</span><span class="p">[</span><span class="n">index</span><span class="p">])</span>
        <span class="n">output</span><span class="p">[</span><span class="n">count</span><span class="p">[</span><span class="n">code</span><span class="p">]]</span> <span class="o">=</span> <span class="n">word</span>
        <span class="n">count</span><span class="p">[</span><span class="n">code</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="k">return</span> <span class="n">output</span>
</code></pre></div></div>

<p>Bu yardımcı fonksiyon, sabit bir karakter konumuna göre kararlı sıralama yapar. <code class="language-plaintext highlighter-rouge">count</code> dizisindeki bir hücre frekansı, ön toplam işleminden sonra ise başlangıç konumunu temsil eder.</p>

<h2 id="lsd-sağdan-sola-i̇lerlemek">LSD: Sağdan Sola İlerlemek</h2>

<p>LSD, yani <em>Least Significant Digit</em>, en sağdaki karakterden başlar ve sola doğru ilerler. Genellikle tüm anahtarların aynı uzunlukta olduğu durumlarda kullanılır. Plaka kodları, sabit uzunluklu kimlikler ve tarih biçimleri iyi örneklerdir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">lsd_sort</span><span class="p">(</span><span class="n">words</span><span class="p">,</span> <span class="n">width</span><span class="p">):</span>
    <span class="n">result</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="n">words</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">index</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">width</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
        <span class="n">result</span> <span class="o">=</span> <span class="nf">counting_sort_by_char</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">result</span>

<span class="n">codes</span> <span class="o">=</span> <span class="p">[</span><span class="sh">'</span><span class="s">B12</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">A90</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">B01</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">A12</span><span class="sh">'</span><span class="p">]</span>
<span class="nf">print</span><span class="p">(</span><span class="nf">lsd_sort</span><span class="p">(</span><span class="n">codes</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
</code></pre></div></div>

<p>Sağdan başlanmasının nedeni kararlılıktır. Son basamağa göre oluşan düzen, daha önemli bir karakter işlendiğinde aynı karakterli grupların içinde korunur. $W$ karakterli $N$ dizgi için yaklaşık maliyet $O(W(N + R))$ seviyesindedir.</p>

<h2 id="msd-soldan-başlayan-böl-ve-yönet">MSD: Soldan Başlayan Böl ve Yönet</h2>

<p>MSD, yani <em>Most Significant Digit</em>, önce en soldaki karakteri işler. Ardından aynı karakterle başlayan grupları kendi içlerinde özyinelemeli olarak sıralar. Değişken uzunluktaki kelimelerde özel bir “karakter yok” değeri kullanılır.</p>

<p>Örneğin <code class="language-plaintext highlighter-rouge">ar</code>, <code class="language-plaintext highlighter-rouge">ara</code> ve <code class="language-plaintext highlighter-rouge">armut</code> karşılaştırılırken kısa kelimenin bittiğini gösteren değer, gerçek karakterlerden küçük kabul edilir. Böylece <code class="language-plaintext highlighter-rouge">ar</code>, diğer ikisinin önüne gelir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>LSD</th>
      <th>MSD</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Başlangıç yönü</td>
      <td>Sağdan sola</td>
      <td>Soldan sağa</td>
    </tr>
    <tr>
      <td>Uygun anahtarlar</td>
      <td>Sabit uzunluklu</td>
      <td>Değişken uzunluklu</td>
    </tr>
    <tr>
      <td>Temel yapı</td>
      <td>Yinelemeli geçiş</td>
      <td>Özyinelemeli bölme</td>
    </tr>
    <tr>
      <td>Güçlü yanı</td>
      <td>Basit ve öngörülebilir</td>
      <td>Gereksiz karakterleri atlayabilir</td>
    </tr>
    <tr>
      <td>Zayıf yanı</td>
      <td>Her karakteri işler</td>
      <td>Küçük gruplarda ek yük oluşturur</td>
    </tr>
  </tbody>
</table>

<h2 id="ne-zaman-daha-hızlıdır">Ne Zaman Daha Hızlıdır?</h2>

<p>Karşılaştırmalı sıralama yaklaşık $N \log N$ adet karar verir; üstelik ortak ön eke sahip dizgilerde aynı karakterleri defalarca okuyabilir. LSD ve MSD ise alfabe küçükken karakterleri kovalar gibi doğrudan kutulara dağıtır. Özellikle $R$ sabit ve anahtar uzunluğu sınırlıysa doğrusal davranışa yaklaşırlar.</p>

<p>Bununla birlikte Unicode gibi çok büyük alfabelerde doğrudan devasa sayım dizileri kullanmak bellek israfına dönüşebilir. Küçük veri kümelerinde de Python’ın yerleşik <code class="language-plaintext highlighter-rouge">sorted</code> fonksiyonu, düşük sabit maliyetleri sayesinde daha hızlı olabilir. Kısacası LSD düzenli veri için güvenilir bir maratoncu, MSD ise ortak önekleri ustaca eleyen çevik bir sprinterdir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="algoritma" /><category term="sıralama" /><category term="lsd" /><category term="msd" /><category term="dizgi" /><category term="python" /><summary type="html"><![CDATA[Bir sözlükteki milyonlarca kelimeyi sıralamanız gerektiğini düşünün. Klasik algoritmalar kelimeleri tekrar tekrar karşılaştırırken LSD ve MSD, karakterleri doğrudan anahtar olarak kullanır. Böylece “hangisi küçük?” sorusunu sürekli sormak yerine karakterlerin dağılımından yararlanırlar. Sonuç, uygun koşullarda karşılaştırmalı sıralamalardan belirgin biçimde daha hızlı çalışan bir yaklaşımdır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/dizgi-siralamada-hizli-55.png" /><media:content medium="image" url="https://program.sonsuz.us/img/dizgi-siralamada-hizli-55.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Huffman Sıkıştırma Algoritması: Veriyi Akıllı Kodlarla Küçültmek</title><link href="https://program.sonsuz.us/posts/huffman-sikistirma-algoritmasi-veriyi-akilli-kodlarla-kucultmek/" rel="alternate" type="text/html" title="Huffman Sıkıştırma Algoritması: Veriyi Akıllı Kodlarla Küçültmek" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/huffman-sikistirma-algoritmasi-veriyi-akilli-kodlarla-kucultmek</id><content type="html" xml:base="https://program.sonsuz.us/posts/huffman-sikistirma-algoritmasi-veriyi-akilli-kodlarla-kucultmek/"><![CDATA[<p>Bir metindeki bütün karakterlere aynı uzunlukta bit dizileri vermek kolaydır; ancak pek ekonomik değildir. Huffman sıkıştırması, sık karşılaşılan karakterlere kısa, nadir karakterlere uzun kodlar atayarak ortalama veri boyutunu azaltır. Böylece algoritma, adeta çok konuşan karakterlere kestirme yol verirken seyrek görünenleri manzaralı ama uzun rotaya gönderir.</p>

<p>``</p>

<h2 id="temel-fikir-her-karakter-eşit-değildir">Temel fikir: Her karakter eşit değildir</h2>

<p>Elimizde <code class="language-plaintext highlighter-rouge">ABRACADABRA</code> metni olsun. Bu metinde <code class="language-plaintext highlighter-rouge">A</code> beş kez görülürken <code class="language-plaintext highlighter-rouge">C</code> yalnızca bir kez görünür. Her karakteri eşit uzunlukta kodlamak yerine <code class="language-plaintext highlighter-rouge">A</code> için daha kısa bir kod seçmek toplam bit sayısını düşürür.</p>

<p>Huffman algoritması <strong>kayıpsızdır</strong>: Sıkıştırılan veri açıldığında orijinal verinin birebir aynısı elde edilir. JPEG gibi bazı yöntemlerin aksine hiçbir karakter gözden çıkarılmaz.</p>

<p>Bir sembolün frekansı $f_i$, ona verilen kodun uzunluğu $l_i$ ise toplam maliyet şöyle ifade edilir:</p>

\[L = \sum_{i=1}^{n} f_i l_i\]

<p>Algoritmanın amacı, önek koşulunu koruyarak $L$ değerini küçültmektir. Önek koşulu, hiçbir kodun başka bir kodun başlangıcı olmaması demektir. Örneğin <code class="language-plaintext highlighter-rouge">A = 0</code> iken <code class="language-plaintext highlighter-rouge">B = 01</code> seçilemez; aksi hâlde bitleri okurken nerede duracağımız belirsizleşir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Sabit uzunluklu kodlama</th>
      <th>Huffman kodlama</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kod uzunluğu</td>
      <td>Her sembolde aynı</td>
      <td>Frekansa göre değişir</td>
    </tr>
    <tr>
      <td>Kayıp</td>
      <td>Yok</td>
      <td>Yok</td>
    </tr>
    <tr>
      <td>Çözümleme</td>
      <td>Doğrudan</td>
      <td>Huffman ağacıyla</td>
    </tr>
    <tr>
      <td>Verimlilik</td>
      <td>Dağılımdan etkilenmez</td>
      <td>Dengesiz dağılımlarda yüksektir</td>
    </tr>
    <tr>
      <td>Ek bilgi</td>
      <td>Genellikle gerekmez</td>
      <td>Kod ağacı veya tablosu gerekir</td>
    </tr>
  </tbody>
</table>

<h2 id="huffman-ağacı-nasıl-kurulur">Huffman ağacı nasıl kurulur?</h2>

<p>Önce her karakterin frekansı hesaplanır ve karakterler bir öncelik kuyruğuna yerleştirilir. Ardından şu döngü uygulanır:</p>

<ol>
  <li>En düşük frekanslı iki düğümü kuyruktan çıkar.</li>
  <li>Frekansları toplamına eşit yeni bir üst düğüm oluştur.</li>
  <li>İki düğümü bu üst düğümün çocukları yap.</li>
  <li>Yeni düğümü yeniden kuyruğa ekle.</li>
  <li>Tek düğüm kalana kadar işlemi tekrarla.</li>
</ol>

<p>Ağaç tamamlandığında sol dallara <code class="language-plaintext highlighter-rouge">0</code>, sağ dallara <code class="language-plaintext highlighter-rouge">1</code> verilebilir. Kökten karaktere kadar izlenen yol, karakterin kodudur. Sol ve sağ seçiminin ters yapılması sıkıştırma oranını değiştirmez; yalnızca ortaya çıkan kodları değiştirir.</p>

<h2 id="python-ile-uygulama">Python ile uygulama</h2>

<p>Aşağıdaki kod, karakter frekanslarından Huffman ağacı üretir ve her karakterin ikili kodunu çıkarır:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">collections</span> <span class="kn">import</span> <span class="n">Counter</span>
<span class="kn">import</span> <span class="n">heapq</span>

<span class="k">class</span> <span class="nc">Node</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">char</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">freq</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">left</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">right</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">char</span> <span class="o">=</span> <span class="n">char</span>
        <span class="n">self</span><span class="p">.</span><span class="n">freq</span> <span class="o">=</span> <span class="n">freq</span>
        <span class="n">self</span><span class="p">.</span><span class="n">left</span> <span class="o">=</span> <span class="n">left</span>
        <span class="n">self</span><span class="p">.</span><span class="n">right</span> <span class="o">=</span> <span class="n">right</span>

    <span class="k">def</span> <span class="nf">__lt__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">freq</span> <span class="o">&lt;</span> <span class="n">other</span><span class="p">.</span><span class="n">freq</span>


<span class="k">def</span> <span class="nf">huffman_codes</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="n">heap</span> <span class="o">=</span> <span class="p">[</span><span class="nc">Node</span><span class="p">(</span><span class="n">char</span><span class="p">,</span> <span class="n">freq</span><span class="p">)</span> <span class="k">for</span> <span class="n">char</span><span class="p">,</span> <span class="n">freq</span> <span class="ow">in</span> <span class="nc">Counter</span><span class="p">(</span><span class="n">text</span><span class="p">).</span><span class="nf">items</span><span class="p">()]</span>
    <span class="n">heapq</span><span class="p">.</span><span class="nf">heapify</span><span class="p">(</span><span class="n">heap</span><span class="p">)</span>

    <span class="k">if</span> <span class="nf">len</span><span class="p">(</span><span class="n">heap</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">{</span><span class="n">heap</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">char</span><span class="p">:</span> <span class="sh">"</span><span class="s">0</span><span class="sh">"</span><span class="p">}</span>

    <span class="k">while</span> <span class="nf">len</span><span class="p">(</span><span class="n">heap</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">left</span> <span class="o">=</span> <span class="n">heapq</span><span class="p">.</span><span class="nf">heappop</span><span class="p">(</span><span class="n">heap</span><span class="p">)</span>
        <span class="n">right</span> <span class="o">=</span> <span class="n">heapq</span><span class="p">.</span><span class="nf">heappop</span><span class="p">(</span><span class="n">heap</span><span class="p">)</span>
        <span class="n">parent</span> <span class="o">=</span> <span class="nc">Node</span><span class="p">(</span><span class="n">freq</span><span class="o">=</span><span class="n">left</span><span class="p">.</span><span class="n">freq</span> <span class="o">+</span> <span class="n">right</span><span class="p">.</span><span class="n">freq</span><span class="p">,</span>
                      <span class="n">left</span><span class="o">=</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="o">=</span><span class="n">right</span><span class="p">)</span>
        <span class="n">heapq</span><span class="p">.</span><span class="nf">heappush</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">parent</span><span class="p">)</span>

    <span class="n">codes</span> <span class="o">=</span> <span class="p">{}</span>

    <span class="k">def</span> <span class="nf">walk</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">code</span><span class="o">=</span><span class="sh">""</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">node</span><span class="p">.</span><span class="n">char</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="n">codes</span><span class="p">[</span><span class="n">node</span><span class="p">.</span><span class="n">char</span><span class="p">]</span> <span class="o">=</span> <span class="n">code</span>
            <span class="k">return</span>
        <span class="nf">walk</span><span class="p">(</span><span class="n">node</span><span class="p">.</span><span class="n">left</span><span class="p">,</span> <span class="n">code</span> <span class="o">+</span> <span class="sh">"</span><span class="s">0</span><span class="sh">"</span><span class="p">)</span>
        <span class="nf">walk</span><span class="p">(</span><span class="n">node</span><span class="p">.</span><span class="n">right</span><span class="p">,</span> <span class="n">code</span> <span class="o">+</span> <span class="sh">"</span><span class="s">1</span><span class="sh">"</span><span class="p">)</span>

    <span class="nf">walk</span><span class="p">(</span><span class="n">heap</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
    <span class="k">return</span> <span class="n">codes</span>

<span class="n">text</span> <span class="o">=</span> <span class="sh">"</span><span class="s">ABRACADABRA</span><span class="sh">"</span>
<span class="n">codes</span> <span class="o">=</span> <span class="nf">huffman_codes</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">encoded</span> <span class="o">=</span> <span class="sh">""</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">codes</span><span class="p">[</span><span class="n">ch</span><span class="p">]</span> <span class="k">for</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">text</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="n">codes</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">encoded</span><span class="p">)</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Counter</code> frekansları bulur; <code class="language-plaintext highlighter-rouge">heapq</code> ise en küçük iki düğüme verimli biçimde ulaşılmasını sağlar. Tek karakterden oluşan girdiye <code class="language-plaintext highlighter-rouge">0</code> kodu verilmesi, boş kod gibi kullanışsız bir özel durumu önler. $k$ farklı sembol için ağaç oluşturmanın zaman karmaşıklığı yaklaşık $O(k \log k)$ düzeyindedir.</p>

<h2 id="her-zaman-kazandırır-mı">Her zaman kazandırır mı?</h2>

<p>Hayır. Karakterlerin frekansları birbirine çok yakınsa kod uzunlukları da benzer olur. Üstelik çözücünün ağacı öğrenebilmesi için frekans tablosu veya kod sözlüğü dosyaya eklenmelidir. Çok küçük verilerde bu ek yük, elde edilen tasarrufu geçebilir.</p>

<p>Buna rağmen Huffman kodlama; ZIP, DEFLATE, PNG ve çeşitli medya biçimlerinde daha büyük sıkıştırma süreçlerinin önemli bir parçasıdır. Basit fikri, matematiksel sağlamlığı ve ağaç yapılarıyla kurduğu bağ sayesinde hem pratik hem de öğretici bir algoritmadır.</p>

<p><img src="/img/huffman-sikistirma-algoritmasi-79.svg" alt="huffman-sikistirma-algoritmasi-79" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="huffman" /><category term="veri sıkıştırma" /><category term="algoritma" /><category term="python" /><category term="ikili ağaç" /><category term="kodlama" /><summary type="html"><![CDATA[Bir metindeki bütün karakterlere aynı uzunlukta bit dizileri vermek kolaydır; ancak pek ekonomik değildir. Huffman sıkıştırması, sık karşılaşılan karakterlere kısa, nadir karakterlere uzun kodlar atayarak ortalama veri boyutunu azaltır. Böylece algoritma, adeta çok konuşan karakterlere kestirme yol verirken seyrek görünenleri manzaralı ama uzun rotaya gönderir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/huffman-sikistirma-algoritmasi-79.png" /><media:content medium="image" url="https://program.sonsuz.us/img/huffman-sikistirma-algoritmasi-79.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>