Bölüm 2: Diziler

Veri Yapıları
Dizi kavramıJava'da dizilerStack ve heap Dizi algoritmalarıÇok boyutlu dizilerKarmaşıklıkSıralama
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Dizi modeli

Dizilerin bellekteki yerleşimini ve indeksleme mantığını açıklamak.

Java kullanımı

Tek ve çok boyutlu dizileri doğru biçimde tanımlayıp kullanmak.

Algoritmalar

Arama, ekleme, silme ve sıralama işlemlerini diziler üzerinde uygulamak.

Maliyet analizi

Dizi işlemlerinin zaman ve alan maliyetlerini karşılaştırmak.

Temel Kavramlar

Diziler (Arrays)

  • Aynı türden birden çok veriyi tek bir isim altında, düzenli olarak saklar.
  • Boyutu dizi oluşturulurken belirlenir ve sonradan değiştirilemez.
  • Öğeler bellekte ardışık (contiguous) yuvalarda, yan yana tutulur.
  • Öğelerin değerleri her zaman güncellenebilir; "ekleme/silme" ise öğeleri kaydırmak demektir.
  • Matris, resim (pikseller) ve ses (örnekler) gibi verileri temsil etmek için kullanılır.
indis eleman 13 0 -1 1 4 2 2 3 7 4 dizi.length = 5 · ilk indis 0 · son indis 4

Temel Kavramlar

Dizi Kullanımı: İndisle Erişim

  • Dizi elemanlarına indis (index) numarasıyla erişilir: diziAdi[indis].
  • İlk elemanın indisi 0, son elemanınki length − 1'dir.
  • Öğeler ardışık ve eşit boyutlu olduğundan her öğenin adresi tek bir çarpma ve toplamayla hesaplanır.
Bir hücreye tıkla: üst sıra indis, alt sıra değer.
int[] dizi = {7, 2, 9, 5, 1};
int ilkEleman = dizi[0];   // 7
int sonEleman = dizi[dizi.length - 1];   // 1

Temel Kavramlar

Dizi Türleri

Tek boyutlu
Elemanlar tek bir satırda saklanır.int[] a = new int[5];
İki boyutlu
Elemanlar satır ve sütunlarda saklanır (matris).int[][] m = new int[3][3];
Çok boyutlu
Daha karmaşık düzenler: ör. zaman × satır × sütun.int[][][] k = new int[3][3][3];

Temel Kavramlar

Diziler: Avantajlar ve Dezavantajlar

Avantajları

  • İndisle doğrudan, hızlı erişim: O(1).
  • Verileri gruplar ve eklenme sırasını korur.
  • Hem ilkel tipleri (int, char…) hem nesneleri tutabilir.
  • Ardışık bellek: ek referans yükü yok, önbellek (cache) dostu.

Dezavantajları

  • Sabit boyutludur; dolunca büyütülemez, yenisi oluşturulup kopyalanır.
  • Araya ekleme ve silme öğe kaydırmayı gerektirir: O(n).
  • Kullanılmayan kapasite boşa gider.
  • Dizinin kendi metodu yoktur; sıralama, arama vb. için java.util.Arrays kullanılır.
Java dizileri kovaryanttır (covariant): bu hem esneklik hem de bir tür güvenliği açığı getirir → sonraki slayt.

Temel Kavramlar

Dizi Kovaryansı ve ArrayStoreException

  • String, Object'in alt türü olduğundan String[] da Object[]'in alt türü sayılır.
  • Böylece Object[] alan tek bir metot her referans dizisiyle çalışır.
  • Bedeli: yanlış türde atama derleme zamanında değil, çalışma zamanında yakalanır.
String[] isimler = {"Ali", "Ayşe"};
Object[] nesneler = isimler;   // derlenir: String[] bir Object[]'dir
nesneler[0] = 42;              // derlenir, ama çalışırken ArrayStoreException!
EsneklikGenel amaçlı metotlar yazılabilir.static void yazdir(Object[] a)
KarşılaştırmaJenerik (generic) listeler kovaryant değildir; hata derleme sırasında yakalanır.List<Object> l = new ArrayList<String>(); // hata

Java'da Diziler

Dizi Tanımlama

VeriTipi[] diziAdi = new VeriTipi[diziBoyutu];
VeriTipiDizide saklanacak verilerin türü.int, double, String…
diziAdiDiziyi gösteren referans değişkenin adı.sayilar
diziBoyutuEleman sayısı; çalışma zamanında hesaplanabilir.5, n, 2 * n
int[] sayilar = new int[5];
// → [0, 0, 0, 0, 0]

new ile oluşturulan dizinin her elemanı, türünün varsayılan değerini alır.

TürVarsayılan değer
int, long…0
double0.0
booleanfalse
char'\u0000'
nesne (String…)null

Java'da Diziler

Erişim, İlklendirme ve length

İlklendirmeİlklendirici (initializer) listesi başlangıç değerlerini atar; boyut yazılmaz, öğe sayısı boyutu belirler.
Erişimİndisler 0'dan başlar. Okuma ve yazma aynı sözdizimiyle yapılır.
lengthDizinin eleman sayısını verir. Metot değil alandır: parantez yok.
int[] sayilar = {10, 20, 30, 40, 50};   // 5 ilklendirici → boyut 5
int ilkEleman    = sayilar[0];         // 10
int ikinciEleman = sayilar[1];         // 20
sayilar[4] = 55;                         // son eleman güncellendi
int diziBoyutu   = sayilar.length;     // 5

sayilar = new int[] {1, 2, 3};          // sonradan atamada new int[] gerekir
int[] hatali = new int[3] {1, 2, 3};   // derleme hatası: boyut + liste

Java'da Diziler

Örnek Kod: Tanımla, Doldur, Yazdır

public class DiziOrnegi {
    public static void main(String[] args) {
        int[] sayilar = new int[5];            // 5 elemanlı dizi
        for (int i = 0; i < sayilar.length; i++)
            sayilar[i] = (i + 1) * 10;              // 10, 20, 30, 40, 50

        System.out.println("Dizinin birinci elemanı: " + sayilar[0]);
        System.out.println("Dizinin üçüncü elemanı: " + sayilar[2]);

        System.out.print("Dizi Elemanları: ");
        for (int x : sayilar)                       // for-each: indis gerekmiyorsa
            System.out.print(x + " ");
    }
}
Dizinin birinci elemanı: 10
Dizinin üçüncü elemanı: 30
Dizi Elemanları: 10 20 30 40 50

Beş ayrı sayilar[k] = … ataması yerine döngü kullanmak, boyut değişse de doğru çalışır. Döngü sınırı her zaman i < sayilar.length.

Java'da Diziler

Dizi Kopyalama: Referans mı, Kopya mı?

  • Java'da diziler nesnedir; değişken yalnızca diziye bir referans tutar.
  • = işleci referansı kopyalar, diziyi değil.
  • Öğeleri kopyalamak için Arrays.copyOf, dizi.clone() veya System.arraycopy.
int[] dizi = {1, 2, 3, 4, 5};
int[] referans = dizi;   // aynı nesne
int[] kopya =
    Arrays.copyOf(dizi, dizi.length);
referans[0] = 99;
dizi referans 1 2 3 4 5 heap

referans = dizi: yalnızca adres kopyalanır; iki değişken aynı diziyi gösterir.

dizi referans 1 2 3 4 5 heap kopya 1 2 3 4 5 ayrı nesne

Arrays.copyOf(dizi, dizi.length): heap'te yeni bir dizi oluşturulur, öğeler tek tek kopyalanır.

dizi referans 99 2 3 4 5 heap kopya 1 2 3 4 5 ayrı nesne

referans[0] = 99 → dizi[0] da 99 olur; kopya[0] hâlâ 1.

Java'da Diziler

Varargs (Değişken Sayıda Argüman)

  • tip... ad yazımı, metodun istediği sayıda argüman almasını sağlar.
  • Metodun içinde parametre sıradan bir dizidir.
  • Yalnızca son parametre varargs olabilir; metot başına bir tane.
  • Hazır bir dizi de doğrudan geçirilebilir.
static double ortalama(double... dizi) {
    if (dizi.length == 0)
        return Double.NaN;  // tanımsız
    var toplam = 0.0;
    for (var eleman : dizi)
        toplam += eleman;
    return toplam / dizi.length;
}
Çağrıdizi.lengthSonuç
ortalama(4, 8, 15)39.0
ortalama(7.5)17.5
ortalama()0NaN
ortalama(new double[] {1, 2})21.5

Java'da Diziler

Bellekte Diziler: Stack ve Heap

  • Stack (yığın belleği): yerel değişkenler ve metot çağrıları. Metot bitince çerçevesi otomatik silinir.
  • Heap: new ile oluşturulan tüm nesneler. Java'da her dizi heap'tedir; stack'te yalnızca referansı durur.
  • Heap'i çöp toplayıcı (garbage collector, GC) yönetir: hiçbir referansın göstermediği nesneleri kendisi serbest bırakır.
Stack main() çerçevesi sayilar Heap int[] nesnesi · length = 5 10 20 30 40 50 GC tarafından otomatik yönetilir
StackHeap
Ne tutulur?yerel değişkenler, referanslar, çağrı çerçevelerinesneler, diziler
Ömürmetot bitene kadarerişilebilir olduğu sürece
Yönetimotomatik (çağrı / dönüş)otomatik (GC)

Java'da Diziler

"Statik" ve "Dinamik" Diziler: C ve Java

C / C++Java
Stack'te diziint a[10]; — boyut derleme zamanında sabit, fonksiyon bitince yok olurYok: tüm diziler heap'te
Heap'te dizimalloc / new int[n]new int[n] (ilklendirici listesi de heap'te)
Boyutheap'te çalışma zamanında belirlenirçalışma zamanında belirlenir, sonra sabit
Serbest bırakmaprogramcı: free / delete[]GC otomatik; dizi = null yalnızca referansı koparır
int[] dinamikDizi = new int[n];   // heap'te n elemanlık yer ayrılır
dinamikDizi = null;               // başka referans yoksa GC toplayabilir
System.gc() yalnızca bir istektir, toplamayı garanti etmez; Java'da delete yoktur. "Dinamik dizi" adı, dolunca kendiliğinden büyüyen dizi (ArrayList) için de kullanılır → Bölüm 6.

Java'da Diziler

İndis Sınır Dışı Hatası

  • Geçerli aralığın dışındaki bir indise erişilirse Java ArrayIndexOutOfBoundsException fırlatır (IndexOutOfBoundsException'ın alt sınıfı).
  • Yakalanmazsa program sonlanır. Java her erişimi denetler; C'de bu denetim yoktur ve sessizce başka belleğe yazılır.
0 0 0 1 0 2 0 3 0 4 ? 5 geçerli indisler: 0 … length − 1 dizi[5] ✗
int[] dizi = new int[5];
dizi[5] = 1;  // Index 5 out of
              // bounds for length 5
dizi[-1] = 1; // aynı hata
if (index >= 0
        && index < dizi.length) {
    int deger = dizi[index];
} else {
    System.out.println("Geçersiz");
}

Dizi Algoritmaları

Diziyi Kullanıcıdan Okuma

Ortalama, ortanca ve mod programlarının üçü de aynı giriş koduyla başlıyor; tek bir yardımcı metotta toplayalım:

import java.util.Scanner;

static double[] diziOku(Scanner scanner) {
    System.out.print("Dizi boyutunu girin: ");
    int boyut = scanner.nextInt();
    double[] dizi = new double[boyut];  // boyut çalışma zamanında
    for (int i = 0; i < boyut; i++) {
        System.out.print((i + 1) + ". elemanı girin: "); // 1'den say
        dizi[i] = scanner.nextDouble();
    }
    return dizi;
}
OrtalamaToplam / eleman sayısıO(n)
Ortanca (median)Sıralı dizinin ortasıO(n log n)
ModEn sık tekrar eden değerO(n log n)

Dizi Algoritmaları

Ortalama Hesaplama

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    double[] dizi = diziOku(sc);
    double toplam = 0;
    for (int i = 0; i < dizi.length; i++)
        toplam += dizi[i];
    double ortalama = toplam / dizi.length;
    System.out.println("Dizi: "
        + Arrays.toString(dizi));
    System.out.println("Ortalama: "
        + ortalama);
    sc.close();
}
Örnekdizi = {4, 8, 15, 16, 23}
toplam = 66
ortalama = 66 / 5 = 13.2
MaliyetHer eleman bir kez toplanır → O(n) zaman, O(1) ek bellek.
Sınır durumuBoyut 0 ise 0.0 / 0 = NaN; kullanıcıya uyarı vermek daha iyi.

Dizi Algoritmaları

Ortanca (Median) Hesaplama

static double ortanca(double[] dizi) {
    double[] s = dizi.clone(); // kopya
    Arrays.sort(s);             // O(n log n)
    int boyut = s.length;
    double ortanca;
    if (boyut % 2 == 0) {       // çift
        int o1 = boyut/2 - 1, o2 = boyut/2;
        ortanca = (s[o1] + s[o2]) / 2;
    } else {                    // tek
        ortanca = s[boyut / 2];
    }
    return ortanca;
}
  • Ortanca, sıralı dizinin ortasındaki değerdir.
  • Tek boyutta tam ortadaki, çift boyutta ortadaki iki değerin ortalaması alınır.
  • Ortalamanın aksine uç değerlerden (ör. 1000) etkilenmez.
tek (n = 5) 3 0 5 1 7 2 9 3 11 4 → s[2] = 7 çift (n = 4) 2 0 4 1 6 2 8 3 → (4 + 6) / 2 = 5

Dizi Algoritmaları

Mod (En Sık Tekrar Eden Değer)

static int mod(int[] dizi) { // boş değil
    int[] s = dizi.clone();
    Arrays.sort(s);  // eşitler yan yana
    int enCok = s[0], enCokSayi = 1;
    int mevcutSayi = 1;
    for (int i = 1; i < s.length; i++) {
        if (s[i] == s[i - 1]) mevcutSayi++;
        else mevcutSayi = 1;   // yeni değer
        if (mevcutSayi > enCokSayi) {
            enCokSayi = mevcutSayi;
            enCok = s[i];
        }
    }
    return enCok;
}
  • Sıralamadan sonra eşit değerler ardışık olur; tek geçişte en uzun tekrar dizisi bulunur.
  • Eşitlikte ilk (en küçük) değer kalır, çünkü karşılaştırma >.
  • Maliyet: sıralama O(n log n) + tarama O(n).
1 0 1 1 2 2 4 3 4 4 4 5 2 kez 1 kez 3 kez → mod = 4

Dizi Algoritmaları

Diziyi Yerinde Tersine Çevirme

static void tersineCevir(int[] dizi) {
    int baslangic = 0;
    int bitis = dizi.length - 1;
    while (baslangic < bitis) {
        // uçtaki iki elemanı değiştir
        int gecici = dizi[baslangic];
        dizi[baslangic] = dizi[bitis];
        dizi[bitis] = gecici;
        baslangic++;   // içe doğru ilerle
        bitis--;
    }
}
3 0 8 1 1 2 9 3 4 4 6 5baslangicbitis

baslangic = 0, bitis = 5 → 3 ↔ 6

6 0 8 1 1 2 9 3 4 4 3 5baslangicbitis

baslangic = 1, bitis = 4 → 8 ↔ 4

6 0 4 1 1 2 9 3 8 4 3 5baslangicbitis

baslangic = 2, bitis = 3 → 1 ↔ 9

6 0 4 1 9 2 1 3 8 4 3 5baslangicbitis

baslangic ≥ bitis → dur. ⌊n/2⌋ = 3 takas

Yerinde (in-place)⌊n/2⌋ takas → O(n) zaman; yalnızca bir gecici değişken → O(1) ek bellek.
AlternatifYeni bir diziye sondan başa kopyalamak da O(n) zamandır, ama O(n) ek bellek ister.yeni[i] = dizi[n - 1 - i]

Tek boyutta (ör. n = 5) ortadaki eleman yerinde kalır; döngü baslangic < bitis olduğu sürece döner.

Çok Boyutlu Diziler

İki Boyutlu Diziler (Matrisler)

  • Satır ve sütunlardan oluşan tablo benzeri bir yapıdır.
  • Satranç tahtası, resim (piksel ızgarası), tablo gibi iki boyutlu veriler için kullanışlıdır.
  • Bir elemana iki indisle erişilir: matris[satır][sütun].
int[][] matris = new int[3][3];
matris[1][2] = 7;   // 2. satır, 3. sütun
sütun 0 sütun 1 sütun 2 satır 0 [0][0] [0][1] [0][2] satır 1 [1][0] [1][1] [1][2] satır 2 [2][0] [2][1] [2][2]

Çok Boyutlu Diziler

Java'da Matris = Dizilerin Dizisi

int[][] matris = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};
matris.length      // 3 (satır sayısı)
matris[0].length   // 3 (sütun sayısı)
matris 1 2 3 matris[0] 4 5 6 matris[1] 7 8 9 matris[2] length = 3 her satır ayrı bir int[]
  • İlklendiricide boyut yazılmaz: satır sayısı dış listedeki, sütun sayısı iç listelerdeki öğe sayısından çıkar.
  • Her satır ayrı bir dizi olduğundan satırların boyu farklı olabilir (düzensiz dizi, jagged array): int[][] ucgen = new int[3][]; ucgen[0] = new int[1]; …

Çok Boyutlu Diziler

Örnek: Matrisi Doldur ve Yazdır

public class CokBoyutluDiziOrnegi {
  public static void main(String[] a) {
    int[][] matris = new int[3][3];
    // ilk değer atama: 1…9
    for (int i = 0; i < 3; i++)      // satır
      for (int j = 0; j < 3; j++)    // sütun
        matris[i][j] = i * 3 + j + 1;

    System.out.println("Matrisin İçeriği:");
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++)
        System.out.print(matris[i][j] + " ");
      System.out.println();   // yeni satır
    }
  }
}
Matrisin İçeriği:
1 2 3
4 5 6
7 8 9
İç içe döngüDış döngü satırları, iç döngü sütunları gezer. 3 × 3 = 9 atama.i * 3 + j + 1

Sabit 3 yerine matris.length ve matris[i].length yazmak, her boyutta çalışan kod verir.

Çok Boyutlu Diziler

Üç Boyutlu Diziler

  • Java'da üç ya da daha çok boyutlu diziler kullanılabilir (ör. zaman × satır × sütun, RGB katmanları).
  • Her boyut bir iç içe döngü demektir: 3 × 3 × 3 dizide 27 eleman.
int[][][] ucBoyutluDizi =
        new int[3][3][3];
for (int x = 0; x < 3; x++)
  for (int y = 0; y < 3; y++)
    for (int z = 0; z < 3; z++)
      ucBoyutluDizi[x][y][z] =
          x * 9 + y * 3 + z + 1;

// yazdırma: aynı üç döngü;
// z döngüsünden sonra println (y),
// y döngüsünden sonra println (x)
x = 0 1 2 3 4 5 6 7 8 9 x = 1 10 11 12 13 14 15 16 17 18 x = 2 19 20 21 22 23 24 25 26 27 her katman bir 3×3 matris · satır y, sütun z

Değişken adında Türkçe karakter (üçBoyutluDizi) Java'da geçerlidir, ancak taşınabilirlik için ASCII adlar tercih edilir.

Çok Boyutlu Diziler

Matris Transpozu

Satırlar sütuna, sütunlar satıra dönüşür: m×n matrisin transpozu n×m'dir.

static int[][] transpoz(int[][] m) {
    int satir = m.length;
    int sutun = m[0].length;
    int[][] t = new int[sutun][satir];
    for (int i = 0; i < satir; i++)
        for (int j = 0; j < sutun; j++)
            t[j][i] = m[i][j];
    return t;
}
static void yazdirMatris(int[][] m) {
    for (int[] s : m) {
        for (int x : s)
            System.out.print(x + " ");
        System.out.println();
    }
}
1 2 3 4 5 6 1 4 2 5 3 6 m: 2 × 3 t: 3 × 2 t[j][i] = m[i][j] m[0][1] = 2 → t[1][0]

Maliyet: her eleman bir kez kopyalanır → O(m·n).

Yardımcı metotlar static olmalı: main statiktir ve nesne oluşturmadan yalnızca statik metotları çağırabilir.

Çok Boyutlu Diziler

Uygulama: Tic Tac Toe (X-O Oyunu)

  • 3×3'lük bir oyun tahtası: char[][] tahta.
  • İki oyuncu (X ve O) sırayla hamle yapar.
  • Kendi işaretini aynı satır, sütun ya da çaprazda üçleyen kazanır.
  • Tahtada boş yer kalmazsa oyun berabere biter.

Her hamle yalnızca bir dizi ataması: tahta[satir][sutun] = oyuncu

Çok Boyutlu Diziler

Tic Tac Toe: Ana Döngü

public class TicTacToe {   // import java.util.Scanner;
    static Scanner scanner = new Scanner(System.in); // tek Scanner

    public static void main(String[] args) {
        char[][] tahta = new char[3][3];   // 3x3'lük oyun tahtası
        char oyuncu = 'X';                   // ilk oyuncu X
        boolean oyunDevamEdiyor = true;
        tahtaDoldur(tahta);                  // tüm hücreler ' '
        while (oyunDevamEdiyor) {
            tahtayiGoster(tahta);
            hamleYap(tahta, oyuncu);
            oyunDevamEdiyor = oyunDevamEdiyorMu(tahta, oyuncu);
            oyuncu = (oyuncu == 'X') ? 'O' : 'X';   // sıra değişir
        }
        tahtayiGoster(tahta);
    }

new char[3][3] hücreleri '\u0000' ile başlar; boş hücreyi ' ' ile göstermek için tahta önce doldurulur. Tüm yardımcı metotlar static.

Çok Boyutlu Diziler

Tic Tac Toe: Tahta ve Hamle

static void tahtaDoldur(char[][] t) {
  for (int i = 0; i < 3; i++)
    for (int j = 0; j < 3; j++)
      t[i][j] = ' ';
}
static void tahtayiGoster(char[][] t) {
  System.out.println("-------------");
  for (int i = 0; i < 3; i++) {
    System.out.print("| ");
    for (int j = 0; j < 3; j++)
      System.out.print(t[i][j]+" | ");
    System.out.println("\n-------------");
  }
}
static void hamleYap(char[][] t,
                     char oyuncu) {
  int satir, sutun;
  do {
    System.out.print("Sıra " + oyuncu
      + ": satır ve sütun (1-3): ");
    satir = scanner.nextInt() - 1;
    sutun = scanner.nextInt() - 1;
  } while (satir < 0 || satir > 2
        || sutun < 0 || sutun > 2
        || t[satir][sutun] != ' ');
  t[satir][sutun] = oyuncu;
}
// kullanıcı 1-3 girer, dizi 0-2;
// geçersiz/dolu hücre → tekrar sor

Çok Boyutlu Diziler

Tic Tac Toe: Kazanma ve Beraberlik

8 kazanma koşulu (3 satır + 3 sütun + 2 çapraz) bir döngüyle 4 satırda denetlenir.

static boolean kazandi(char[][] t, char o) {
    for (int i = 0; i < 3; i++)
        if ((t[i][0] == o && t[i][1] == o && t[i][2] == o)     // satır i
         || (t[0][i] == o && t[1][i] == o && t[2][i] == o))    // sütun i
            return true;
    return (t[0][0] == o && t[1][1] == o && t[2][2] == o)      // ana çapraz
        || (t[0][2] == o && t[1][1] == o && t[2][0] == o);     // ters çapraz
}
static boolean oyunDevamEdiyorMu(char[][] t, char o) {
    if (kazandi(t, o)) {
        System.out.println("Tebrikler, " + o + " oyuncusu kazandı!");
        return false;
    }
    for (char[] satir : t)
        for (char c : satir)
            if (c == ' ') return true;          // boş hücre var → devam
    System.out.println("Oyun berabere bitti.");
    return false;
}

Karmaşıklık

Dizi İşlemlerinin Maliyeti

Algoritma karmaşıklığı, çalışma süresinin ve bellek kullanımının girdi boyutu n'ye göre nasıl büyüdüğünü gösterir (Bölüm 1).

İşlemZamanNeden?
İndisle erişim / güncelleme a[i]O(1)adres doğrudan hesaplanır
Değer arama (sırasız dizi)O(n)her öğeye bakmak gerekebilir
Değer arama (sıralı dizi, ikili arama)O(log n)her adımda aralık yarıya iner
Sona ekleme / sondan silme (yer varsa)O(1)kaydırma yok
Araya ekleme / aradan silmeO(n)sonraki öğeler kaydırılır
Sıralama (iyi bir algoritma)O(n log n)ör. birleştirmeli sıralama
Kopyalama / büyütmeO(n)tüm öğeler yeni diziye taşınır

Karmaşıklık

Dizi Elemanına Erişim: O(1)

  • İşlem süresi dizinin boyutundan bağımsızdır: 5 elemanlı dizide de 5 milyon elemanlıda da aynı.
  • Çünkü her elemanın adresi hesaplanabilir: adres = başlangıç + i × öğe boyutu.
10 0 20 1 30 2 40 3 50 4 1000 1004 1008 1012 1016 adresindis adres(dizi[2]) = 1000 + 2 × 4 = 1008
int[] dizi = {10, 20, 30, 40, 50};
int eleman = dizi[2];   // 30 — tek adımda, O(1)

Karmaşıklık

Dizide Arama: Doğrusal Arama, O(n)

static boolean lineerArama(int[] dizi,
                           int hedef) {
    for (int eleman : dizi)
        if (eleman == hedef)
            return true; // bulundu
    return false;
}
İyi durumHedef başta: 1 karşılaştırma, O(1).
Kötü durumHedef sonda ya da yok: n karşılaştırma, O(n).
hedef = 5 7 0 2 1 9 2 5 3 1 4 8 5i

i = 0: 7 ≠ 5 → devam

hedef = 5 7 0 2 1 9 2 5 3 1 4 8 5i

i = 1: 2 ≠ 5 → devam

hedef = 5 7 0 2 1 9 2 5 3 1 4 8 5i

i = 2: 9 ≠ 5 → devam

hedef = 5 7 0 2 1 9 2 5 3 1 4 8 5i

i = 3: 5 = 5 → true (4 karşılaştırma)

hedef = 3 7 0 2 1 9 2 5 3 1 4 8 5

hedef = 3: altı öğenin hepsi denenir → false (en kötü durum: n karşılaştırma)

Karmaşıklık

İki Dizide Ortak Eleman Bulma: O(n·m)

static void eslestir(int[] dizi1, int[] dizi2) {
    for (int eleman1 : dizi1)       // n kez
        for (int eleman2 : dizi2)   // m kez
            if (eleman1 == eleman2)
                System.out.println(
                    "Eşleşen eleman: " + eleman1);
}
  • Her dizi1 elemanı, dizi2'nin her elemanıyla karşılaştırılır: n·m karşılaştırma.
  • İki dizi de n elemanlıysa O(n²): büyük veri için verimsiz.
  • Daha iyisi: birini sıralayıp ikili arama O(n log n) ya da hash kümesi, ortalama O(n) (Bölüm 9).
dizi1 ↓ / dizi2 → 5 1 3 8 3 · · ✓ · 7 · · · · 5 ✓ · · · 3 × 4 = 12 karşılaştırma, 2 eşleşme

Karmaşıklık

Araya Ekleme ve Silme: O(n)

static int ekle(int[] a, int boyut,
             int indis, int deger) {
  // ön koşul: boyut < a.length
  for (int k = boyut; k > indis; k--)
    a[k] = a[k - 1];   // sağa kaydır
  a[indis] = deger;
  return boyut + 1;   // yeni boyut
}
7 0 2 1 9 2 5 3 4 5 6 boyut = 4 · kapasite = 7

Hedef: 4'ü indis 1'e eklemek. Önce sağdaki öğeler yer açmak için kaydırılmalı.

7 0 2 1 9 2 5 3 5 4 5 6 boyut = 4 · kapasite = 7

En sağdan başla: dizi[4] = dizi[3]

7 0 2 1 9 2 9 3 5 4 5 6 boyut = 4 · kapasite = 7

dizi[3] = dizi[2]

7 0 2 1 2 2 9 3 5 4 5 6 boyut = 4 · kapasite = 7

dizi[2] = dizi[1]

7 0 4 1 2 2 9 3 5 4 5 6 boyut = 5 · kapasite = 7

dizi[1] = 4, boyut++ → 3 kaydırma. En kötü durum (indis 0): n kaydırma → O(n)

7 0 2 1 9 2 5 3 4 5 6 boyut = 4 · kapasite = 7

Silme (indis 1) tersidir: sağdakiler birer sola kayar → O(n)

Sona eklemeYer varsa kaydırma yok.O(1)
Ortaya eklemeOrtalama n/2 kaydırma.O(n)
Başa eklemen öğenin hepsi kayar (en kötü durum).O(n)

Kaydırma sağdan sola yapılır; soldan başlansaydı her öğe bir sonrakinin üzerine yazılırdı. Dizi doluysa önce daha büyük bir dizi oluşturulup kopyalanır (O(n)).

Karmaşıklık

Dizi Sıralama: Zaman Karmaşıklığı

Sıralamanın maliyeti kullanılan algoritmaya bağlıdır:

AlgoritmaEn iyiOrtalamaEn kötüEk bellek
Kabarcık (Bubble Sort)O(n)*O(n²)O(n²)O(1)
Seçimli (Selection Sort)O(n²)O(n²)O(n²)O(1)
Eklemeli (Insertion Sort)O(n)O(n²)O(n²)O(1)
Hızlı (Quick Sort)O(n log n)O(n log n)O(n²)O(log n)
Birleştirmeli (Merge Sort)O(n log n)O(n log n)O(n log n)O(n)

* Takas olmayan turda duran sürümde. Hızlı sıralamanın en kötü durumu kötü pivot seçiminde (ör. sıralı girdi + ilk eleman pivot) ortaya çıkar.

Arrays.sort: ilkel diziler için çift pivotlu hızlı sıralama, nesne dizileri için kararlı (stable) TimSort kullanır.

Karmaşıklık

Seçimli Sıralama (Selection Sort)

Her turda sıralanmamış kısmın en küçük elemanını bul, o kısmın başına taşı.

int[] dizi = {64, 25, 12, 22, 11};
int n = dizi.length;
for (int i = 0; i < n - 1; i++) {
    int minIndex = i;
    for (int j = i + 1; j < n; j++)
        if (dizi[j] < dizi[minIndex])
            minIndex = j;
    // takas: indislerle, yerinde
    int gecici = dizi[minIndex];
    dizi[minIndex] = dizi[i];
    dizi[i] = gecici;
}
64 0 25 1 12 2 22 3 11 4iminIndex

i = 0: en küçük 11 (indis 4) → 64 ile takas

11 0 25 1 12 2 22 3 64 4iminIndex

i = 1: kalanların en küçüğü 12 → 25 ile takas

11 0 12 1 25 2 22 3 64 4iminIndex

i = 2: en küçük 22 → 25 ile takas

11 0 12 1 22 2 25 3 64 4i = minIndex

i = 3: en küçük zaten yerinde (25), takas yok

11 0 12 1 22 2 25 3 64 4

Sıralandı: 4 + 3 + 2 + 1 = 10 = n(n−1)/2 karşılaştırma

Java'da parametreler değerle geçer: yerDegistir(dizi[minIndex], dizi[i]) yalnızca kopyaları değiştirir, dizi değişmez. Takas indislerle yapılmalı (ya da yerDegistir(dizi, i, minIndex)).

Karmaşıklık

Alan Karmaşıklığı ve Bellek Kullanımı

  • Alan karmaşıklığı, bir algoritmanın/veri yapısının bellek ihtiyacının n ile nasıl büyüdüğüdür.
  • n elemanlı bir dizi O(n) alan kaplar; bayt olarak miktar eleman tipine bağlıdır.
Dizi tipiEleman başına100 eleman (yalnızca veri)
int[]4 bayt400 bayt
char[] (UTF-16)2 bayt200 bayt
double[], long[]8 bayt800 bayt
Object[] (referans)4 / 8 bayt400 / 800 bayt + nesneler
Ek yükHer dizi nesnesinin ayrıca ~16 baytlık başlığı (tür bilgisi + length) vardır.
Referans dizileriYalnızca referanslar ardışıktır; gösterilen nesneler heap'te ayrı yer kaplar.

Özet

Özet

YapıAynı türden, sabit boyutlu, ardışık bellek; indis 0 … length − 1.
Java'daDizi bir nesnedir, heap'tedir; = referansı kopyalar, Arrays.copyOf öğeleri.
Çok boyutluDizilerin dizisi; satırlar farklı boyda olabilir. m[i][j].
İşlemMaliyetİşlemMaliyet
Erişim a[i]O(1)Araya ekleme / silmeO(n)
Doğrusal aramaO(n)Tersine çevirmeO(n)
Seçimli sıralamaO(n²)Transpoz (m×n)O(m·n)
Etkileşimli simülatör: dizide erişim, ekleme, silme ve aramayı adım adım denemek için Dizi Simülatörü.

Özet

Örnek Problemler

  1. int[] a = new int[4]; sonrası a[4] ifadesi ne olur? a.length kaçtır?
  2. int[] b = a; b[0] = 9; sonrası a[0] kaçtır? Neden?
  3. n elemanlı dizide en büyük elemanı bulan metodu yazın. Karmaşıklığı nedir?
  4. {5, 1, 4, 2, 8} dizisine seçimli sıralamanın ilk iki turundan sonra dizi nasıl görünür?
  5. 1000 elemanlı double[] dizinin veri kısmı kaç bayttır?
  6. 3×4 bir matrisin transpozu kaç satır, kaç sütundur? t[2][1] hangi elemandır?
Cevapları göster
  1. ArrayIndexOutOfBoundsException (geçerli indisler 0–3); a.length = 4.
  2. 9: b ve a aynı dizi nesnesini gösterir.
  3. int max = a[0]; for (int x : a) if (x > max) max = x; → O(n) (boş dizi ayrıca kontrol edilmeli).
  4. 1. tur: {1, 5, 4, 2, 8}; 2. tur: {1, 2, 4, 5, 8}.
  5. 1000 × 8 = 8000 bayt (+ dizi başlığı).
  6. 4 satır, 3 sütun; t[2][1] = m[1][2].

Özet

Kaynaklar

  • Goodrich, Tamassia ve Goldwasser, Data Structures and Algorithms in Java, 6. baskı, 2014.
  • Lafore, Data Structures and Algorithms in Java, 2. baskı, 2002.
  • Oracle, Java SE 17 Arrays ve System API belgeleri.

Son

Bölüm 2: Diziler
Sonraki bölüm: Bağlı Listeler
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.

← → veya boşluk ile gezinin · F: tam ekran · Home/End: ilk/son slayt