<?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-15T12:05:54+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">C Temelleri: Tarihten Derleme Modeline Sistem Programlamanın Alfabesi</title><link href="https://program.sonsuz.us/posts/c-temelleri-tarihten-derleme-modeline-sistem-programlamanin-alfabesi/" rel="alternate" type="text/html" title="C Temelleri: Tarihten Derleme Modeline Sistem Programlamanın Alfabesi" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/c-temelleri-tarihten-derleme-modeline-sistem-programlamanin-alfabesi</id><content type="html" xml:base="https://program.sonsuz.us/posts/c-temelleri-tarihten-derleme-modeline-sistem-programlamanin-alfabesi/"><![CDATA[<p>C, işletim sistemlerinden gömülü cihazlara kadar sayısız teknolojinin görünmeyen motorudur. Sözdizimi ilk bakışta sade görünse de bellek, işlemci ve program arasındaki ilişkiyi doğrudan hissettirmesi onu öğretici ve güçlü kılar. C öğrenmek yalnızca yeni bir dil öğrenmek değil, bilgisayarın perde arkasına küçük ama oldukça aydınlatıcı bir pencere açmaktır.
``</p>
<h2 id="kısa-bir-tarih-yolculuğu">Kısa Bir Tarih Yolculuğu</h2>

<p>C’nin hikâyesi 1970’lerin başında Bell Laboratuvarları’nda başladı. Dennis Ritchie, Ken Thompson’ın geliştirdiği B dilinden esinlenerek daha güçlü ve taşınabilir bir dil tasarladı. Temel amaç, Unix işletim sistemini donanıma bağımlı Assembly kodları yerine daha üst seviyeli bir dille geliştirmekti.</p>

<p>Bu tercih büyük bir dönüşüm yarattı: Unix farklı bilgisayarlara daha kolay taşınırken C de sistem programlamanın ortak dili hâline geldi. Brian Kernighan ve Dennis Ritchie’nin 1978’de yayımladığı kitap, dilin ilk yaygın başvuru kaynağı oldu. Ardından ANSI C ya da C89 standardı geldi; C99, C11, C17 ve C23 sürümleri ise dili modern ihtiyaçlara göre geliştirdi.</p>

<table>
  <thead>
    <tr>
      <th>Dönem</th>
      <th>Gelişme</th>
      <th>Önemi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1972</td>
      <td>C’nin ilk sürümü</td>
      <td>Unix geliştirmede kullanıldı</td>
    </tr>
    <tr>
      <td>1978</td>
      <td>K&amp;R kitabı</td>
      <td>Dilin fiilî tanımı yayıldı</td>
    </tr>
    <tr>
      <td>1989</td>
      <td>ANSI C (C89)</td>
      <td>Taşınabilir bir standart oluştu</td>
    </tr>
    <tr>
      <td>1999</td>
      <td>C99</td>
      <td>Yeni veri türleri ve sözdizimi eklendi</td>
    </tr>
    <tr>
      <td>2011–2023</td>
      <td>C11, C17, C23</td>
      <td>Güvenlik ve modernleştirme çalışmaları yapıldı</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/c-temelleri-tarihten-76.svg" alt="c-temelleri-tarihten-76" /></p>

<h2 id="bir-c-programının-anatomisi">Bir C Programının Anatomisi</h2>

<p>C programları fonksiyonlardan oluşur ve yürütme genellikle <code class="language-plaintext highlighter-rouge">main</code> fonksiyonundan başlar. Kütüphaneler başlık dosyalarıyla programa tanıtılır. Değişkenler veriyi, ifadeler hesaplamayı, kontrol yapıları ise programın kararlarını temsil eder.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">kare</span><span class="p">(</span><span class="kt">int</span> <span class="n">sayi</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">sayi</span> <span class="o">*</span> <span class="n">sayi</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">deger</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">sonuc</span> <span class="o">=</span> <span class="n">kare</span><span class="p">(</span><span class="n">deger</span><span class="p">);</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"%d sayısının karesi: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">deger</span><span class="p">,</span> <span class="n">sonuc</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">#include &lt;stdio.h&gt;</code> standart giriş-çıkış araçlarını bildirir. <code class="language-plaintext highlighter-rouge">kare</code> fonksiyonu aldığı tam sayıyı kendisiyle çarpar. Matematiksel olarak işlem</p>

\[f(x)=x^2\]

<p>şeklinde gösterilebilir. <code class="language-plaintext highlighter-rouge">main</code>, değişkenleri oluşturur, fonksiyonu çağırır ve sonucu <code class="language-plaintext highlighter-rouge">printf</code> ile ekrana yazar. <code class="language-plaintext highlighter-rouge">return 0</code> ifadesi de programın başarıyla tamamlandığını işletim sistemine bildirir.</p>

<p>C’de tür bilgisi önemlidir. Örneğin <code class="language-plaintext highlighter-rouge">int</code> tam sayıları, <code class="language-plaintext highlighter-rouge">char</code> karakterleri, <code class="language-plaintext highlighter-rouge">float</code> ve <code class="language-plaintext highlighter-rouge">double</code> ondalıklı değerleri saklar. Bir dizinin bellekte kapladığı yaklaşık alan şu ilişkiyle düşünülebilir:</p>

\[Bellek = Eleman\ Sayısı \times sizeof(Tür)\]

<p>Bu nedenle C, programcıya hem güç hem de sorumluluk verir; yanlış sınır kullanımı bellek hatalarına yol açabilir.</p>

<h2 id="kaynak-kod-nasıl-çalışan-programa-dönüşür">Kaynak Kod Nasıl Çalışan Programa Dönüşür?</h2>

<p>C çoğunlukla derlenen bir dildir. Yazdığımız kaynak kod işlemci tarafından doğrudan anlaşılmaz. Dönüşüm zinciri genel olarak şöyledir:</p>

\[Kaynak \rightarrow Ön\ İşleme \rightarrow Derleme \rightarrow Assembly \rightarrow Nesne\ Dosyası \rightarrow Bağlama\]

<table>
  <thead>
    <tr>
      <th>Aşama</th>
      <th>Görevi</th>
      <th>Tipik çıktı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Ön işleme</td>
      <td><code class="language-plaintext highlighter-rouge">#include</code> ve makroları işler</td>
      <td>Genişletilmiş kaynak</td>
    </tr>
    <tr>
      <td>Derleme</td>
      <td>C kodunu düşük seviyeli yapıya çevirir</td>
      <td>Assembly kodu</td>
    </tr>
    <tr>
      <td>Assembler</td>
      <td>Assembly komutlarını makine koduna dönüştürür</td>
      <td>Nesne dosyası</td>
    </tr>
    <tr>
      <td>Bağlama</td>
      <td>Kütüphane ve nesne dosyalarını birleştirir</td>
      <td>Çalıştırılabilir dosya</td>
    </tr>
  </tbody>
</table>

<p>GCC ile örnek program şöyle derlenebilir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-Wall</span> <span class="nt">-Wextra</span> <span class="nt">-std</span><span class="o">=</span>c17 program.c <span class="nt">-o</span> program
./program
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">-Wall</code> ve <code class="language-plaintext highlighter-rouge">-Wextra</code>, olası sorunlar hakkında uyarılar üretir; <code class="language-plaintext highlighter-rouge">-std=c17</code> kullanılacak standardı seçer. Uyarıları görmezden gelmemek, C dünyasında emniyet kemeri takmaya benzer: Program yine ilerleyebilir ama ilk sert virajda farkı anlarsınız.</p>

<p>C’nin kalıcı etkisi; küçük çalışma zamanı, donanıma yakınlık, taşınabilirlik ve öngörülebilir performanstan gelir. Değişkenler, fonksiyonlar, koşullar ve döngüler temeli oluştururken derleme modelini anlamak hataları çözmeyi kolaylaştırır. Kısacası C, bilgisayara yalnızca ne yapacağını değil, bunu kaynakları nasıl kullanarak yapacağını da anlatmayı öğretir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="c" /><category term="programlama" /><category term="derleyici" /><category term="algoritma" /><category term="sistem programlama" /><summary type="html"><![CDATA[C, işletim sistemlerinden gömülü cihazlara kadar sayısız teknolojinin görünmeyen motorudur. Sözdizimi ilk bakışta sade görünse de bellek, işlemci ve program arasındaki ilişkiyi doğrudan hissettirmesi onu öğretici ve güçlü kılar. C öğrenmek yalnızca yeni bir dil öğrenmek değil, bilgisayarın perde arkasına küçük ama oldukça aydınlatıcı bir pencere açmaktır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/c-temelleri-tarihten-76.png" /><media:content medium="image" url="https://program.sonsuz.us/img/c-temelleri-tarihten-76.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">En Uzun Yol Problemi Neden Bu Kadar Zor?</title><link href="https://program.sonsuz.us/posts/en-uzun-yol-problemi-neden-bu-kadar-zor/" rel="alternate" type="text/html" title="En Uzun Yol Problemi Neden Bu Kadar Zor?" /><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-yol-problemi-neden-bu-kadar-zor</id><content type="html" xml:base="https://program.sonsuz.us/posts/en-uzun-yol-problemi-neden-bu-kadar-zor/"><![CDATA[<p>Bir şehirden diğerine giderken navigasyon uygulaması en kısa rotayı saniyeler içinde bulabilir. Peki uygulamadan hiçbir kavşağı iki kez ziyaret etmeden mümkün olan en uzun rotayı bulmasını istersek ne olur? Masum görünen bu değişiklik, problemi algoritmalar dünyasının en çetin sınıflarından birine taşır: En Uzun Yol Problemi genel graflarda NP-zordur.
``</p>

<h2 id="önce-yol-kavramını-netleştirelim">Önce “yol” kavramını netleştirelim</h2>

<p>Bir graf $G=(V,E)$, düğümlerden oluşan $V$ kümesi ile bu düğümleri bağlayan $E$ kenar kümesidir. Ağırlıklı bir grafta her kenarın $w(u,v)$ maliyeti bulunur. Bir $P$ yolunun toplam ağırlığı şöyle hesaplanır:</p>

\[w(P)=\sum_{(u,v)\in P} w(u,v)\]

<p>Buradaki kritik ayrıntı, aradığımız yapının <strong>basit yol</strong> olmasıdır; yani hiçbir düğüm birden fazla ziyaret edilemez. Tekrara izin verilseydi pozitif ağırlıklı bir döngünün çevresinde sonsuza kadar dolaşarak yol uzunluğunu sınırsız büyütebilirdik. Dolayısıyla anlamlı optimizasyon problemi, tekrar içermeyen en uzun yolu arar.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>En kısa yol</th>
      <th>En uzun basit yol</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Genel çözüm</td>
      <td>Dijkstra, Bellman-Ford</td>
      <td>Bilinen polinom zamanlı çözüm yok</td>
    </tr>
    <tr>
      <td>Döngü etkisi</td>
      <td>Pozitif döngüler sorun çıkarmaz</td>
      <td>Düğüm tekrarı yoksa seçimleri zorlaştırır</td>
    </tr>
    <tr>
      <td>Açgözlü yaklaşım</td>
      <td>Bazı koşullarda çalışır</td>
      <td>Genellikle yanlış sonuç verir</td>
    </tr>
    <tr>
      <td>Karmaşıklık</td>
      <td>Çoğunlukla polinom</td>
      <td>Genel durumda NP-zor</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/en-uzun-yol-21.svg" alt="en-uzun-yol-21" /></p>

<h2 id="en-kısa-yol-kolayken-en-uzun-yol-neden-zor">En kısa yol kolayken en uzun yol neden zor?</h2>

<p>En kısa yol algoritmaları <strong>optimal alt yapıdan</strong> yararlanır. Bir düğüme ulaşmanın en iyi maliyeti bulunduğunda, özellikle negatif ağırlık yoksa bu karar güvenle kullanılabilir. En uzun basit yolda ise erken seçilen bir kenar, ileride ihtiyaç duyulan önemli bir düğümü tüketebilir. Yerel olarak uzun görünen seçim, küresel olarak kısa bir çıkmaza dönüşebilir.</p>

<p>Örneğin en ağır komşuya gitmeyi seçen açgözlü algoritma, birkaç adım sonra kapanan bir kola sapabilir. Daha hafif başlayan başka bir kol ise grafın neredeyse tamamını dolaşabilir. Algoritmanın bütün olası düğüm sıralamalarını hesaba katması gerekebilir; bu olasılık sayısı üstel biçimde büyür.</p>

<h2 id="hamilton-yolu-bağlantısı">Hamilton Yolu bağlantısı</h2>

<p>Zorluğu göstermenin klasik yolu, <strong>Hamilton Yolu Problemi</strong> ile ilişki kurmaktır. Hamilton yolu, graftaki her düğümü tam bir kez ziyaret eden basit bir yoldur ve bu karar problemi NP-tamdır.</p>

<p>Ağırlıksız bir grafta her kenara $1$ ağırlığını verelim. $\vert V\vert =n$ düğüm varsa Hamilton yolu tam olarak $n-1$ kenar içerir. Şu soruyu sorabiliriz:</p>

\[\text{Uzunluğu en az } n-1 \text{ olan basit bir yol var mı?}\]

<p>Bu soruya cevap verebilen bir en uzun yol algoritması, Hamilton yolu olup olmadığını da belirler. Dönüşüm polinom zamanda yapıldığı için en uzun yol problemi NP-zordur. Ayrıca verilen bir yolun basit olduğunu ve hedef uzunluğa ulaştığını hızlıca doğrulayabildiğimizden karar sürümü NP-tamdır.</p>

<h2 id="her-graf-türünde-umutsuz-muyuz">Her graf türünde umutsuz muyuz?</h2>

<p>Hayır! Graf bir <strong>DAG</strong>, yani yönlendirilmiş döngüsüz graf ise topolojik sıralama sayesinde problem $O(\vert V\vert +\vert E\vert )$ zamanda çözülebilir. Döngü bulunmadığından geçmiş bir düğüme dönme ihtimali yoktur.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">longest_path_dag</span><span class="p">(</span><span class="n">vertices</span><span class="p">,</span> <span class="n">edges</span><span class="p">,</span> <span class="n">order</span><span class="p">,</span> <span class="n">source</span><span class="p">):</span>
    <span class="n">dist</span> <span class="o">=</span> <span class="p">{</span><span class="n">v</span><span class="p">:</span> <span class="nf">float</span><span class="p">(</span><span class="sh">"</span><span class="s">-inf</span><span class="sh">"</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">vertices</span><span class="p">}</span>
    <span class="n">dist</span><span class="p">[</span><span class="n">source</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">for</span> <span class="n">u</span> <span class="ow">in</span> <span class="n">order</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">==</span> <span class="nf">float</span><span class="p">(</span><span class="sh">"</span><span class="s">-inf</span><span class="sh">"</span><span class="p">):</span>
            <span class="k">continue</span>
        <span class="k">for</span> <span class="n">v</span><span class="p">,</span> <span class="n">weight</span> <span class="ow">in</span> <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">]:</span>
            <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">],</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">weight</span><span class="p">)</span>

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

<p>Kod, düğümleri topolojik sırayla işler. <code class="language-plaintext highlighter-rouge">dist[v]</code>, kaynaktan <code class="language-plaintext highlighter-rouge">v</code> düğümüne bulunan en uzun mesafeyi saklar; her kenar yalnızca bir kez gevşetilir. Bu, en kısa yol gevşetmesine benzer, fakat <code class="language-plaintext highlighter-rouge">min</code> yerine <code class="language-plaintext highlighter-rouge">max</code> kullanılır.</p>

<p>Genel graflarda ise kesin çözüm için geri izleme, bitmask dinamik programlama veya dal-sınır yöntemleri kullanılabilir. Büyük örneklerde yaklaşım algoritmaları ve sezgiseller tercih edilir. Kısacası tek kelimelik “en” değişikliği, kolay bir rota probleminden kombinatoryal bir labirente geçmemize yeter!</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="algoritmalar" /><category term="graf teorisi" /><category term="np-zor" /><category term="en uzun yol" /><category term="dinamik programlama" /><summary type="html"><![CDATA[Bir şehirden diğerine giderken navigasyon uygulaması en kısa rotayı saniyeler içinde bulabilir. Peki uygulamadan hiçbir kavşağı iki kez ziyaret etmeden mümkün olan en uzun rotayı bulmasını istersek ne olur? Masum görünen bu değişiklik, problemi algoritmalar dünyasının en çetin sınıflarından birine taşır: En Uzun Yol Problemi genel graflarda NP-zordur.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/en-uzun-yol-21.png" /><media:content medium="image" url="https://program.sonsuz.us/img/en-uzun-yol-21.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">İHA Uçuş Kontrolcüleri Rüzgâra Nasıl Meydan Okur?</title><link href="https://program.sonsuz.us/posts/iha-ucus-kontrolculeri-ruzgara-nasil-meydan-okur/" rel="alternate" type="text/html" title="İHA Uçuş Kontrolcüleri Rüzgâra Nasıl Meydan Okur?" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/iha-ucus-kontrolculeri-ruzgara-nasil-meydan-okur</id><content type="html" xml:base="https://program.sonsuz.us/posts/iha-ucus-kontrolculeri-ruzgara-nasil-meydan-okur/"><![CDATA[<p>Bir drone sakin havada uslu bir robot gibi davranabilir; ancak rüzgâr başladığında işler hızla değişir. Ani yön değişimleri, pervane itkisindeki dengesizlikler ve gövde üzerindeki aerodinamik kuvvetler, İHA’yı hedeflenen konumdan uzaklaştırır. Uçuş kontrolcüsünün görevi bu bozucu etkileri algılamak, uygun motor komutlarını hesaplamak ve araç daha ne olduğunu anlamadan dengeyi yeniden kurmaktır.
``</p>

<h2 id="rüzgâr-neden-bir-bozucudur">Rüzgâr neden bir bozucudur?</h2>

<p>Bir İHA’nın hareketi basitleştirilmiş biçimde Newton’un ikinci yasasıyla açıklanabilir:</p>

\[m\vec{a}=\vec{F}_{itki}+\vec{F}_{yerçekimi}+\vec{F}_{rüzgar}\]

<p>Burada $\vec{F}_{rüzgar}$ kontrolcünün doğrudan yönetemediği dış kuvvettir. Rüzgârın sürükleme kuvveti yaklaşık olarak</p>

\[F_d=\frac{1}{2}\rho C_d A v_r^2\]

<p>ile modellenir. $\rho$ hava yoğunluğu, $C_d$ sürükleme katsayısı, $A$ rüzgâra maruz kalan alan ve $v_r$ bağıl hava hızıdır. Hızın karesi özellikle önemlidir: Rüzgâr iki katına çıktığında sürükleme yaklaşık dört katına çıkabilir. Küçük drone’un neden sert rüzgârda alışveriş poşeti gibi savrulduğu böylece anlaşılır.</p>

<h2 id="kontrol-döngüleri-nasıl-çalışır">Kontrol döngüleri nasıl çalışır?</h2>

<p>Modern uçuş kontrolcüleri genellikle iç içe geçmiş kontrol döngüleri kullanır. En içte açısal hız, onun dışında tutum, daha dışta hız ve konum kontrolü bulunur. İç döngüler yüzlerce veya binlerce hertz hızında çalışırken GPS tabanlı konum döngüsü daha yavaştır.</p>

<table>
  <thead>
    <tr>
      <th>Kontrol katmanı</th>
      <th>Ölçülen büyüklük</th>
      <th>Tipik sensör</th>
      <th>Rüzgâra karşı görevi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Açısal hız</td>
      <td>Roll, pitch, yaw hızı</td>
      <td>Jiroskop</td>
      <td>Ani dönmeleri bastırır</td>
    </tr>
    <tr>
      <td>Tutum</td>
      <td>Gövde açıları</td>
      <td>IMU</td>
      <td>Aracı istenen eğimde tutar</td>
    </tr>
    <tr>
      <td>Hız</td>
      <td>Yatay ve düşey hız</td>
      <td>GPS, optik akış</td>
      <td>Sürüklenmeyi azaltır</td>
    </tr>
    <tr>
      <td>Konum</td>
      <td>Dünya koordinatları</td>
      <td>GPS, GNSS-RTK</td>
      <td>Aracı hedef noktaya döndürür</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/iha-ucus-kontrolculeri-78.svg" alt="iha-ucus-kontrolculeri-78" /></p>

<p>Rüzgâr drone’u sağa sürüklediğinde konum kontrolcüsü sola doğru hız talep eder. Hız kontrolcüsü bu talebi bir eğim açısına dönüştürür; tutum kontrolcüsü de motorların devirlerini değiştirir. Sonuçta drone, rüzgâra doğru hafifçe yatıp konumunu korur.</p>

<h2 id="pid-kontrolünün-rolü">PID kontrolünün rolü</h2>

<p>Yaygın PID kontrol yasası şöyledir:</p>

\[u(t)=K_p e(t)+K_i\int e(t)dt+K_d\frac{de(t)}{dt}\]

<p>$K_p$ mevcut hataya tepki verir, $K_i$ sürekli rüzgârın oluşturduğu kalıcı kaymayı giderir, $K_d$ ise hızlı değişimleri sönümler. Fazla yüksek kazançlar titreşime, düşük kazançlar ise ağır ve yetersiz tepkiye yol açar.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PID</td>
      <td>Basit, hızlı ve ucuz</td>
      <td>Değişen koşullara uyumu sınırlı</td>
    </tr>
    <tr>
      <td>LQR</td>
      <td>Çok değişkenli sistemi birlikte yönetir</td>
      <td>Doğru model gerektirir</td>
    </tr>
    <tr>
      <td>MPC</td>
      <td>Kısıtları ve geleceği hesaba katar</td>
      <td>Yüksek işlem yükü oluşturur</td>
    </tr>
    <tr>
      <td>Adaptif kontrol</td>
      <td>Rüzgâra göre kendini ayarlayabilir</td>
      <td>Tasarımı ve doğrulaması zordur</td>
    </tr>
  </tbody>
</table>

<p>Aşağıdaki örnek, yatay hız hatasından pitch komutu üreten sade bir PID döngüsüdür:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">PID</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">kp</span><span class="p">,</span> <span class="n">ki</span><span class="p">,</span> <span class="n">kd</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">kp</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">ki</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">kd</span> <span class="o">=</span> <span class="n">kp</span><span class="p">,</span> <span class="n">ki</span><span class="p">,</span> <span class="n">kd</span>
        <span class="n">self</span><span class="p">.</span><span class="n">integral</span> <span class="o">=</span> <span class="mf">0.0</span>
        <span class="n">self</span><span class="p">.</span><span class="n">previous_error</span> <span class="o">=</span> <span class="mf">0.0</span>

    <span class="k">def</span> <span class="nf">update</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">measured</span><span class="p">,</span> <span class="n">dt</span><span class="p">):</span>
        <span class="n">error</span> <span class="o">=</span> <span class="n">target</span> <span class="o">-</span> <span class="n">measured</span>
        <span class="n">self</span><span class="p">.</span><span class="n">integral</span> <span class="o">+=</span> <span class="n">error</span> <span class="o">*</span> <span class="n">dt</span>
        <span class="n">derivative</span> <span class="o">=</span> <span class="p">(</span><span class="n">error</span> <span class="o">-</span> <span class="n">self</span><span class="p">.</span><span class="n">previous_error</span><span class="p">)</span> <span class="o">/</span> <span class="n">dt</span>
        <span class="n">self</span><span class="p">.</span><span class="n">previous_error</span> <span class="o">=</span> <span class="n">error</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">kp</span> <span class="o">*</span> <span class="n">error</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">ki</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">integral</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">kd</span> <span class="o">*</span> <span class="n">derivative</span>

<span class="n">pid</span> <span class="o">=</span> <span class="nc">PID</span><span class="p">(</span><span class="mf">0.8</span><span class="p">,</span> <span class="mf">0.15</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">)</span>
<span class="n">pitch_command</span> <span class="o">=</span> <span class="n">pid</span><span class="p">.</span><span class="nf">update</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">measured</span><span class="o">=</span><span class="mf">1.2</span><span class="p">,</span> <span class="n">dt</span><span class="o">=</span><span class="mf">0.01</span><span class="p">)</span>
</code></pre></div></div>

<p>Burada hedef hız sıfırdır; ölçülen pozitif hız rüzgâr kaynaklı sürüklenmeyi temsil eder. Üretilen pitch komutu, drone’un ters yönde kuvvet oluşturmasını sağlar. Gerçek sistemlerde integral taşmasını önleyen sınırlar, çıkış doyumu ve türev filtresi de eklenmelidir.</p>

<h2 id="dayanıklılığı-artıran-unsurlar">Dayanıklılığı artıran unsurlar</h2>

<p>Başarılı rüzgâr dayanıklılığı yalnızca kontrol algoritmasına bağlı değildir. Düşük gürültülü IMU, doğru sensör füzyonu, rijit gövde, yeterli motor rezervi ve dengeli pervaneler birlikte çalışmalıdır. Kalman filtresi; jiroskop, ivmeölçer, barometre ve GPS verilerini birleştirerek daha güvenilir durum tahmini üretir.</p>

<p>Kontrolcü ayrıca motorların maksimum itki sınırını bilmelidir. Rüzgârı yenmek için gereken kuvvet fiziksel kapasiteyi aşarsa dünyanın en akıllı algoritması bile mucize yaratamaz. Bu nedenle dayanıklı bir İHA; iyi modellenmiş, doğru ayarlanmış, simülasyonda sınanmış ve kontrollü saha testleriyle doğrulanmış sistemdir. Kısacası rüzgârla kavga etmek yerine onu ölçer, tahmin eder ve motorlara doğru karşı hamleyi yaptırır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="iha" /><category term="drone" /><category term="uçuş kontrolü" /><category term="pid" /><category term="robotik" /><category term="rüzgar dayanıklılığı" /><summary type="html"><![CDATA[Bir drone sakin havada uslu bir robot gibi davranabilir; ancak rüzgâr başladığında işler hızla değişir. Ani yön değişimleri, pervane itkisindeki dengesizlikler ve gövde üzerindeki aerodinamik kuvvetler, İHA’yı hedeflenen konumdan uzaklaştırır. Uçuş kontrolcüsünün görevi bu bozucu etkileri algılamak, uygun motor komutlarını hesaplamak ve araç daha ne olduğunu anlamadan dengeyi yeniden kurmaktır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/iha-ucus-kontrolculeri-78.png" /><media:content medium="image" url="https://program.sonsuz.us/img/iha-ucus-kontrolculeri-78.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">Problemler Arası İndirgeme: Zor Soruları Tanıdık Problemlere Dönüştürmek</title><link href="https://program.sonsuz.us/posts/problemler-arasi-indirgeme-zor-sorulari-tanidik-problemlere-donusturmek/" rel="alternate" type="text/html" title="Problemler Arası İndirgeme: Zor Soruları Tanıdık Problemlere Dönüştürmek" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/problemler-arasi-indirgeme-zor-sorulari-tanidik-problemlere-donusturmek</id><content type="html" xml:base="https://program.sonsuz.us/posts/problemler-arasi-indirgeme-zor-sorulari-tanidik-problemlere-donusturmek/"><![CDATA[<p>Bir problemi çözerken her zaman sıfırdan algoritma tasarlamak zorunda değiliz. Bazen elimizdeki soruyu, çözümünü bildiğimiz başka bir problemin kılığına sokmak yeterlidir. Bilgisayar biliminde bu yönteme <strong>indirgeme (reduction)</strong> denir. İndirgeme, algoritma tasarımından NP-tamlık ispatlarına kadar pek çok alanda kullanılan güçlü bir düşünme aracıdır.
``</p>

<h2 id="i̇ndirgeme-nedir">İndirgeme nedir?</h2>

<p>Bir $A$ problemini $B$ problemine indirgemek, $A$ probleminin girdilerini $B$ problemine ait girdilere dönüştüren bir yöntem oluşturmaktır. Dönüşümden sonra $B$ için elde edilen cevap, $A$ probleminin cevabını belirlemelidir.</p>

<p>Polinom zamanda gerçekleştirilen indirgeme genellikle şu şekilde gösterilir:</p>

\[A \leq_p B\]

<p>Bu ifade, “$A$, polinom zamanda $B$ problemine indirgenebilir” anlamına gelir. Süreç üç adımdan oluşur:</p>

<ol>
  <li>$A$ problemine ait $x$ girdisini al.</li>
  <li>Polinom zamanda $f(x)$ dönüşümünü uygula.</li>
  <li>$B$ problemini $f(x)$ üzerinde çözerek $A$ için sonucu yorumla.</li>
</ol>

<p>Dönüşümün temel doğruluk koşulu şöyledir:</p>

\[x \in A \iff f(x) \in B\]

<p>Yani özgün örnek “evet” örneğiyse dönüştürülen örnek de “evet” olmalıdır; aynı ilişki “hayır” cevapları için de korunmalıdır.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Görevi</th>
      <th>Kritik nokta</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kaynak problem $A$</td>
      <td>Çözmek istediğimiz problem</td>
      <td>Bilinmeyen veya zor olabilir</td>
    </tr>
    <tr>
      <td>Hedef problem $B$</td>
      <td>Çözümünden yararlandığımız problem</td>
      <td>Algoritması ya da zorluğu bilinir</td>
    </tr>
    <tr>
      <td>Dönüşüm $f$</td>
      <td>Girdiyi yeni biçime çevirir</td>
      <td>Polinom zamanda çalışmalıdır</td>
    </tr>
    <tr>
      <td>Cevap eşlemesi</td>
      <td>Sonucu geri yorumlar</td>
      <td>Evet/hayır yapısını korumalıdır</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/problemler-arasi-indirgeme-42.svg" alt="problemler-arasi-indirgeme-42" /></p>

<h2 id="basit-bir-örnek-yolculuk-problemi">Basit bir örnek: yolculuk problemi</h2>

<p>Bir şehir ağında iki nokta arasında yol bulunup bulunmadığını düşünelim. Şehirleri düğüm, yolları kenar olarak temsil edersek soru doğrudan <strong>graf erişilebilirliği</strong> problemine dönüşür. Harita ayrıntıları artık önemli değildir; elimizde yalnızca bir grafik vardır.</p>

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

<span class="k">def</span> <span class="nf">ulasilabilir_mi</span><span class="p">(</span><span class="n">graf</span><span class="p">,</span> <span class="n">baslangic</span><span class="p">,</span> <span class="n">hedef</span><span class="p">):</span>
    <span class="n">kuyruk</span> <span class="o">=</span> <span class="nf">deque</span><span class="p">([</span><span class="n">baslangic</span><span class="p">])</span>
    <span class="n">ziyaret</span> <span class="o">=</span> <span class="p">{</span><span class="n">baslangic</span><span class="p">}</span>

    <span class="k">while</span> <span class="n">kuyruk</span><span class="p">:</span>
        <span class="n">dugum</span> <span class="o">=</span> <span class="n">kuyruk</span><span class="p">.</span><span class="nf">popleft</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">dugum</span> <span class="o">==</span> <span class="n">hedef</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">True</span>

        <span class="k">for</span> <span class="n">komsu</span> <span class="ow">in</span> <span class="n">graf</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">dugum</span><span class="p">,</span> <span class="p">[]):</span>
            <span class="k">if</span> <span class="n">komsu</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">ziyaret</span><span class="p">:</span>
                <span class="n">ziyaret</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">komsu</span><span class="p">)</span>
                <span class="n">kuyruk</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">komsu</span><span class="p">)</span>

    <span class="k">return</span> <span class="bp">False</span>
</code></pre></div></div>

<p>Bu kod, dönüştürülmüş graf üzerinde <strong>genişlik öncelikli arama</strong> yapar. Karmaşıklığı $O(V+E)$ düzeyindedir; burada $V$ şehir sayısını, $E$ ise yol sayısını temsil eder. Asıl indirgeme, gerçek dünyadaki şehir-yol modelini graf yapısına çevirmektir.</p>

<h2 id="yön-neden-önemlidir">Yön neden önemlidir?</h2>

<p>İndirgemelerde ok yönü sıkça karıştırılır. $A \leq_p B$ yazıyorsa $A$ problemini çözmek için $B$ kullanılır. Dolayısıyla $B$, en az $A$ kadar güçlü veya zor olabilir.</p>

<table>
  <thead>
    <tr>
      <th>Amaç</th>
      <th>Kurulması gereken indirgeme</th>
      <th>Çıkarım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$A$ için algoritma geliştirmek</td>
      <td>$A \leq_p B$</td>
      <td>$B$ hızlıysa $A$ da hızlı çözülebilir</td>
    </tr>
    <tr>
      <td>$B$’nin zor olduğunu göstermek</td>
      <td>$A \leq_p B$</td>
      <td>Zor $A$, $B$’ye aktarılır</td>
    </tr>
    <tr>
      <td>$A$’nın zor olduğunu göstermek</td>
      <td>$B \leq_p A$</td>
      <td>Bilinen zorluk $A$’ya taşınır</td>
    </tr>
  </tbody>
</table>

<p>Örneğin SAT probleminin zor olduğu biliniyorsa ve $SAT \leq_p X$ gösterilebiliyorsa, $X$ probleminin de en az SAT kadar zor olduğu sonucuna ulaşılır. Ancak ters yönde indirgeme yapmak aynı sonucu vermez; matematiksel ok küçük görünse de bütün ispatı ters çevirebilir.</p>

<h2 id="i̇yi-bir-indirgeme-nasıl-kurulur">İyi bir indirgeme nasıl kurulur?</h2>

<p>Önce iki problemin yapısal ortaklıkları bulunmalıdır. Değişkenler düğümlere, kısıtlar kenarlara veya seçimler mantıksal ifadelere karşılık gelebilir. Ardından dönüşümün polinom zamanda çalıştığı ve cevapları iki yönde de koruduğu kanıtlanır.</p>

<p>Kısacası indirgeme, “Bu problemi başka hangi dilde ifade edebilirim?” sorusudur. Doğru hedef seçildiğinde karmaşık bir soru tanıdık bir algoritmayla çözülebilir; bazen de çözüm üretmek yerine problemin neden zor olduğu gösterilir. Bu nedenle indirgeme yalnızca teknik bir ispat yöntemi değil, algoritmik düşünmenin en kullanışlı süper güçlerinden biridir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="algoritmalar" /><category term="indirgeme" /><category term="karmaşıklık" /><category term="np-tamlık" /><category term="bilgisayar-bilimi" /><summary type="html"><![CDATA[Bir problemi çözerken her zaman sıfırdan algoritma tasarlamak zorunda değiliz. Bazen elimizdeki soruyu, çözümünü bildiğimiz başka bir problemin kılığına sokmak yeterlidir. Bilgisayar biliminde bu yönteme indirgeme (reduction) denir. İndirgeme, algoritma tasarımından NP-tamlık ispatlarına kadar pek çok alanda kullanılan güçlü bir düşünme aracıdır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/problemler-arasi-indirgeme-42.png" /><media:content medium="image" url="https://program.sonsuz.us/img/problemler-arasi-indirgeme-42.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">SAT ve NP-Tamlık: Bir Boole Formülü Neden Bu Kadar Önemli?</title><link href="https://program.sonsuz.us/posts/sat-ve-np-tamlik-bir-boole-formulu-neden-bu-kadar-onemli/" rel="alternate" type="text/html" title="SAT ve NP-Tamlık: Bir Boole Formülü Neden Bu Kadar Önemli?" /><published>2026-10-15T00:00:00+00:00</published><updated>2026-10-15T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/sat-ve-np-tamlik-bir-boole-formulu-neden-bu-kadar-onemli</id><content type="html" xml:base="https://program.sonsuz.us/posts/sat-ve-np-tamlik-bir-boole-formulu-neden-bu-kadar-onemli/"><![CDATA[<p>Bir bulmacanın çözümünü kontrol etmek kolayken çözümü sıfırdan bulmak son derece zor olabilir mi? Mantıksal Sağlanabilirlik Problemi, yani SAT, tam olarak bu ayrımın peşine düşer. Basit görünen Boole formüllerinden doğan SAT; algoritma tasarımından donanım doğrulamaya, yapay zekâdan çizelgelemeye kadar uzanan etkisiyle hesaplama karmaşıklığı teorisinin merkezinde yer alır.</p>

<p><img src="/img/sat-ve-np-60.svg" alt="sat-ve-np-60" /></p>

<p>``</p>

<h2 id="sat-problemi-nedir">SAT problemi nedir?</h2>

<p>Bir Boole formülü; <code class="language-plaintext highlighter-rouge">doğru</code> veya <code class="language-plaintext highlighter-rouge">yanlış</code> değerlerini alabilen değişkenlerden ve AND ($\land$), OR ($\lor$), NOT ($\neg$) gibi bağlaçlardan oluşur. SAT problemi şu soruyu sorar:</p>

<blockquote>
  <p>Formülü doğru yapan en az bir değişken ataması var mı?</p>
</blockquote>

<p>Örneğin</p>

\[F=(x \lor y) \land (\neg x \lor z)\]

<p>formülü için $x=1$, $y=0$ ve $z=1$ seçildiğinde iki parantez de doğru olur. Dolayısıyla $F$ sağlanabilirdir. Buna karşılık</p>

\[G=x \land \neg x\]

<p>hiçbir atamayla doğru yapılamaz; bu formül sağlanamazdır.</p>

<p>$n$ değişkenli bir formül için toplam $2^n$ olası atama vardır. Kaba kuvvet algoritması bunların tamamını dener. Bu yaklaşımın çalışma süresi yaklaşık olarak</p>

\[T(n)=O(2^n \cdot \vert F\vert )\]

<p>olur. Üstel büyüme yüzünden birkaç yüz değişken bile bilgisayarı ciddi biçimde terletebilir.</p>

<h2 id="p-np-ve-np-tamlık-bağlantısı">P, NP ve NP-tamlık bağlantısı</h2>

<p>SAT’ın önemini anlamak için temel karmaşıklık sınıflarını karşılaştıralım:</p>

<table>
  <thead>
    <tr>
      <th>Sınıf</th>
      <th>Temel fikir</th>
      <th>SAT ile ilişkisi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>P</td>
      <td>Çözüm polinom zamanda bulunabilir</td>
      <td>SAT’ın P’de olup olmadığı bilinmiyor</td>
    </tr>
    <tr>
      <td>NP</td>
      <td>Verilen çözüm polinom zamanda doğrulanabilir</td>
      <td>Bir atama kolayca kontrol edildiği için SAT, NP’dedir</td>
    </tr>
    <tr>
      <td>NP-zor</td>
      <td>NP’deki her problem buna indirgenebilir</td>
      <td>SAT, NP-zordur</td>
    </tr>
    <tr>
      <td>NP-tam</td>
      <td>Hem NP’de hem NP-zordur</td>
      <td>SAT, ilk kanıtlanan NP-tam problemdir</td>
    </tr>
  </tbody>
</table>

<p>Birisi bize değişken atamasını sertifika olarak verirse formülü doğrusal ya da polinoma yakın sürede değerlendirebiliriz. Zor olan, bu sertifikayı bulmaktır.</p>

<p>1971 tarihli <strong>Cook–Levin Teoremi</strong>, SAT’ın NP-tam olduğunu gösterdi. Teoremin özündeki fikir şudur: NP’deki herhangi bir problemin polinom zamanlı hesaplama adımları, bir Boole formülüyle temsil edilebilir. Oluşturulan formül ancak ve ancak özgün problem örneğinin geçerli bir çözümü varsa sağlanabilir.</p>

<p>Bu dönüşüme <strong>polinom zamanlı indirgeme</strong> denir:</p>

\[A \leq_p SAT\]

<p>Buradaki ifade, $A$ probleminin örneklerini polinom zamanda SAT örneklerine çevirebildiğimizi anlatır. Bu nedenle SAT için polinom zamanlı bir algoritma bulunursa NP’deki bütün problemler polinom zamanda çözülebilir ve $P=NP$ sonucu elde edilir.</p>

<h2 id="cnf-ve-3-sat-neden-sık-kullanılır">CNF ve 3-SAT neden sık kullanılır?</h2>

<p>SAT formülleri çoğunlukla <strong>Konjonktif Normal Form</strong> ile yazılır. CNF, OR ile bağlanan değişmezlerin oluşturduğu tümcelerin AND ile birleştirilmesidir:</p>

\[(x \lor \neg y \lor z) \land (y \lor w) \land (\neg x \lor \neg w)\]

<p>Her tümcede tam üç değişmez bulunan özel sürüme <strong>3-SAT</strong> denir. Kısıtlı görünmesine rağmen 3-SAT da NP-tamdır. Bu düzenli yapı, başka problemlerin SAT’a veya SAT’tan başka problemlere indirgenmesini kolaylaştırır.</p>

<h2 id="küçük-bir-sat-çözücüsü">Küçük bir SAT çözücüsü</h2>

<p>Aşağıdaki Python kodu bütün atamaları deneyerek verilen CNF formülünü çözer. Her tümce <code class="language-plaintext highlighter-rouge">(değişken, negatif_mi)</code> çiftlerinden oluşur:</p>

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

<span class="k">def</span> <span class="nf">solve_sat</span><span class="p">(</span><span class="n">variables</span><span class="p">,</span> <span class="n">clauses</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">values</span> <span class="ow">in</span> <span class="nf">product</span><span class="p">([</span><span class="bp">False</span><span class="p">,</span> <span class="bp">True</span><span class="p">],</span> <span class="n">repeat</span><span class="o">=</span><span class="nf">len</span><span class="p">(</span><span class="n">variables</span><span class="p">)):</span>
        <span class="n">assignment</span> <span class="o">=</span> <span class="nf">dict</span><span class="p">(</span><span class="nf">zip</span><span class="p">(</span><span class="n">variables</span><span class="p">,</span> <span class="n">values</span><span class="p">))</span>

        <span class="k">def</span> <span class="nf">literal_value</span><span class="p">(</span><span class="n">literal</span><span class="p">):</span>
            <span class="n">variable</span><span class="p">,</span> <span class="n">is_negative</span> <span class="o">=</span> <span class="n">literal</span>
            <span class="n">value</span> <span class="o">=</span> <span class="n">assignment</span><span class="p">[</span><span class="n">variable</span><span class="p">]</span>
            <span class="k">return</span> <span class="ow">not</span> <span class="n">value</span> <span class="k">if</span> <span class="n">is_negative</span> <span class="k">else</span> <span class="n">value</span>

        <span class="k">if</span> <span class="nf">all</span><span class="p">(</span><span class="nf">any</span><span class="p">(</span><span class="nf">literal_value</span><span class="p">(</span><span class="n">lit</span><span class="p">)</span> <span class="k">for</span> <span class="n">lit</span> <span class="ow">in</span> <span class="n">clause</span><span class="p">)</span>
               <span class="k">for</span> <span class="n">clause</span> <span class="ow">in</span> <span class="n">clauses</span><span class="p">):</span>
            <span class="k">return</span> <span class="n">assignment</span>
    <span class="k">return</span> <span class="bp">None</span>

<span class="n">clauses</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">[(</span><span class="sh">"</span><span class="s">x</span><span class="sh">"</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">y</span><span class="sh">"</span><span class="p">,</span> <span class="bp">False</span><span class="p">)],</span>
    <span class="p">[(</span><span class="sh">"</span><span class="s">x</span><span class="sh">"</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">z</span><span class="sh">"</span><span class="p">,</span> <span class="bp">False</span><span class="p">)]</span>
<span class="p">]</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">solve_sat</span><span class="p">([</span><span class="sh">"</span><span class="s">x</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">y</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">z</span><span class="sh">"</span><span class="p">],</span> <span class="n">clauses</span><span class="p">))</span>
</code></pre></div></div>

<p>Kod öğretici olsa da üstel sayıda atama dener. Gerçek SAT çözücüleri DPLL, birim yayılımı, geri izleme ve CDCL gibi tekniklerle arama uzayının büyük bölümlerini eler. En kötü durum hâlâ üstel olabilir; ancak modern çözücüler milyonlarca değişken içeren pratik örneklerde şaşırtıcı derecede başarılıdır.</p>

<p>SAT’ın büyüsü burada yatar: Sorusu küçücük, sonuçları devasa! Devre doğrulama, paket bağımlılıkları, Sudoku, görev planlama ve yazılım testi gibi problemler Boole kısıtlarına çevrilebilir. Bu yüzden SAT yalnızca teorik bir bilmece değil, hem $P$ ile $NP$ arasındaki gizemin kapısı hem de güçlü bir mühendislik aracıdır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="sat" /><category term="np-tamlık" /><category term="algoritmalar" /><category term="karmaşıklık-teorisi" /><category term="boole-mantığı" /><category term="python" /><summary type="html"><![CDATA[Bir bulmacanın çözümünü kontrol etmek kolayken çözümü sıfırdan bulmak son derece zor olabilir mi? Mantıksal Sağlanabilirlik Problemi, yani SAT, tam olarak bu ayrımın peşine düşer. Basit görünen Boole formüllerinden doğan SAT; algoritma tasarımından donanım doğrulamaya, yapay zekâdan çizelgelemeye kadar uzanan etkisiyle hesaplama karmaşıklığı teorisinin merkezinde yer alır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/sat-ve-np-60.png" /><media:content medium="image" url="https://program.sonsuz.us/img/sat-ve-np-60.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></feed>