<?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-15T06:05:40+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">B-Ağaçları: Veritabanlarının Diskteki Hız Sırrı</title><link href="https://program.sonsuz.us/posts/b-agaclari-veritabanlarinin-diskteki-hiz-sirri/" rel="alternate" type="text/html" title="B-Ağaçları: Veritabanlarının Diskteki Hız Sırrı" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/b-agaclari-veritabanlarinin-diskteki-hiz-sirri</id><content type="html" xml:base="https://program.sonsuz.us/posts/b-agaclari-veritabanlarinin-diskteki-hiz-sirri/"><![CDATA[<p>Bir veritabanında milyonlarca kayıt bulunmasına rağmen sorguların birkaç milisaniyede sonuçlanması sihir değildir. Bu başarının arkasında, verileri disk üzerinde akıllıca düzenleyen indeksler ve özellikle B-ağaçları vardır. Dengeli, geniş ve kısa bir yapıya sahip olan B-ağaçları, pahalı disk erişimlerinin sayısını azaltarak aradığımız kayda mümkün olduğunca az adımda ulaşmamızı sağlar.
``</p>

<h2 id="asıl-sorun-disk-erişimi-pahalıdır">Asıl sorun: Disk erişimi pahalıdır</h2>

<p>RAM üzerindeki verilere erişmek son derece hızlıdır; ancak kalıcı veriler SSD veya sabit diskte tutulur. Diskten tek bir bayt yerine genellikle <strong>sayfa</strong> ya da <strong>blok</strong> adı verilen sabit boyutlu veri parçaları okunur. Bir sayfanın boyutu örneğin 4 KB, 8 KB veya 16 KB olabilir.</p>

<p>Bu nedenle disk tabanlı bir veri yapısında temel maliyet, yapılan karşılaştırmalar değil, okunan sayfa sayısıdır. Bir milyon kayıt arasında ikili arama teorik olarak</p>

\[\log_2(1.000.000) \approx 20\]

<p>adım gerektirir. Fakat her düğüm ayrı bir disk sayfasındaysa yaklaşık 20 disk erişimi oldukça pahalı olabilir. B-ağaçları ise bir düğümde çok sayıda anahtar saklayarak ağacın dallanma katsayısını büyütür.</p>

<h2 id="b-ağacının-temel-mantığı">B-ağacının temel mantığı</h2>

<p>İkili arama ağacındaki her düğüm en fazla iki çocuğa sahiptir. B-ağacında ise bir düğüm onlarca, hatta yüzlerce çocuk barındırabilir. Düğüm boyutu genellikle bir disk sayfasını dolduracak şekilde seçilir.</p>

<p>Bir B-ağacının dallanma katsayısı $m$ ise yaklaşık yüksekliği şöyledir:</p>

\[h \approx \log_m(n)\]

<p>Örneğin bir düğüm 100 çocuk gösterebiliyorsa bir milyon kayıt için:</p>

\[\log_{100}(1.000.000) = 3\]

<p>Yani teorik olarak yalnızca üç sayfa okumasıyla hedef bölgeye ulaşılabilir. Üst düğümlerin önbellekte tutulması durumunda gerçek disk erişimi daha da azalır.</p>

<table>
  <thead>
    <tr>
      <th>Yapı</th>
      <th style="text-align: right">Düğüm başına çocuk</th>
      <th style="text-align: right">Yaklaşık yükseklik</th>
      <th>Disk kullanımı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>İkili arama ağacı</td>
      <td style="text-align: right">2</td>
      <td style="text-align: right">Yüksek</td>
      <td>Çok sayıda rastgele erişim</td>
    </tr>
    <tr>
      <td>B-ağacı</td>
      <td style="text-align: right">Çok sayıda</td>
      <td style="text-align: right">Düşük</td>
      <td>Sayfa odaklı ve verimli</td>
    </tr>
    <tr>
      <td>B+ ağacı</td>
      <td style="text-align: right">Çok sayıda</td>
      <td style="text-align: right">Düşük</td>
      <td>Sıralı taramalar için çok uygun</td>
    </tr>
    <tr>
      <td>Hash indeks</td>
      <td style="text-align: right">Kovaya bağlı</td>
      <td style="text-align: right">Genellikle sabit</td>
      <td>Eşitlik sorgularında güçlü</td>
    </tr>
  </tbody>
</table>

<h2 id="arama-nasıl-gerçekleştirilir">Arama nasıl gerçekleştirilir?</h2>

<p>Her düğümde anahtarlar sıralı tutulur. Aranan değer düğümdeki anahtarlarla karşılaştırılır ve uygun çocuk sayfasına geçilir. Aşağıdaki sadeleştirilmiş Python kodu, bellekteki bir B-ağacı düğümünde bu yönlendirmeyi gösterir:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">BTreeNode</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">keys</span><span class="p">,</span> <span class="n">children</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">leaf</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">keys</span> <span class="o">=</span> <span class="n">keys</span>
        <span class="n">self</span><span class="p">.</span><span class="n">children</span> <span class="o">=</span> <span class="n">children</span> <span class="ow">or</span> <span class="p">[]</span>
        <span class="n">self</span><span class="p">.</span><span class="n">leaf</span> <span class="o">=</span> <span class="n">leaf</span>

    <span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">target</span><span class="p">):</span>
        <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="k">while</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">keys</span><span class="p">)</span> <span class="ow">and</span> <span class="n">target</span> <span class="o">&gt;</span> <span class="n">self</span><span class="p">.</span><span class="n">keys</span><span class="p">[</span><span class="n">index</span><span class="p">]:</span>
            <span class="n">index</span> <span class="o">+=</span> <span class="mi">1</span>

        <span class="k">if</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">keys</span><span class="p">)</span> <span class="ow">and</span> <span class="n">target</span> <span class="o">==</span> <span class="n">self</span><span class="p">.</span><span class="n">keys</span><span class="p">[</span><span class="n">index</span><span class="p">]:</span>
            <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">keys</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>

        <span class="k">if</span> <span class="n">self</span><span class="p">.</span><span class="n">leaf</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">None</span>

        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">children</span><span class="p">[</span><span class="n">index</span><span class="p">].</span><span class="nf">search</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
</code></pre></div></div>

<p>Kod, önce hedefin hangi anahtar aralığında bulunduğunu belirler. Düğüm yaprak değilse yalnızca ilgili çocuğa ilerler. Gerçek veritabanlarında <code class="language-plaintext highlighter-rouge">children</code> listesindeki öğeler çoğunlukla nesne değil, disk sayfalarının adresleridir. Ayrıca düğüm içindeki arama doğrusal tarama yerine ikili aramayla yapılabilir.</p>

<h2 id="ekleme-ve-bölünme">Ekleme ve bölünme</h2>

<p>Bir düğüm dolduğunda yeni kayıt gelişigüzel başka bir yere konmaz. Düğüm iki parçaya bölünür ve ortadaki anahtar üst düğüme taşınır. Üst düğüm de dolarsa bölünme köke kadar ilerleyebilir. Kök bölündüğünde ağacın yüksekliği yalnızca bir artar.</p>

<p>Bu kurallar bütün yaprakların aynı seviyede kalmasını sağlar. Böylece kötü sıralanmış eklemeler bile ağacı uzun bir zincire dönüştüremez. Arama, ekleme ve silme işlemlerinin maliyeti genel olarak $O(\log_m n)$ seviyesindedir.</p>

<h2 id="b-ağaçları-neden-daha-yaygın">B+ ağaçları neden daha yaygın?</h2>

<p>Modern veritabanları çoğunlukla B-ağacının bir türevi olan <strong>B+ ağacını</strong> kullanır. İç düğümler yalnızca yönlendirme anahtarlarını içerirken gerçek kayıtlar yapraklarda saklanır. Yapraklar birbirine bağlı olduğundan <code class="language-plaintext highlighter-rouge">WHERE yas BETWEEN 20 AND 30</code> gibi aralık sorguları, ilk kayıt bulunduktan sonra sayfalar üzerinde sıralı biçimde ilerleyebilir.</p>

<p>Kısacası B-ağaçlarının gücü yalnızca hızlı arama yapmalarından gelmez. Disk sayfalarıyla uyumlu çalışmaları, dengelerini korumaları ve yüksek dallanma katsayıları sayesinde milyonlarca kaydı birkaç disk erişimine indirgemeleri onları veritabanı indekslerinin vazgeçilmez kahramanı yapar.</p>

<p><img src="/img/b-agaclari-veritabanlarinin-26.svg" alt="b-agaclari-veritabanlarinin-26" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="b-ağacı" /><category term="veritabanı" /><category term="veri yapıları" /><category term="algoritma" /><category term="indeksleme" /><category term="disk erişimi" /><summary type="html"><![CDATA[Bir veritabanında milyonlarca kayıt bulunmasına rağmen sorguların birkaç milisaniyede sonuçlanması sihir değildir. Bu başarının arkasında, verileri disk üzerinde akıllıca düzenleyen indeksler ve özellikle B-ağaçları vardır. Dengeli, geniş ve kısa bir yapıya sahip olan B-ağaçları, pahalı disk erişimlerinin sayısını azaltarak aradığımız kayda mümkün olduğunca az adımda ulaşmamızı sağlar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/b-agaclari-veritabanlarinin-26.png" /><media:content medium="image" url="https://program.sonsuz.us/img/b-agaclari-veritabanlarinin-26.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">En Uzun Tekrar Eden Alt Dizgi: Son Ek Dizileriyle Metnin Gizli Tekrarlarını Bulmak</title><link href="https://program.sonsuz.us/posts/en-uzun-tekrar-eden-alt-dizgi-son-ek-dizileriyle-metnin-gizli-tekrarlarini-bulmak/" rel="alternate" type="text/html" title="En Uzun Tekrar Eden Alt Dizgi: Son Ek Dizileriyle Metnin Gizli Tekrarlarını Bulmak" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/en-uzun-tekrar-eden-alt-dizgi-son-ek-dizileriyle-metnin-gizli-tekrarlarini-bulmak</id><content type="html" xml:base="https://program.sonsuz.us/posts/en-uzun-tekrar-eden-alt-dizgi-son-ek-dizileriyle-metnin-gizli-tekrarlarini-bulmak/"><![CDATA[<p><img src="/img/en-uzun-tekrar-83.svg" alt="en-uzun-tekrar-83" /></p>

<p>Bir metnin içinde en az iki kez geçen en uzun parça hangisidir? İlk bakışta bütün alt dizgileri üretip karşılaştırmak makul görünebilir. Ancak metin büyüdüğünde bu yöntem, samanlıkta iğne ararken önce bütün samanları tek tek numaralandırmaya dönüşür. Son ek dizisi ve LCP dizisi ise tekrarları düzenli, hızlı ve şaşırtıcı derecede zarif biçimde ortaya çıkarır.
``</p>
<h2 id="problem-tam-olarak-nedir">Problem tam olarak nedir?</h2>

<p>Bir $S$ metni verildiğinde, metin içinde farklı başlangıç konumlarında en az iki kez bulunan en uzun <strong>alt dizgiyi</strong> ararız. Örneğin <code class="language-plaintext highlighter-rouge">banana</code> metninde cevap <code class="language-plaintext highlighter-rouge">ana</code> olur:</p>

<ul>
  <li>İlk geçiş: <code class="language-plaintext highlighter-rouge">b[ana]na</code></li>
  <li>İkinci geçiş: <code class="language-plaintext highlighter-rouge">ban[ana]</code></li>
</ul>

<p>Geçişlerin çakışmasına izin verilebilir. Örneğin <code class="language-plaintext highlighter-rouge">aaaa</code> içinde <code class="language-plaintext highlighter-rouge">aaa</code>, 0 ve 1 indislerinden başlayarak iki kez görünür.</p>

<p>Naif yaklaşım tüm alt dizgileri karşılaştırır. Uzunluğu $n$ olan bir metinde yaklaşık $n(n+1)/2$ alt dizgi bulunduğundan maliyet hızla büyür.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Temel fikir</th>
      <th style="text-align: right">Yaklaşık zaman</th>
      <th style="text-align: right">Bellek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kaba kuvvet</td>
      <td>Bütün alt dizgileri karşılaştır</td>
      <td style="text-align: right">$O(n^3)$</td>
      <td style="text-align: right">$O(1)$–$O(n^2)$</td>
    </tr>
    <tr>
      <td>Hash tabanlı arama</td>
      <td>Uzunluğu ikili arayıp hash karşılaştır</td>
      <td style="text-align: right">$O(n \log n)$</td>
      <td style="text-align: right">$O(n)$</td>
    </tr>
    <tr>
      <td>Son ek dizisi + LCP</td>
      <td>Sıralı son eklerin ortak öneklerini ölç</td>
      <td style="text-align: right">$O(n \log n)$</td>
      <td style="text-align: right">$O(n)$</td>
    </tr>
  </tbody>
</table>

<h2 id="son-ek-dizisi-neden-işe-yarar">Son ek dizisi neden işe yarar?</h2>

<p>Bir <strong>son ek</strong>, metnin herhangi bir konumundan başlayıp sona kadar giden parçadır. <code class="language-plaintext highlighter-rouge">banana</code> için son ekler şöyledir:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: right">Başlangıç</th>
      <th>Son ek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">0</td>
      <td>banana</td>
    </tr>
    <tr>
      <td style="text-align: right">1</td>
      <td>anana</td>
    </tr>
    <tr>
      <td style="text-align: right">2</td>
      <td>nana</td>
    </tr>
    <tr>
      <td style="text-align: right">3</td>
      <td>ana</td>
    </tr>
    <tr>
      <td style="text-align: right">4</td>
      <td>na</td>
    </tr>
    <tr>
      <td style="text-align: right">5</td>
      <td>a</td>
    </tr>
  </tbody>
</table>

<p>Bunlar alfabetik sıralandığında başlangıç indisleri <code class="language-plaintext highlighter-rouge">[5, 3, 1, 0, 4, 2]</code> olur. Bu indis listesine <strong>son ek dizisi</strong> denir.</p>

<p>Kritik fikir şudur: Ortak başlangıca sahip son ekler alfabetik sıralamada yan yana gelir. Dolayısıyla bütün son ek çiftlerini karşılaştırmak yerine yalnızca komşuları incelemek yeterlidir.</p>

<p>Komşu son eklerin ortak önek uzunluklarını tutan yapıya <strong>LCP</strong> (<em>Longest Common Prefix</em>) dizisi denir. Aradığımız sonuç:</p>

\[L = \max_{1 \le i &lt; n} LCP[i]\]

<p><code class="language-plaintext highlighter-rouge">banana</code> için en büyük LCP değeri 3’tür; ilgili parça <code class="language-plaintext highlighter-rouge">ana</code>dır.</p>

<h2 id="python-ile-çözüm">Python ile çözüm</h2>

<p>Aşağıdaki uygulama, son ek dizisini önek katlama yöntemiyle kurar. Her turda karşılaştırılan önek uzunluğu iki katına çıkar. Ardından Kasai algoritması LCP dizisini doğrusal zamanda hesaplar.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">suffix_array</span><span class="p">(</span><span class="n">text</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">text</span><span class="p">)</span>
    <span class="n">sa</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="n">n</span><span class="p">))</span>
    <span class="n">rank</span> <span class="o">=</span> <span class="p">[</span><span class="nf">ord</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="n">k</span> <span class="o">=</span> <span class="mi">1</span>

    <span class="k">while</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">:</span>
        <span class="n">sa</span><span class="p">.</span><span class="nf">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="p">(</span>
            <span class="n">rank</span><span class="p">[</span><span class="n">i</span><span class="p">],</span>
            <span class="n">rank</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">k</span><span class="p">]</span> <span class="k">if</span> <span class="n">i</span> <span class="o">+</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="k">else</span> <span class="o">-</span><span class="mi">1</span>
        <span class="p">))</span>

        <span class="n">new_rank</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
            <span class="n">previous</span><span class="p">,</span> <span class="n">current</span> <span class="o">=</span> <span class="n">sa</span><span class="p">[</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">],</span> <span class="n">sa</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
            <span class="n">prev_key</span> <span class="o">=</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">previous</span><span class="p">],</span>
                        <span class="n">rank</span><span class="p">[</span><span class="n">previous</span> <span class="o">+</span> <span class="n">k</span><span class="p">]</span> <span class="k">if</span> <span class="n">previous</span> <span class="o">+</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="k">else</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
            <span class="n">curr_key</span> <span class="o">=</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">current</span><span class="p">],</span>
                        <span class="n">rank</span><span class="p">[</span><span class="n">current</span> <span class="o">+</span> <span class="n">k</span><span class="p">]</span> <span class="k">if</span> <span class="n">current</span> <span class="o">+</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="k">else</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
            <span class="n">new_rank</span><span class="p">[</span><span class="n">current</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_rank</span><span class="p">[</span><span class="n">previous</span><span class="p">]</span> <span class="o">+</span> <span class="p">(</span><span class="n">prev_key</span> <span class="o">!=</span> <span class="n">curr_key</span><span class="p">)</span>

        <span class="n">rank</span> <span class="o">=</span> <span class="n">new_rank</span>
        <span class="k">if</span> <span class="n">rank</span><span class="p">[</span><span class="n">sa</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="o">-</span> <span class="mi">1</span><span class="p">:</span>
            <span class="k">break</span>
        <span class="n">k</span> <span class="o">*=</span> <span class="mi">2</span>

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


<span class="k">def</span> <span class="nf">longest_repeated_substring</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">text</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">""</span>

    <span class="n">sa</span> <span class="o">=</span> <span class="nf">suffix_array</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
    <span class="n">rank</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="nf">len</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">position</span><span class="p">,</span> <span class="n">suffix_start</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">sa</span><span class="p">):</span>
        <span class="n">rank</span><span class="p">[</span><span class="n">suffix_start</span><span class="p">]</span> <span class="o">=</span> <span class="n">position</span>

    <span class="n">best_length</span> <span class="o">=</span> <span class="n">best_start</span> <span class="o">=</span> <span class="n">common</span> <span class="o">=</span> <span class="mi">0</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="nf">len</span><span class="p">(</span><span class="n">text</span><span class="p">)):</span>
        <span class="n">position</span> <span class="o">=</span> <span class="n">rank</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">position</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">continue</span>

        <span class="n">j</span> <span class="o">=</span> <span class="n">sa</span><span class="p">[</span><span class="n">position</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
        <span class="nf">while </span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="n">common</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> <span class="ow">and</span>
               <span class="n">j</span> <span class="o">+</span> <span class="n">common</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> <span class="ow">and</span>
               <span class="n">text</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">common</span><span class="p">]</span> <span class="o">==</span> <span class="n">text</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="n">common</span><span class="p">]):</span>
            <span class="n">common</span> <span class="o">+=</span> <span class="mi">1</span>

        <span class="k">if</span> <span class="n">common</span> <span class="o">&gt;</span> <span class="n">best_length</span><span class="p">:</span>
            <span class="n">best_length</span><span class="p">,</span> <span class="n">best_start</span> <span class="o">=</span> <span class="n">common</span><span class="p">,</span> <span class="n">i</span>

        <span class="n">common</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">common</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">text</span><span class="p">[</span><span class="n">best_start</span><span class="p">:</span><span class="n">best_start</span> <span class="o">+</span> <span class="n">best_length</span><span class="p">]</span>


<span class="nf">print</span><span class="p">(</span><span class="nf">longest_repeated_substring</span><span class="p">(</span><span class="sh">"</span><span class="s">banana</span><span class="sh">"</span><span class="p">))</span>  <span class="c1"># ana
</span></code></pre></div></div>

<p>Kasai algoritmasındaki <code class="language-plaintext highlighter-rouge">common</code> değerinin her adımda tamamen sıfırlanmaması önemlidir. Bir sonraki son eke geçildiğinde ortak önek uzunluğu en fazla bir azalır; böylece tekrar tekrar aynı karakterleri okumaktan kaçınılır.</p>

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

<p>Bu Python uygulamasında sıralama nedeniyle son ek dizisinin kurulması yaklaşık $O(n \log^2 n)$, LCP hesabı ise $O(n)$ sürer. Özel sıralama teknikleriyle toplam süre $O(n \log n)$, gelişmiş yöntemlerle $O(n)$ seviyesine indirilebilir.</p>

<p>Aynı yaklaşım DNA dizilerindeki tekrarları, belgelerdeki kopya bölümleri, sıkıştırılabilir kalıpları ve kod içindeki benzer parçaları bulmak için kullanılabilir. Kısacası son ek dizisi, metni yalnızca sıralamaz; görünmeyen tekrarların yan yana gelmesini sağlayarak problemi kolay bir maksimum aramasına dönüştürür.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="algoritma" /><category term="son-ek-dizisi" /><category term="metin-işleme" /><category term="python" /><category term="lcp" /><category term="veri-yapıları" /><summary type="html"><![CDATA[Bir metnin içinde en az iki kez geçen en uzun parça hangisidir? İlk bakışta bütün alt dizgileri üretip karşılaştırmak makul görünebilir. Ancak metin büyüdüğünde bu yöntem, samanlıkta iğne ararken önce bütün samanları tek tek numaralandırmaya dönüşür. Son ek dizisi ve LCP dizisi ise tekrarları düzenli, hızlı ve şaşırtıcı derecede zarif biçimde ortaya çıkarır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/en-uzun-tekrar-83.png" /><media:content medium="image" url="https://program.sonsuz.us/img/en-uzun-tekrar-83.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">LZW Sıkıştırma Algoritması: Veriyi Sözlükle Küçültme Sanatı</title><link href="https://program.sonsuz.us/posts/lzw-sikistirma-algoritmasi-veriyi-sozlukle-kucultme-sanati/" rel="alternate" type="text/html" title="LZW Sıkıştırma Algoritması: Veriyi Sözlükle Küçültme Sanatı" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/lzw-sikistirma-algoritmasi-veriyi-sozlukle-kucultme-sanati</id><content type="html" xml:base="https://program.sonsuz.us/posts/lzw-sikistirma-algoritmasi-veriyi-sozlukle-kucultme-sanati/"><![CDATA[<p>Bir metindeki aynı karakter dizilerini tekrar tekrar saklamak yerine onlara kısa kodlar verseydik ne olurdu? Lempel–Ziv–Welch, yani LZW algoritması, tam olarak bu fikirle çalışan kayıpsız bir veri sıkıştırma yöntemidir. Metin, görüntü veya benzeri veriler içindeki tekrar eden kalıpları çalışma sırasında oluşturduğu bir sözlükte toplar. Böylece uzun diziler küçük sayılarla temsil edilir; veri hiçbir bilgi kaybedilmeden daha kompakt hâle gelir.</p>

<p>``</p>

<h2 id="lzwnin-temel-mantığı">LZW’nin temel mantığı</h2>

<p>LZW, Terry Welch tarafından LZ78 yaklaşımının geliştirilmesiyle ortaya çıkarılmıştır. Algoritmanın en güzel taraflarından biri, kodlayıcı ile kod çözücünün sözlüğü verinin içine ayrıca eklemesine gerek bırakmamasıdır. Her iki taraf da aynı başlangıç sözlüğünü kullanır ve veriyi işlerken aynı yeni girdileri üretir.</p>

<p>Başlangıç sözlüğünde genellikle kullanılan alfabenin bütün tek karakterleri bulunur. Örneğin ASCII tabanlı bir uygulamada 0–255 arasındaki kodlar hazırdır. Algoritma girdiyi soldan sağa tarar, sözlükte bulunan en uzun diziyi arar ve bu dizinin kodunu çıktıya ekler. Ardından dizinin sonuna gelen yeni karakterle oluşturulan daha uzun kalıbı sözlüğe kaydeder.</p>

<p>Bu davranışı kabaca şöyle ifade edebiliriz:</p>

\[W' = W + K\]

<p>Burada $W$, sözlükte bulunan mevcut diziyi; $K$, sıradaki karakteri; $W’$ ise sözlüğe eklenmeye aday yeni kalıbı temsil eder. $W’$ sözlükteyse tarama devam eder. Değilse $W$ kodlanır, $W’$ sözlüğe eklenir ve yeni arama $K$ ile başlar.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>LZW</th>
      <th>Sabit uzunluklu kodlama</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tekrarlardan yararlanma</td>
      <td>Evet</td>
      <td>Hayır</td>
    </tr>
    <tr>
      <td>Harici sözlük gereksinimi</td>
      <td>Yok</td>
      <td>Yok</td>
    </tr>
    <tr>
      <td>Bilgi kaybı</td>
      <td>Yok</td>
      <td>Yok</td>
    </tr>
    <tr>
      <td>Değişken kalıpları öğrenme</td>
      <td>Dinamik</td>
      <td>Bulunmaz</td>
    </tr>
    <tr>
      <td>Tekrarsız veride verim</td>
      <td>Düşebilir</td>
      <td>Sabit kalır</td>
    </tr>
  </tbody>
</table>

<h2 id="küçük-bir-örnek">Küçük bir örnek</h2>

<p><code class="language-plaintext highlighter-rouge">ABABABA</code> girdisini düşünelim. Başlangıç sözlüğünde <code class="language-plaintext highlighter-rouge">A</code> ve <code class="language-plaintext highlighter-rouge">B</code> zaten bulunsun. Algoritma önce <code class="language-plaintext highlighter-rouge">A</code> kodunu üretir ve <code class="language-plaintext highlighter-rouge">AB</code> kalıbını sözlüğe ekler. Sonra <code class="language-plaintext highlighter-rouge">B</code> kodlanırken <code class="language-plaintext highlighter-rouge">BA</code> eklenir. Tarama ilerlediğinde <code class="language-plaintext highlighter-rouge">AB</code> artık tek bir sözlük girdisi olarak tanınır. Daha sonra <code class="language-plaintext highlighter-rouge">ABA</code> da öğrenilir. Başlangıçta tek tek görülen karakterler, algoritmanın hafızasında giderek daha büyük parçalara dönüşür.</p>

<p>Sıkıştırma oranı genel olarak şu şekilde hesaplanabilir:</p>

\[R = \frac{\text{Sıkıştırılmış boyut}}{\text{Orijinal boyut}}\]

<p>$R &lt; 1$ olması sıkıştırmanın işe yaradığını gösterir. Ancak veri rastgele veya çok kısa ise sözlük kodları ek yük oluşturabileceğinden LZW her zaman kazanç sağlamaz.</p>

<h2 id="python-ile-lzw-sıkıştırma">Python ile LZW sıkıştırma</h2>

<p>Aşağıdaki fonksiyon, başlangıç sözlüğünü 256 karakterle kurar ve keşfettiği kalıplara artan sayısal kodlar verir:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">lzw_compress</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="n">dictionary</span> <span class="o">=</span> <span class="p">{</span><span class="nf">chr</span><span class="p">(</span><span class="n">i</span><span class="p">):</span> <span class="n">i</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="mi">256</span><span class="p">)}</span>
    <span class="n">next_code</span> <span class="o">=</span> <span class="mi">256</span>
    <span class="n">current</span> <span class="o">=</span> <span class="sh">""</span>
    <span class="n">output</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">text</span><span class="p">:</span>
        <span class="n">candidate</span> <span class="o">=</span> <span class="n">current</span> <span class="o">+</span> <span class="n">char</span>

        <span class="k">if</span> <span class="n">candidate</span> <span class="ow">in</span> <span class="n">dictionary</span><span class="p">:</span>
            <span class="n">current</span> <span class="o">=</span> <span class="n">candidate</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">output</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">dictionary</span><span class="p">[</span><span class="n">current</span><span class="p">])</span>
            <span class="n">dictionary</span><span class="p">[</span><span class="n">candidate</span><span class="p">]</span> <span class="o">=</span> <span class="n">next_code</span>
            <span class="n">next_code</span> <span class="o">+=</span> <span class="mi">1</span>
            <span class="n">current</span> <span class="o">=</span> <span class="n">char</span>

    <span class="k">if</span> <span class="n">current</span><span class="p">:</span>
        <span class="n">output</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">dictionary</span><span class="p">[</span><span class="n">current</span><span class="p">])</span>

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

<span class="nf">print</span><span class="p">(</span><span class="nf">lzw_compress</span><span class="p">(</span><span class="sh">"</span><span class="s">ABABABA</span><span class="sh">"</span><span class="p">))</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">current</code>, sözlükte bulunan en uzun kalıbı tutar. <code class="language-plaintext highlighter-rouge">candidate</code> sözlükte yoksa mevcut kalıbın kodu çıktıya gönderilir ve yeni kalıp öğrenilir. Fonksiyonun ürettiği sayılar doğrudan bit düzeyinde paketlenmediği için bu örnek öğretim amaçlıdır. Gerçek sistemlerde kodlar 9, 10 veya 12 bitlik alanlara yerleştirilerek dosya boyutu gerçekten azaltılır.</p>

<h2 id="nerelerde-kullanılır">Nerelerde kullanılır?</h2>

<p>LZW özellikle GIF görüntü formatında ve bazı TIFF dosyalarında tanınır. Metinlerdeki, çizimlerdeki ve sınırlı renk paletine sahip görüntülerdeki tekrarlar algoritma için oldukça lezzetli lokmalardır. Buna karşılık modern fotoğraflar veya şifrelenmiş veriler daha düzensiz olduğundan sözlüğün büyümesine rağmen yeterli tekrar sunmayabilir.</p>

<p>Sonuç olarak LZW, veriyi önceden analiz etmeden kalıpları öğrenen zarif bir algoritmadır. Bir bakıma okudukça kelime öğrenen ve uzun cümleleri küçük notlarla hatırlayan dijital bir stenograf gibi davranır.</p>

<p><img src="/img/lzw-sikistirma-algoritmasi-76.svg" alt="lzw-sikistirma-algoritmasi-76" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="lzw" /><category term="veri sıkıştırma" /><category term="algoritma" /><category term="python" /><category term="kayıpsız sıkıştırma" /><summary type="html"><![CDATA[Bir metindeki aynı karakter dizilerini tekrar tekrar saklamak yerine onlara kısa kodlar verseydik ne olurdu? Lempel–Ziv–Welch, yani LZW algoritması, tam olarak bu fikirle çalışan kayıpsız bir veri sıkıştırma yöntemidir. Metin, görüntü veya benzeri veriler içindeki tekrar eden kalıpları çalışma sırasında oluşturduğu bir sözlükte toplar. Böylece uzun diziler küçük sayılarla temsil edilir; veri hiçbir bilgi kaybedilmeden daha kompakt hâle gelir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/lzw-sikistirma-algoritmasi-76.png" /><media:content medium="image" url="https://program.sonsuz.us/img/lzw-sikistirma-algoritmasi-76.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Son Ek Dizileri: Metin Aramalarının Sıralı Süper Gücü</title><link href="https://program.sonsuz.us/posts/son-ek-dizileri-metin-aramalarinin-sirali-super-gucu/" rel="alternate" type="text/html" title="Son Ek Dizileri: Metin Aramalarının Sıralı Süper Gücü" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/son-ek-dizileri-metin-aramalarinin-sirali-super-gucu</id><content type="html" xml:base="https://program.sonsuz.us/posts/son-ek-dizileri-metin-aramalarinin-sirali-super-gucu/"><![CDATA[<p>Uzun bir metinde belirli bir kalıbı aramak, samanlıkta iğne bulmaya benzeyebilir. Son ek dizileri, samanları alfabetik biçimde düzenleyerek bu işi şaşırtıcı derecede hızlandırır. Özellikle genom analizi, arama motorları, veri sıkıştırma ve tekrar tespiti gibi alanlarda kullanılan bu yapı, metnin kendisini değiştirmez; yalnızca nereden başlayan son eklerin hangi sırada bulunduğunu saklar.</p>

<p>``</p>

<h2 id="son-ek-nedir">Son ek nedir?</h2>

<p>Bir metnin belirli bir konumundan sonuna kadar uzanan parçaya <strong>son ek</strong> denir. Örneğin <code class="language-plaintext highlighter-rouge">banana</code> metninin son ekleri şöyledir:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: right">Başlangıç indisi</th>
      <th>Son ek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">0</td>
      <td>banana</td>
    </tr>
    <tr>
      <td style="text-align: right">1</td>
      <td>anana</td>
    </tr>
    <tr>
      <td style="text-align: right">2</td>
      <td>nana</td>
    </tr>
    <tr>
      <td style="text-align: right">3</td>
      <td>ana</td>
    </tr>
    <tr>
      <td style="text-align: right">4</td>
      <td>na</td>
    </tr>
    <tr>
      <td style="text-align: right">5</td>
      <td>a</td>
    </tr>
  </tbody>
</table>

<p>Bu son ekleri sözlük sırasına koyduğumuzda <code class="language-plaintext highlighter-rouge">a</code>, <code class="language-plaintext highlighter-rouge">ana</code>, <code class="language-plaintext highlighter-rouge">anana</code>, <code class="language-plaintext highlighter-rouge">banana</code>, <code class="language-plaintext highlighter-rouge">na</code>, <code class="language-plaintext highlighter-rouge">nana</code> sıralamasını elde ederiz. Son ek dizisi, parçaların kendileri yerine başlangıç indislerini tutar:</p>

\[SA = [5, 3, 1, 0, 4, 2]\]

<p>Buradaki temel fikir basittir: Aradığımız kalıpla başlayan bütün son ekler, sıralı listede yan yana bulunur. Böylece metni soldan sağa taramak yerine son ekler üzerinde ikili arama yapabiliriz.</p>

<h2 id="neden-daha-hızlıdır">Neden daha hızlıdır?</h2>

<p>Uzunluğu $n$ olan bir metinde, uzunluğu $m$ olan bir kalıbı klasik yöntemle aramak en kötü durumda $O(nm)$ zaman alabilir. Son ek dizisi hazırsa ikili arama yaklaşık $O(\log n)$ karşılaştırma yapar. Her karşılaştırmada en fazla $m$ karakter incelendiği için sorgu maliyeti:</p>

\[O(m \log n)\]

<p>olur. Yapının hazırlanması ayrıca maliyetlidir; fakat aynı metin üzerinde binlerce sorgu yapılacaksa bu yatırım kısa sürede karşılığını verir.</p>

<table>
  <thead>
    <tr>
      <th>Yöntem</th>
      <th style="text-align: right">Ön işleme</th>
      <th style="text-align: right">Tek sorgu</th>
      <th style="text-align: right">Ek bellek</th>
      <th>Uygun kullanım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Doğrusal arama</td>
      <td style="text-align: right">$O(1)$</td>
      <td style="text-align: right">$O(nm)$</td>
      <td style="text-align: right">$O(1)$</td>
      <td>Az sayıda sorgu</td>
    </tr>
    <tr>
      <td>Son ek dizisi</td>
      <td style="text-align: right">Genellikle $O(n \log n)$</td>
      <td style="text-align: right">$O(m \log n)$</td>
      <td style="text-align: right">$O(n)$</td>
      <td>Çok sayıda sorgu</td>
    </tr>
    <tr>
      <td>Son ek ağacı</td>
      <td style="text-align: right">$O(n)$</td>
      <td style="text-align: right">$O(m)$</td>
      <td style="text-align: right">Yüksek</td>
      <td>En hızlı sorgular</td>
    </tr>
  </tbody>
</table>

<p>Son ek dizisi, son ek ağacına göre daha kompakt olması ve önbellek dostu ardışık bir dizi kullanması nedeniyle pratikte oldukça çekicidir.</p>

<h2 id="python-ile-basit-kurulum">Python ile basit kurulum</h2>

<p>Aşağıdaki eğitim amaçlı uygulama, bütün başlangıç indislerini karşılık gelen son eklere göre sıralar:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">suffix_array</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="c1"># Her indis, text[i:] son ekinin anahtarıyla sıralanır.
</span>    <span class="k">return</span> <span class="nf">sorted</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="nf">len</span><span class="p">(</span><span class="n">text</span><span class="p">)),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">text</span><span class="p">[</span><span class="n">i</span><span class="p">:])</span>

<span class="n">text</span> <span class="o">=</span> <span class="sh">"</span><span class="s">banana</span><span class="sh">"</span>
<span class="n">sa</span> <span class="o">=</span> <span class="nf">suffix_array</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">sa</span><span class="p">)</span>  <span class="c1"># [5, 3, 1, 0, 4, 2]
</span></code></pre></div></div>

<p>Kod oldukça okunaklıdır; ancak <code class="language-plaintext highlighter-rouge">text[i:]</code> işlemi yeni dizgiler oluşturduğu için büyük verilerde pahalıdır. Üretim seviyesindeki algoritmalar, son ekleri doğrudan kopyalamak yerine sıralama derecelerini kullanır. <strong>Prefix doubling</strong> yaklaşımı önce bir karakterlik, ardından 2, 4, 8 karakterlik önekleri karşılaştırır ve yaklaşık $O(n \log n)$ sürede çalışır.</p>

<h2 id="kalıp-arama">Kalıp arama</h2>

<p>Python’ın <code class="language-plaintext highlighter-rouge">bisect</code> modülü doğrudan özel karşılaştırıcı kabul etmediğinden, mantığı açıkça gösteren bir ikili arama yazabiliriz:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">find_pattern</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">sa</span><span class="p">,</span> <span class="n">pattern</span><span class="p">):</span>
    <span class="n">left</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="nf">len</span><span class="p">(</span><span class="n">sa</span><span class="p">)</span>

    <span class="k">while</span> <span class="n">left</span> <span class="o">&lt;</span> <span class="n">right</span><span class="p">:</span>
        <span class="n">mid</span> <span class="o">=</span> <span class="p">(</span><span class="n">left</span> <span class="o">+</span> <span class="n">right</span><span class="p">)</span> <span class="o">//</span> <span class="mi">2</span>
        <span class="n">piece</span> <span class="o">=</span> <span class="n">text</span><span class="p">[</span><span class="n">sa</span><span class="p">[</span><span class="n">mid</span><span class="p">]:</span><span class="n">sa</span><span class="p">[</span><span class="n">mid</span><span class="p">]</span> <span class="o">+</span> <span class="nf">len</span><span class="p">(</span><span class="n">pattern</span><span class="p">)]</span>

        <span class="k">if</span> <span class="n">piece</span> <span class="o">&lt;</span> <span class="n">pattern</span><span class="p">:</span>
            <span class="n">left</span> <span class="o">=</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">right</span> <span class="o">=</span> <span class="n">mid</span>

    <span class="n">start</span> <span class="o">=</span> <span class="n">left</span>
    <span class="n">matches</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">while</span> <span class="n">start</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">sa</span><span class="p">)</span> <span class="ow">and</span> <span class="n">text</span><span class="p">.</span><span class="nf">startswith</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">sa</span><span class="p">[</span><span class="n">start</span><span class="p">]):</span>
        <span class="n">matches</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">sa</span><span class="p">[</span><span class="n">start</span><span class="p">])</span>
        <span class="n">start</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="nf">sorted</span><span class="p">(</span><span class="n">matches</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">find_pattern</span><span class="p">(</span><span class="sh">"</span><span class="s">banana</span><span class="sh">"</span><span class="p">,</span> <span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</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="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="sh">"</span><span class="s">ana</span><span class="sh">"</span><span class="p">))</span>
<span class="c1"># [1, 3]
</span></code></pre></div></div>

<p>İkili arama ilk eşleşmenin sınırını bulur; ardından yan yana duran eşleşmeler toplanır. Sonuç sayısı $k$ ise toplam maliyet yaklaşık $O(m \log n + km)$ olur.</p>

<h2 id="lcp-ile-bir-adım-ileri">LCP ile bir adım ileri</h2>

<p>Son ek dizisinin sık kullanılan yardımcısı <strong>LCP dizisidir</strong>. LCP, komşu iki sıralı son ekin en uzun ortak önek uzunluğunu saklar. Örneğin <code class="language-plaintext highlighter-rouge">ana</code> ile <code class="language-plaintext highlighter-rouge">anana</code> arasındaki ortak önek uzunluğu 3’tür. En büyük LCP değeri, metindeki en uzun tekrarlanan parçayı gösterebilir.</p>

<p>Kısacası son ek dizisi, “bütün parçaları sakla” yaklaşımı değil, “başlangıçları akıllıca sırala” yaklaşımıdır. Metin sabit, sorgu sayısı fazlaysa bu mütevazı indis listesi gerçek bir arama roketine dönüşür.</p>

<p><img src="/img/son-ek-dizileri-15.svg" alt="son-ek-dizileri-15" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="son ek dizisi" /><category term="dizgi algoritmaları" /><category term="veri yapıları" /><category term="ikili arama" /><category term="python" /><category term="algoritma" /><summary type="html"><![CDATA[Uzun bir metinde belirli bir kalıbı aramak, samanlıkta iğne bulmaya benzeyebilir. Son ek dizileri, samanları alfabetik biçimde düzenleyerek bu işi şaşırtıcı derecede hızlandırır. Özellikle genom analizi, arama motorları, veri sıkıştırma ve tekrar tespiti gibi alanlarda kullanılan bu yapı, metnin kendisini değiştirmez; yalnızca nereden başlayan son eklerin hangi sırada bulunduğunu saklar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/son-ek-dizileri-15.png" /><media:content medium="image" url="https://program.sonsuz.us/img/son-ek-dizileri-15.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Zamanı İleri Sar: Olay-Güdümlü Benzetimle Parçacık Çarpışmaları</title><link href="https://program.sonsuz.us/posts/zamani-ileri-sar-olay-gudumlu-benzetimle-parcacik-carpismalari/" rel="alternate" type="text/html" title="Zamanı İleri Sar: Olay-Güdümlü Benzetimle Parçacık Çarpışmaları" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/zamani-ileri-sar-olay-gudumlu-benzetimle-parcacik-carpismalari</id><content type="html" xml:base="https://program.sonsuz.us/posts/zamani-ileri-sar-olay-gudumlu-benzetimle-parcacik-carpismalari/"><![CDATA[<p>Bir bilardo masasındaki topları simüle ettiğimizi düşünelim. Zamanı milisaniyelik dilimlere ayırıp her adımda bütün topların konumunu güncelleyebiliriz. Ancak toplar çoğu zaman yalnızca düz bir çizgide ilerler; asıl ilginç değişimler çarpışma anlarında gerçekleşir. Olay-güdümlü benzetim, boş geçen zaman adımlarını hesaplamak yerine doğrudan bir sonraki önemli olaya sıçrayarak işlem yapar.</p>

<p><img src="/img/zamani-ileri-sar-97.svg" alt="zamani-ileri-sar-97" /></p>

<p>``</p>

<h2 id="zaman-adımlı-ve-olay-güdümlü-yaklaşım">Zaman adımlı ve olay-güdümlü yaklaşım</h2>

<p>Geleneksel zaman adımlı benzetimde saat, sabit bir $\Delta t$ miktarıyla ilerletilir. Bir parçacığın yeni konumu yaklaşık olarak</p>

\[\vec{x}(t + \Delta t) = \vec{x}(t) + \vec{v}(t)\Delta t\]

<p>şeklinde hesaplanır. $\Delta t$ küçüldükçe sonuç genellikle daha hassas olur, fakat işlem sayısı artar. Üstelik hızlı parçacıklar büyük bir zaman adımında birbirlerinin içinden geçebilir. Buna tünelleme problemi denir.</p>

<p>Olay-güdümlü yaklaşımda ise sistemin gelecekteki çarpışma zamanları hesaplanır. Benzetim saati en yakın olaya taşınır, ilgili parçacıkların durumları değiştirilir ve bu değişiklikten etkilenen yeni olaylar planlanır.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Zaman adımlı benzetim</th>
      <th>Olay-güdümlü benzetim</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Zamanın ilerlemesi</td>
      <td>Sabit $\Delta t$</td>
      <td>Bir sonraki olay zamanı</td>
    </tr>
    <tr>
      <td>Boş hareket dönemleri</td>
      <td>Tek tek hesaplanır</td>
      <td>Doğrudan atlanır</td>
    </tr>
    <tr>
      <td>Çarpışma hassasiyeti</td>
      <td>Adım boyuna bağlıdır</td>
      <td>Analitik zamana dayanır</td>
    </tr>
    <tr>
      <td>Uygulama kolaylığı</td>
      <td>Genellikle daha kolay</td>
      <td>Olay yönetimi daha karmaşıktır</td>
    </tr>
    <tr>
      <td>Uygun sistemler</td>
      <td>Sürekli kuvvetler, akışkanlar</td>
      <td>Sert küreler, kuyruklar, ağ paketleri</td>
    </tr>
  </tbody>
</table>

<h2 id="çarpışma-zamanı-nasıl-bulunur">Çarpışma zamanı nasıl bulunur?</h2>

<p>Yarıçapları $r_1$ ve $r_2$ olan iki parçacığın konum farkını $\Delta\vec{x}$, hız farkını da $\Delta\vec{v}$ olarak tanımlayalım. Çarpışma anında merkezler arasındaki uzaklık, yarıçapların toplamına eşittir:</p>

\[\left\vert \Delta\vec{x} + \Delta\vec{v}t\right\vert  = r_1 + r_2\]

<p>Denklemin karesi alındığında $at^2+bt+c=0$ biçiminde ikinci dereceden bir denklem elde edilir. Pozitif ve en küçük kök, gelecekteki ilk çarpışma zamanıdır. Diskler birbirinden uzaklaşıyorsa veya diskriminant negatifse çarpışma olayı oluşturulmaz.</p>

<p>Çarpışma gerçekleştiğinde hızlar momentum ve enerji korunumu kullanılarak güncellenir. Toplam momentum için</p>

\[m_1\vec{v}_1 + m_2\vec{v}_2 = m_1\vec{v}'_1 + m_2\vec{v}'_2\]

<p>olmalıdır. Esnek çarpışmada kinetik enerji de korunur. Böylece benzetim yalnızca görsel olarak değil, fiziksel olarak da tutarlı kalır.</p>

<h2 id="öncelik-kuyruğu-benzetimin-ajandası">Öncelik kuyruğu: Benzetimin ajandası</h2>

<p>Gelecekteki olaylar, olay zamanına göre sıralanan bir <strong>öncelik kuyruğunda</strong> tutulur. En yakın olay kuyruğun başından alınır. Python’daki <code class="language-plaintext highlighter-rouge">heapq</code>, bu iş için uygun bir min-heap sağlar.</p>

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

<span class="n">queue</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">current_time</span> <span class="o">=</span> <span class="mf">0.0</span>

<span class="k">def</span> <span class="nf">schedule</span><span class="p">(</span><span class="n">time</span><span class="p">,</span> <span class="n">kind</span><span class="p">,</span> <span class="n">particles</span><span class="p">):</span>
    <span class="c1"># Olayları gerçekleşme zamanına göre kuyruğa ekler.
</span>    <span class="n">heapq</span><span class="p">.</span><span class="nf">heappush</span><span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="p">(</span><span class="n">time</span><span class="p">,</span> <span class="n">kind</span><span class="p">,</span> <span class="n">particles</span><span class="p">))</span>

<span class="nf">schedule</span><span class="p">(</span><span class="mf">1.25</span><span class="p">,</span> <span class="sh">"</span><span class="s">collision</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">3</span><span class="p">))</span>
<span class="nf">schedule</span><span class="p">(</span><span class="mf">0.80</span><span class="p">,</span> <span class="sh">"</span><span class="s">wall</span><span class="sh">"</span><span class="p">,</span> <span class="p">(</span><span class="mi">2</span><span class="p">,))</span>

<span class="k">while</span> <span class="n">queue</span><span class="p">:</span>
    <span class="n">event_time</span><span class="p">,</span> <span class="n">kind</span><span class="p">,</span> <span class="n">particles</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">queue</span><span class="p">)</span>
    <span class="n">current_time</span> <span class="o">=</span> <span class="n">event_time</span>

    <span class="k">if</span> <span class="n">kind</span> <span class="o">==</span> <span class="sh">"</span><span class="s">collision</span><span class="sh">"</span><span class="p">:</span>
        <span class="nf">resolve_collision</span><span class="p">(</span><span class="o">*</span><span class="n">particles</span><span class="p">)</span>
    <span class="k">elif</span> <span class="n">kind</span> <span class="o">==</span> <span class="sh">"</span><span class="s">wall</span><span class="sh">"</span><span class="p">:</span>
        <span class="nf">reflect_from_wall</span><span class="p">(</span><span class="o">*</span><span class="n">particles</span><span class="p">)</span>

    <span class="nf">predict_new_events</span><span class="p">(</span><span class="n">particles</span><span class="p">,</span> <span class="n">current_time</span><span class="p">)</span>
</code></pre></div></div>

<p>Kod, zamanı küçük adımlarla artırmaz; saati doğrudan <code class="language-plaintext highlighter-rouge">event_time</code> değerine taşır. Olay işlendikten sonra yalnızca etkilenen parçacıklarla ilgili tahminlerin yenilenmesi önemli bir optimizasyondur.</p>

<h2 id="geçersiz-olaylar-ve-pratik-zorluklar">Geçersiz olaylar ve pratik zorluklar</h2>

<p>Bir parçacık için önceden hesaplanan olay, araya başka bir çarpışma girdiğinde geçersiz olabilir. Her parçacıkta bir çarpışma sayacı tutularak olay oluşturulurken sayaç değerleri kaydedilebilir. Olay işlenmeden önce değerler karşılaştırılır; uyuşmuyorsa eski olay çöpe atılır.</p>

<p>Olay-güdümlü benzetim her problem için sihirli değnek değildir. Yerçekimi veya sürtünme gibi sürekli etkiler baskınsa olay zamanlarını analitik biçimde bulmak zorlaşır. Buna karşılık seyrek ve ani değişimlerin bulunduğu sistemlerde, zamanı adımlamak yerine olaydan olaya zıplamak hem daha hızlı hem de daha hassas bir dijital evren kurar.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="olay-güdümlü benzetim" /><category term="simülasyon" /><category term="algoritma" /><category term="python" /><category term="fizik" /><category term="öncelik kuyruğu" /><summary type="html"><![CDATA[Bir bilardo masasındaki topları simüle ettiğimizi düşünelim. Zamanı milisaniyelik dilimlere ayırıp her adımda bütün topların konumunu güncelleyebiliriz. Ancak toplar çoğu zaman yalnızca düz bir çizgide ilerler; asıl ilginç değişimler çarpışma anlarında gerçekleşir. Olay-güdümlü benzetim, boş geçen zaman adımlarını hesaplamak yerine doğrudan bir sonraki önemli olaya sıçrayarak işlem yapar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/zamani-ileri-sar-97.png" /><media:content medium="image" url="https://program.sonsuz.us/img/zamani-ileri-sar-97.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><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></feed>