Bölüm 3: Diziler
Giriş
Öğrenme Çıktıları
Dizilerin bellekteki yerleşimini ve indisleme mantığını açıklamak.
Tek ve çok boyutlu dizileri doğru biçimde tanımlayıp kullanmak.
Arama, ekleme, silme ve sıralama işlemlerini diziler üzerinde uygulamak.
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.
Temel Kavramlar
Dizi Kullanımı: İndisle Erişim
- Dizi öğelerine indis (index) numarasıyla erişilir:
diziAdi[indis]. - İlk öğenin indisi 0, son öğeninki length − 1'dir.
- Öğeler ardışık ve eşit boyutlu olduğundan her öğenin adresi tek bir çarpma ve toplamayla hesaplanır.
int[] dizi = {7, 2, 9, 5, 1}; int ilkOge = dizi[0]; // 7 int sonOge = dizi[dizi.length - 1]; // 1
Temel Kavramlar
Dizi Türleri
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 sıralama, arama gibi metotları yoktur; bunlar için
java.util.Arrayskullanılır.
Temel Kavramlar
Dizi Kovaryansı ve ArrayStoreException
String,Object'in alt türü olduğundanString[]daObject[]'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 nesneler[0] = 42; // derlenir, ama // çalışırken istisna!
Java'da Diziler
Dizi Tanımlama
VeriTipi[] diziAdi = new VeriTipi[diziBoyutu];int[] sayilar = new int[5]; // → [0, 0, 0, 0, 0]
new ile oluşturulan dizinin her öğesi, türünün varsayılan değerini alır.
| Tür | Varsayılan değer |
|---|---|
int, long… | 0 |
double | 0.0 |
boolean | false |
char | '\u0000' |
nesne (String…) | null |
Java'da Diziler
Erişim, İlklendirme ve length
int[] sayilar = {10, 20, 30, 40, 50}; // 5 ilklendirici → boyut 5 int ilkOge = sayilar[0]; // 10 int ikinciOge = sayilar[1]; // 20 sayilar[4] = 55; // son öğe 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 · Kodu adım adım çalıştır
Kod İzleme: Dizide Okuma ve Yazma
İlklendirici listesinde 5 değer var → heap'te 5 öğeli bir int[] oluşur; sayilar yalnızca onun referansını tutar.
Okuma: sayilar[0] ilk hücre. Adres = başlangıç + 0 × 4 → tek adımda, O(1).
İndis 1 = ikinci öğe (indisler 0'dan başlar).
Yazma: aynı sözdizimi, atamanın solunda. Son hücre (indis 4 = length − 1) 50 → 55.
length bir alandır (parantez yok) → 5. Boyut, dizi oluşturulurken sabitlendi.
Sonradan atamada new int[] gerekir: yeni 3 öğeli dizi oluşur, sayilar onu gösterir. Eski dizi değişmedi; referansı kalmadığı için GC toplayabilir. diziBoyutu hâlâ 5: o bir kopyaydı.
int[] sayilar = {10, 20, 30, 40, 50}; int ilkOge = sayilar[0]; int ikinciOge = sayilar[1]; sayilar[4] = 55; int diziBoyutu = sayilar.length; sayilar = new int[] {1, 2, 3};
Son satır (new int[3] {1, 2, 3}) derlenmez.
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 öğeli dizi for (int i = 0; i < sayilar.length; i++) sayilar[i] = (i + 1) * 10; // 10, 20, 30, 40, 50 System.out.println("Dizinin birinci öğesi: " + sayilar[0]); System.out.println("Dizinin üçüncü öğesi: " + sayilar[2]); System.out.print("Dizi Öğeleri: "); for (int x : sayilar) // for-each: indis gerekmiyorsa System.out.print(x + " "); } }
Dizinin birinci öğesi: 10 Dizinin üçüncü öğesi: 30 Dizi Öğeleri: 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 · Kodu adım adım çalıştır
Kod İzleme: Doldur ve Yazdır
new int[5]: 5 hücre ayrılır ve hepsi int'in varsayılan değeri 0 ile başlar.
i = 0 < 5 → sayilar[0] = (0 + 1) × 10 = 10.
i = 1 < 5 → sayilar[1] = (1 + 1) × 10 = 20.
i = 2 < 5 → sayilar[2] = (2 + 1) × 10 = 30.
i = 3 < 5 → sayilar[3] = (3 + 1) × 10 = 40.
i = 4 < 5 → sayilar[4] = (4 + 1) × 10 = 50.
i = 5 için 5 < 5 yanlış → döngü biter. Sınır sayilar.length olduğundan boyut değişse de kod doğru kalır.
İndis 0 okunur → 10; println satır sonu ekler.
Üçüncü öğe indis 2'dedir → 30.
print satır sonu eklemez; öğeler aynı satıra yazılacak.
for-each: x = 10 (indis 0). İndis değişkeni gerekmiyorsa daha okunaklı.
x = 20 yazdırılır.
x = 30 yazdırılır.
x = 40 yazdırılır.
x = 50 yazdırılır. Tüm öğeler gezildi → döngü biter.
int[] sayilar = new int[5]; for (int i = 0; i < sayilar.length; i++) sayilar[i] = (i + 1) * 10; System.out.println("Dizinin birinci öğesi: " + sayilar[0]); System.out.println("Dizinin üçüncü öğesi: " + sayilar[2]); System.out.print("Dizi Öğeleri: "); for (int x : sayilar) System.out.print(x + " ");
Java'da Diziler
Dizi Kopyalama: Referans mı, Kopya mı?
Dizi bir nesnedir: heap'te oluşur (#1). Stack'teki dizi değişkeni yalnızca onun adresini tutar.
= yalnızca adresi kopyalar: iki değişken aynı diziyi (#1) gösterir. Yeni dizi oluşmadı.
Arrays.copyOf heap'te yeni bir dizi (#2) oluşturur ve öğeleri tek tek kopyalar → O(n). (dizi.clone() ve System.arraycopy da öğeleri kopyalar.)
referans[0] = 99 #1'i değiştirir → dizi[0] da 99 olur. kopya[0] ayrı nesnede, hâlâ 1.
int[] dizi = {1, 2, 3, 4, 5}; int[] referans = dizi; // aynı nesne int[] kopya = Arrays.copyOf(dizi, dizi.length); referans[0] = 99;
Java'da Diziler
Hazır Dizi İşlemleri: java.util.Arrays
| Metot | Ne yapar? | Maliyet |
|---|---|---|
Arrays.toString(a) | "[1, 2, 3]" biçiminde metin üretir | O(n) |
Arrays.equals(a, b) | Uzunluklar ve öğeler tek tek eşit mi? | O(n) |
Arrays.fill(a, v) | Tüm hücrelere v yazar | O(n) |
Arrays.copyOf(a, n) | Yeni dizi; n > a.length ise fazlası varsayılan değer | O(n) |
Arrays.sort(a) | Artan sıraya dizer (yerinde) | O(n log n) |
Arrays.binarySearch(a, x) | Sıralı dizide ikili arama; yoksa negatif sonuç | O(log n) |
int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; a == b // false: ayrı nesne Arrays.equals(a, b) // true: aynı içerik println(a) // [I@1b6d3586
Java'da Diziler
Varargs (Değişken Sayıda Argüman)
tip... adyazı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 oge : dizi) toplam += oge; return toplam / dizi.length; }
| Çağrı | dizi.length | Sonuç |
|---|---|---|
ortalama(4, 8, 15) | 3 | 9.0 |
ortalama(7.5) | 1 | 7.5 |
ortalama() | 0 | NaN |
ortalama(new double[] {1, 2}) | 2 | 1.5 |
Java'da Diziler · Kodu adım adım çalıştır
Kod İzleme: ortalama(4, 8, 15)
Çağrı ortalama(4, 8, 15): derleyici argümanları bir double[] dizisine koyar (int → double genişletilir).
dizi.length = 3 ≠ 0 → boş dizi durumu değil, devam.
var: türü sağdaki değerden çıkarılır → double.
for-each: öğe = 4.0 (dizideki 1. öğe).
toplam = 0.0 + 4.0 = 4.0.
for-each: öğe = 8.0 (dizideki 2. öğe).
toplam = 4.0 + 8.0 = 12.0.
for-each: öğe = 15.0 (dizideki 3. öğe).
toplam = 12.0 + 15.0 = 27.0.
Döngü bitti. return 27.0 / 3 = 9.0. ortalama() çağrılsaydı length 0 olur, 3. satırda NaN dönerdi.
static double ortalama(double... dizi) { if (dizi.length == 0) return Double.NaN; // tanımsız var toplam = 0.0; for (var oge : dizi) toplam += oge; return toplam / dizi.length; }
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:
newile 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 | Heap | |
|---|---|---|
| Ne tutulur? | yerel değişkenler, referanslar, çağrı çerçeveleri | nesneler, diziler |
| Ömür | metot bitene kadar | erişilebilir olduğu sürece |
| Yönetim | otomatik (çağrı / dönüş) | otomatik (GC) |
Java'da Diziler
"Statik" ve "Dinamik" Diziler: C ve Java
| C / C++ | Java | |
|---|---|---|
| Stack'te dizi | int a[10]; — boyut derleme zamanında sabit, fonksiyon bitince yok olur | Yok: tüm diziler heap'te |
| Heap'te dizi | malloc / new int[n] | new int[n] (ilklendirici listesi de heap'te) |
| Boyut | heap'te çalışma zamanında belirlenir | çalışma zamanında belirlenir, sonra sabit |
| Serbest bırakma | programcı: free / delete[] | GC otomatik; dizi = null yalnızca referansı koparır |
int[] dinamikDizi = new int[n]; // heap'te n öğelik 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.Java'da Diziler
İndis Sınır Dışı Hatası
- Geçerli aralığın dışındaki bir indise erişilirse Java
ArrayIndexOutOfBoundsExceptionfı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.
int[] dizi = new int[5]; dizi[5] = 1; // Index 5 out of // bounds for length 5 dizi[-1] = 1; // aynı hata
if (indis >= 0 && indis < dizi.length) { int deger = dizi[indis]; } else { System.out.println("Geçersiz"); }
Dizi Algoritmaları
Diziyi Kullanıcıdan Okuma
Ortalama, ortanca ve mod programları aynı giriş kalıbıyla başlar; ortak kodu bir yardımcı metotta toplayalım (mod için int[] sürümü aynıdır):
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) + ". öğeyi girin: "); // 1'den say dizi[i] = scanner.nextDouble(); } return dizi; }
Dizi Algoritmaları · Kodu adım adım çalıştır
Kod İzleme: diziOku(sc)
Kullanıcıdan önce boyut istenir. print satır sonu eklemez; imleç aynı satırda bekler.
Kullanıcı 4 yazar; nextInt() okur. (Konsolda kullanıcının yazdığı da görünür.)
Boyut çalışma zamanında belli oldu → new double[4], hücreler 0.0.
i = 0, ama kullanıcıya 1. öğe diye sorulur (insanlar 1'den sayar).
Kullanıcı 4 yazar → dizi[0] = 4.0.
i = 1, ama kullanıcıya 2. öğe diye sorulur (insanlar 1'den sayar).
Kullanıcı 8 yazar → dizi[1] = 8.0.
i = 2, ama kullanıcıya 3. öğe diye sorulur (insanlar 1'den sayar).
Kullanıcı 15 yazar → dizi[2] = 15.0.
i = 3, ama kullanıcıya 4. öğe diye sorulur (insanlar 1'den sayar).
Kullanıcı 16 yazar → dizi[3] = 16.0. i = 4 olunca döngü biter.
Dizinin referansı döndürülür; dizi heap'te olduğundan metot bitince de yaşar.
static double[] diziOku(Scanner scanner) { System.out.print("Dizi boyutunu girin: "); int boyut = scanner.nextInt(); double[] dizi = new double[boyut]; for (int i = 0; i < boyut; i++) { System.out.print((i + 1) + ". öğeyi girin: "); dizi[i] = scanner.nextDouble(); } return dizi; }
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(); }
toplam = 66
ortalama = 66 / 5 = 13.2
NaN; kullanıcıya uyarı vermek daha iyi.Dizi Algoritmaları · Kodu adım adım çalıştır
Kod İzleme: Ortalama Hesaplama
Bu kez kullanıcı 5 değer girmiş olsun: diziOku {4, 8, 15, 16, 23} dizisini döndürür.
Toplayıcı değişken 0 ile başlar (int 0 → double 0.0).
toplam += dizi[0] → 0.0 + 4.0 = 4.0.
toplam += dizi[1] → 4.0 + 8.0 = 12.0.
toplam += dizi[2] → 12.0 + 15.0 = 27.0.
toplam += dizi[3] → 27.0 + 16.0 = 43.0.
toplam += dizi[4] → 43.0 + 23.0 = 66.0.
i = 5, 5 < 5 yanlış → döngü biter. Her öğe bir kez toplandı → O(n).
ortalama = 66.0 / 5 = 13.2. Boyut 0 olsaydı 0.0 / 0 = NaN çıkardı.
Arrays.toString diziyi [a, b, …] biçiminde yazıya çevirir. (println(dizi) yalnızca tür@adres yazardı.)
Sonuç yazdırılır. Toplam O(n) zaman, O(1) ek bellek.
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);
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.
Dizi Algoritmaları · Kodu adım adım çalıştır
Kod İzleme: ortanca()
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; }
1. çağrı (çift boyut): ortanca 4 öğeli bir diziyle çağrılır.
Önce kopya: çağıranın dizisinin sırası bozulmasın.
Kopya sıralanır; orijinal dizi değişmedi.
boyut = 4.
4 % 2 == 0 → çift: ortada tek bir öğe yok, iki öğe var.
Ortadaki iki indis: o1 = 1, o2 = 2.
ortanca = (4.0 + 6.0) / 2 = 5.0.
return 5.0.
2. çağrı (tek boyut): ortanca 5 öğeli bir diziyle çağrılır.
Önce kopya: çağıranın dizisinin sırası bozulmasın.
Kopya sıralanır; orijinal dizi değişmedi.
boyut = 5.
5 % 2 = 1 → tek: else dalına geçilir.
Tam orta: indis 5 / 2 = 2 → 7.0.
return 7.0. Sıralama baskın → O(n log n).
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).
Dizi Algoritmaları · Kodu adım adım çalıştır
Kod İzleme: mod({4, 1, 4, 2, 1, 4})
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; }
Girdi: {4, 1, 4, 2, 1, 4}. Eşit değerler dağınık.
Kopya sıralanınca eşit değerler yan yana gelir; artık tek geçiş yeter.
Başlangıç: ilk değer (1) şimdilik en çok görülen, 1 kez.
s[1] = 1 == s[0] → aynı değer sürüyor, mevcutSayi = 2.
2 > önceki rekor → yeni rekor: enCok = 1, 2 kez.
s[2] = 2 ≠ 1 → yeni değer, sayaç 1'e döner.
1 > 2 yanlış → rekor değişmez.
s[3] = 4 ≠ 2 → yeni değer, sayaç 1'e döner.
1 > 2 yanlış → rekor değişmez.
s[4] = 4 == s[3] → aynı değer sürüyor, mevcutSayi = 2.
2 > 2 yanlış → rekor değişmez. (Eşitlikte ilk değer kalır.)
s[5] = 4 == s[4] → aynı değer sürüyor, mevcutSayi = 3.
3 > önceki rekor → yeni rekor: enCok = 4, 3 kez.
return 4 (3 kez). Sıralama O(n log n) + tarama O(n).
Dizi Algoritmaları · Kodu adım adım çalıştır
Diziyi Yerinde Tersine Çevirme
static void tersineCevir(int[] dizi) { int baslangic = 0; int bitis = dizi.length - 1; while (baslangic < bitis) { // uçtaki iki öğeyi takas et int gecici = dizi[baslangic]; dizi[baslangic] = dizi[bitis]; dizi[bitis] = gecici; baslangic++; // içe doğru ilerle bitis--; } }
Sol işaretçi ilk öğede.
Sağ işaretçi son öğede (length − 1 = 5).
0 < 5 → takas edilecek bir çift daha var.
gecici = dizi[0] = 3: soldaki değer kaybolmasın diye saklanır.
dizi[0] = dizi[5] → 6. (Eski 3 artık yalnızca gecici'de.)
dizi[5] = gecici → 3. Çift yer değiştirdi.
İşaretçiler içe doğru: baslangic = 1, bitis = 4.
1 < 4 → takas edilecek bir çift daha var.
gecici = dizi[1] = 8: soldaki değer kaybolmasın diye saklanır.
dizi[1] = dizi[4] → 4. (Eski 8 artık yalnızca gecici'de.)
dizi[4] = gecici → 8. Çift yer değiştirdi.
İşaretçiler içe doğru: baslangic = 2, bitis = 3.
2 < 3 → takas edilecek bir çift daha var.
gecici = dizi[2] = 1: soldaki değer kaybolmasın diye saklanır.
dizi[2] = dizi[3] → 9. (Eski 1 artık yalnızca gecici'de.)
dizi[3] = gecici → 1. Çift yer değiştirdi.
İşaretçiler içe doğru: baslangic = 3, bitis = 2.
3 < 2 yanlış → işaretçiler ortada buluştu, döngü biter. ⌊n/2⌋ = 3 takas → O(n) zaman, O(1) ek bellek.
Alternatif: yeni diziye sondan başa kopyalamak (yeni[i] = dizi[n - 1 - i]) da O(n) zamandır, ama O(n) ek bellek ister. Öğe sayısı tekse ortadaki öğe yerinde kalır.
Dizi Algoritmaları · Kodu adım adım çalıştır
Uygulama: Sezar Şifresi sifrele("ZEKA", 3)
toCharArray() metnin harflerini yeni bir char[] dizisine kopyalar. String değiştirilemez; dizi ise yerinde değiştirilebilir.
i = 0: 'Z' − 'A' harfin alfabedeki sırasını verir: 25 (char değerleri tamsayıdır).
harf[0] = 'C': sıra 3 kaydırılır, yeniden harfe çevrilir. Sona taşan sıra % 26 ile başa sarar (Z → C).
i = 1: 'E' − 'A' harfin alfabedeki sırasını verir: 4 (char değerleri tamsayıdır).
harf[1] = 'H': sıra 3 kaydırılır, yeniden harfe çevrilir.
i = 2: 'K' − 'A' harfin alfabedeki sırasını verir: 10 (char değerleri tamsayıdır).
harf[2] = 'N': sıra 3 kaydırılır, yeniden harfe çevrilir.
i = 3: 'A' − 'A' harfin alfabedeki sırasını verir: 0 (char değerleri tamsayıdır).
harf[3] = 'D': sıra 3 kaydırılır, yeniden harfe çevrilir.
new String(harf) → "CHND". Çözmek için aynı metot k = 26 − 3 = 23 ile çağrılır. Her harf bir kez işlenir: O(n).
static String sifrele(String mesaj, int k) { char[] harf = mesaj.toCharArray(); for (int i = 0; i < harf.length; i++) { int sira = harf[i] - 'A'; // 0..25 harf[i] = (char) ('A' + (sira + k) % 26); } return new String(harf); }
Ç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 öğeye 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
Ç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ı)
- İ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 · Kodu adım adım çalıştır
Düzensiz Dizi: Pascal Üçgeni
new int[n][]: yalnızca 4 referanslık dış dizi oluşur; satır dizileri henüz yok (null).
p[0] = new int[1]: 0. satır 1 uzunlukta ayrı bir dizi; hücreler 0 ile başlar.
p[0][0] = 1: tek hücreli satırda baş ve son aynı hücre.
p[1] = new int[2]: 1. satır 2 uzunlukta ayrı bir dizi; satırların boyu farklı → düzensiz (jagged) dizi.
p[1][0] = p[1][1] = 1: satırın iki ucu 1 (zincirleme atama sağdan sola).
p[2] = new int[3]: 3 hücrelik yeni satır.
p[2][0] = p[2][2] = 1: satırın iki ucu 1 (zincirleme atama sağdan sola).
p[2][1] = p[1][0] + p[1][1] = 1 + 1 = 2: üstteki iki komşunun toplamı.
p[3] = new int[4]: 4 hücrelik yeni satır.
p[3][0] = p[3][3] = 1: satırın iki ucu 1 (zincirleme atama sağdan sola).
p[3][1] = p[2][0] + p[2][1] = 1 + 2 = 3: üstteki iki komşunun toplamı.
p[3][2] = p[2][1] + p[2][2] = 2 + 1 = 3: üstteki iki komşunun toplamı. Pascal üçgeni tamam: toplam 1+2+3+4 = 10 hücre (4×4 = 16 değil).
int n = 4; int[][] p = new int[n][]; // satırlar yok for (int i = 0; i < n; i++) { p[i] = new int[i + 1]; // i + 1 uzunluk p[i][0] = p[i][i] = 1; for (int j = 1; j < i; j++) p[i][j] = p[i-1][j-1] + p[i-1][j]; }
Çok Boyutlu Diziler · Kodu adım adım çalıştır
2B Dizide Sığ ve Derin Kopya
2×2 matris: dış dizi m iki satır dizisini gösterir (dizilerin dizisi).
m.clone() yalnızca dış diziyi kopyalar: s yeni bir dış dizi, ama içindeki referanslar aynı satırları gösterir → sığ kopya (shallow copy).
s[0][0] = 9 ortak satırı değiştirir: m[0][0] de 9 olur. Sık yapılan hata!
s[1] = new int[] {7, 8} ise s'nin kendi dış dizisindeki referansı değiştirir; m[1] hâlâ {3, 4}.
Derin kopya (deep copy) için önce d dış dizisi oluşturulur; satırları henüz yok.
d[0] = m[0].clone(): 0. satırın öğeleri yeni bir diziye kopyalanır.
d[1] = m[1].clone(): 1. satırın öğeleri yeni bir diziye kopyalanır.
d[0][1] = 5 yalnızca kopyayı değiştirir; m[0][1] hâlâ 2. Derin kopya O(satır × sütun) sürer.
int[][] m = { {1, 2}, {3, 4} }; int[][] s = m.clone(); // sığ kopya s[0][0] = 9; // m[0][0] de 9! s[1] = new int[] {7, 8}; // yalnız s değişir int[][] d = new int[2][]; // derin kopya: for (int i = 0; i < 2; i++) d[i] = m[i].clone(); // satırlar da d[0][1] = 5; // m etkilenmez
Ç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
Sabit 3 yerine matris.length ve matris[i].length yazmak, her boyutta çalışan kod verir.
Çok Boyutlu Diziler · Kodu adım adım çalıştır
Kod İzleme: Matrisi Doldur
int[][] matris = new int[3][3]; 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 }
3 satırlık dış dizi + 3 ayrı satır dizisi oluşur; tüm hücreler 0.
i = 0, j = 0 → matris[0][0] = 0·3 + 0 + 1 = 1. Dış döngü satırı, iç döngü sütunu seçer.
i = 0, j = 1 → matris[0][1] = 0·3 + 1 + 1 = 2.
i = 0, j = 2 → matris[0][2] = 0·3 + 2 + 1 = 3.
i = 1, j = 0 → matris[1][0] = 1·3 + 0 + 1 = 4. İç döngü bitti, dış döngü sonraki satıra geçti; j yeniden 0.
i = 1, j = 1 → matris[1][1] = 1·3 + 1 + 1 = 5.
i = 1, j = 2 → matris[1][2] = 1·3 + 2 + 1 = 6.
i = 2, j = 0 → matris[2][0] = 2·3 + 0 + 1 = 7. İç döngü bitti, dış döngü sonraki satıra geçti; j yeniden 0.
i = 2, j = 1 → matris[2][1] = 2·3 + 1 + 1 = 8.
i = 2, j = 2 → matris[2][2] = 2·3 + 2 + 1 = 9.
i = 3 → dış döngü biter. İç gövde 3 × 3 = 9 kez çalıştı.
Çok Boyutlu Diziler · Kodu adım adım çalıştır
Kod İzleme: Matrisi Yazdır (devam)
int[][] matris = new int[3][3]; 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 }
Başlık yazılır; matris artık dolu.
Satır 0: j = 0'dan başlar → 1.
matris[0][1] = 2 aynı satıra yazılır (print).
matris[0][2] = 3 aynı satıra yazılır (print).
Satır 0 bitti → println() alt satıra geçer.
Satır 1: j = 0'dan başlar → 4.
matris[1][1] = 5 aynı satıra yazılır (print).
matris[1][2] = 6 aynı satıra yazılır (print).
Satır 1 bitti → println() alt satıra geçer.
Satır 2: j = 0'dan başlar → 7.
matris[2][1] = 8 aynı satıra yazılır (print).
matris[2][2] = 9 aynı satıra yazılır (print).
Satır 2 bitti → println() alt satıra geçer. Tüm matris yazıldı.
Ç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 öğe.
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)
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(); } }
Maliyet: her öğe 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 · Kodu adım adım çalıştır
Kod İzleme: transpoz(m)
m: 2 satır, 3 sütun.
m.length = satır sayısı (dış dizinin boyu).
m[0].length = ilk satırın boyu = sütun sayısı.
Boyutlar yer değiştirir: 3 × 2'lik yeni matris (hepsi 0).
t[0][0] = m[0][0] = 1: satır ↔ sütun.
t[1][0] = m[0][1] = 2: satır ↔ sütun.
t[2][0] = m[0][2] = 3: satır ↔ sütun. m'nin 0. satırı t'nin 0. sütunu olur.
t[0][1] = m[1][0] = 4: satır ↔ sütun.
t[1][1] = m[1][1] = 5: satır ↔ sütun.
t[2][1] = m[1][2] = 6: satır ↔ sütun.
return t. 2 × 3 = 6 kopyalama → O(m·n).
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; }
Ç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ü (satır, sütun) ve tek bir return (çaprazlar) ile 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; }
Çok Boyutlu Diziler · Kodu adım adım çalıştır
Kod İzleme: kazandi(t, 'X')
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 }
Son hamleyi X yaptı; X kazandı mı? 8 çizgi denetlenecek.
i = 0, satır 0: t[0][1] = 'O' ≠ 'X' → yanlış. && kısa devre: kalan 1 hücreye bakılmaz.
i = 0, sütun 0: t[1][0] = boş ≠ 'X' → yanlış. && kısa devre: kalan 1 hücreye bakılmaz.
i = 1, satır 1: t[1][0] = boş ≠ 'X' → yanlış. && kısa devre: kalan 2 hücreye bakılmaz.
i = 1, sütun 1: t[0][1] = 'O' ≠ 'X' → yanlış. && kısa devre: kalan 2 hücreye bakılmaz.
i = 2, satır 2: t[2][0] = boş ≠ 'X' → yanlış. && kısa devre: kalan 2 hücreye bakılmaz.
i = 2, sütun 2: t[0][2] = boş ≠ 'X' → yanlış. && kısa devre: kalan 2 hücreye bakılmaz.
i = 3 → döngü biter: hiçbir satır ve sütun X ile dolu değil.
Ana çapraz: t[0][0], t[1][1], t[2][2] hepsi 'X' → || sağ tarafa hiç bakılmaz, return true.
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.
| İşlem | Zaman | Neden? |
|---|---|---|
İ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 silme | O(n) | sonraki öğeler kaydırılır |
| Sıralama (iyi bir algoritma) | O(n log n) | ör. birleştirme sıralaması |
| Kopyalama / büyütme | O(n) | tüm öğeler yeni diziye taşınır |
Karmaşıklık
Dizi Öğesine Erişim: O(1)
- İşlem süresi dizinin boyutundan bağımsızdır: 5 öğeli dizide de 5 milyon öğelide de aynı.
- Çünkü her öğenin adresi hesaplanabilir:
adres = başlangıç + i × öğe boyutu.
int[] dizi = {10, 20, 30, 40, 50}; int oge = dizi[2]; // 30 — tek adımda, O(1)
Karmaşıklık · Kodu adım adım çalıştır
Dizide Arama: Doğrusal Arama, O(n)
1. çağrı: 5 aranıyor. Dizi sırasız → baştan sona bakmaktan başka yol yok.
7 ≠ 5 → sonraki öğe.
2 ≠ 5 → sonraki öğe.
9 ≠ 5 → sonraki öğe.
5 == 5 → eşit.
return true: 4 karşılaştırmada bulundu; kalan öğelere bakılmaz. Hedef baştaysa 1 karşılaştırma → en iyi durum O(1).
2. çağrı: 3 aranıyor. Dizi sırasız → baştan sona bakmaktan başka yol yok.
7 ≠ 3 → sonraki öğe.
2 ≠ 3 → sonraki öğe.
9 ≠ 3 → sonraki öğe.
5 ≠ 3 → sonraki öğe.
1 ≠ 3 → sonraki öğe.
8 ≠ 3 → sonraki öğe.
Dizi bitti, return false: n = 6 öğenin hepsine bakıldı → en kötü durum O(n).
static boolean dogrusalArama(int[] dizi, int hedef) { for (int oge : dizi) if (oge == hedef) return true; // bulundu return false; }
Karmaşıklık
İki Dizide Ortak Öğe Bulma: O(n·m)
static void eslestir(int[] dizi1, int[] dizi2) { for (int oge1 : dizi1) // n kez for (int oge2 : dizi2) // m kez if (oge1 == oge2) System.out.println( "Eşleşen öğe: " + oge1); }
- Her
dizi1öğesi,dizi2'nin her öğesiyle karşılaştırılır: n·m karşılaştırma. - İki dizi de n öğeliyse 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).
Karmaşıklık · Kodu adım adım çalıştır
Kod İzleme: eslestir()
Dış döngü: oge1 = 3; iç döngü dizi2'yi baştan tarar. 3 ≠ 5.
3 ≠ 1.
3 == 3 → eşleşme.
Eşleşme yazdırılır; iç döngü yine de sonuna kadar devam eder.
3 ≠ 8.
Dış döngü: oge1 = 7; iç döngü dizi2'yi baştan tarar. 7 ≠ 5.
7 ≠ 1.
7 ≠ 3.
7 ≠ 8.
5 == 5 → eşleşme.
Eşleşme yazdırılır; iç döngü yine de sonuna kadar devam eder.
5 ≠ 1.
5 ≠ 3.
5 ≠ 8.
Bitti: 3 × 4 = 12 karşılaştırma = n·m. İki dizi de n öğeliyse O(n²).
static void eslestir(int[] dizi1, int[] dizi2) { for (int oge1 : dizi1) // n kez for (int oge2 : dizi2) // m kez if (oge1 == oge2) System.out.println( "Eşleşen öğe: " + oge1); }
Karmaşıklık · Kodu adım adım çalıştır
Araya Ekleme: Sağa Kaydırma, O(n)
Kapasite 6, dolu 5 hücre. 4'ü indis 1'e eklemek için önce yer açılmalı.
k = 5: a[5] = a[4] = 1 (bir sağa kopyalandı). Sağdan başlanır: soldan başlasaydık 2, 9'un üzerine yazardı.
k = 4: a[4] = a[3] = 5 (bir sağa kopyalandı).
k = 3: a[3] = a[2] = 9 (bir sağa kopyalandı).
k = 2: a[2] = a[1] = 2 (bir sağa kopyalandı).
k = 1, 1 > 1 yanlış → döngü biter. 4 kaydırma yapıldı; a[1] ve a[2] şu an aynı (2).
Açılan yere yazılır: a[1] = 4.
return 6. Başa eklemek n, ortaya ≈ n/2 kaydırma → O(n); sona eklemek (yer varsa) O(1).
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 }
Dizi doluysa (boyut == a.length) önce daha büyük bir dizi oluşturulup kopyalanır: O(n).
Karmaşıklık · Kodu adım adım çalıştır
Aradan Silme: Sola Kaydırma, O(n)
Önceki eklemeden sonra: a[1] = 4 silinecek. Boşluk kalmaması için sağdakiler sola kayar.
k = 1: a[1] = a[2] = 2. Bu kez soldan başlanır: silinen değerin üzerine yazılır.
k = 2: a[2] = a[3] = 9.
k = 3: a[3] = a[4] = 5.
k = 4: a[4] = a[5] = 1.
k = 5 < 5 yanlış → döngü biter. 4 kaydırma.
Son hücrede eski değerin kopyası kalmıştı; 0 yazılır (nesne dizilerinde null: GC için önemli).
return 5. Baştan silme n − 1 kaydırma → O(n); sondan silme O(1).
static int sil(int[] a, int boyut, int indis) { for (int k = indis; k < boyut - 1; k++) a[k] = a[k + 1]; // sola kaydır a[boyut - 1] = 0; // eski son hücreyi temizle return boyut - 1; // yeni boyut }
Karmaşıklık
Dizi Sıralama: Zaman Karmaşıklığı
Sıralamanın maliyeti kullanılan algoritmaya bağlıdır:
| Algoritma | En iyi | Ortalama | En kötü | Ek bellek |
|---|---|---|---|---|
| Kabarcık sıralaması (Bubble Sort) | O(n)* | O(n²) | O(n²) | O(1) |
| Seçimli sıralama (Selection Sort) | O(n²) | O(n²) | O(n²) | O(1) |
| Eklemeli sıralama (Insertion Sort) | O(n) | O(n²) | O(n²) | O(1) |
| Hızlı sıralama (Quick Sort) | O(n log n) | O(n log n) | O(n²) | O(log n) |
| Birleştirme sıralaması (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 öğe 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 · Kodu adım adım çalıştır
Seçimli Sıralama (Selection Sort)
int[] dizi = {64, 25, 12, 22, 11}; int n = dizi.length; for (int i = 0; i < n - 1; i++) { int minIndis = i; for (int j = i + 1; j < n; j++) if (dizi[j] < dizi[minIndis]) minIndis = j; // takas: indislerle, yerinde int gecici = dizi[minIndis]; dizi[minIndis] = dizi[i]; dizi[i] = gecici; }
Sırasız 5 öğeli dizi. Her tur, sıralanmamış kısmın en küçüğünü o kısmın başına getirecek.
1. tur: sıralanmamış kısım indis 0'dan başlar; şimdilik en küçük dizi[0] = 64.
25 < 64 → minIndis = 1.
12 < 25 → minIndis = 2.
22 < 12 yanlış → değişmez.
11 < 12 → minIndis = 4.
Takas: dizi[0] ↔ dizi[4] (64 ↔ 11). İndis 0 artık kesin yerinde.
2. tur: sıralanmamış kısım indis 1'den başlar; şimdilik en küçük dizi[1] = 25.
12 < 25 → minIndis = 2.
22 < 12 yanlış → değişmez.
64 < 12 yanlış → değişmez.
Takas: dizi[1] ↔ dizi[2] (25 ↔ 12). İndis 1 artık kesin yerinde.
3. tur: sıralanmamış kısım indis 2'den başlar; şimdilik en küçük dizi[2] = 25.
22 < 25 → minIndis = 3.
64 < 22 yanlış → değişmez.
Takas: dizi[2] ↔ dizi[3] (25 ↔ 22). İndis 2 artık kesin yerinde.
4. tur: sıralanmamış kısım indis 3'ten başlar; şimdilik en küçük dizi[3] = 25.
64 < 25 yanlış → değişmez.
En küçük zaten yerinde (minIndis = i = 3); takas kendisiyle yapılır, dizi değişmez. Son öğe de kendiliğinden yerinde → sıralandı: 4 + 3 + 2 + 1 = 10 = n(n−1)/2 karşılaştırma, O(n²).
Java'da parametreler değerle geçer: yerDegistir(dizi[minIndis], dizi[i]) yalnızca kopyaları değiştirir. Takas indislerle yapılmalı (ya da yerDegistir(dizi, i, minIndis)).
Karmaşıklık · Kodu adım adım çalıştır
Eklemeli Sıralama (Insertion Sort)
Sıralı kısım başta yalnız a[0]'dır (tek öğe her zaman sıralıdır). Her tur, sıradaki öğeyi sıralı kısımda doğru yerine kaydırarak yerleştirir.
Tur k = 1: anahtar = a[1] = 2 bir kenara alınır; hücresi artık boşluk sayılır.
a[0] = 5 > 2 → 5 bir sağa kayar; boşluk indis 0'a geçer.
j == 0: sıralı kısmın başına gelindi; a[0] = 2. İlk 2 öğe artık sıralı.
Tur k = 2: anahtar = a[2] = 4 bir kenara alınır; hücresi artık boşluk sayılır.
a[1] = 5 > 4 → 5 bir sağa kayar; boşluk indis 1'e geçer.
a[0] = 2 ≤ 4: durulur; a[1] = 4. İlk 3 öğe artık sıralı.
Tur k = 3: anahtar = a[3] = 1 bir kenara alınır; hücresi artık boşluk sayılır.
a[2] = 5 > 1 → 5 bir sağa kayar; boşluk indis 2'ye geçer.
a[1] = 4 > 1 → 4 bir sağa kayar; boşluk indis 1'e geçer.
a[0] = 2 > 1 → 2 bir sağa kayar; boşluk indis 0'a geçer.
j == 0: sıralı kısmın başına gelindi; a[0] = 1. İlk 4 öğe artık sıralı.
Tur k = 4: anahtar = a[4] = 3 bir kenara alınır; hücresi artık boşluk sayılır.
a[3] = 5 > 3 → 5 bir sağa kayar; boşluk indis 3'e geçer.
a[2] = 4 > 3 → 4 bir sağa kayar; boşluk indis 2'ye geçer.
a[1] = 2 ≤ 3: durulur; a[2] = 3. Dizi sıralı. 7 kaydırma = dizideki ters sıralı çift (inversion) sayısı. En kötü O(n²), zaten sıralı dizide O(n).
static void eklemeliSirala(int[] a) { for (int k = 1; k < a.length; k++) { int anahtar = a[k]; int j = k; while (j > 0 && a[j - 1] > anahtar) { a[j] = a[j - 1]; // sağa kaydır j--; } a[j] = anahtar; // yerleş } }
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 öğeli bir dizi O(n) alan kaplar; bayt olarak miktar öğe tipine bağlıdır.
| Dizi tipi | Öğe başına | 100 öğe (yalnızca veri) |
|---|---|---|
int[] | 4 bayt | 400 bayt |
char[] (UTF-16) | 2 bayt | 200 bayt |
double[], long[] | 8 bayt | 800 bayt |
Object[] (referans) | 4 / 8 bayt | 400 / 800 bayt + nesneler |
length) vardır.Özet
Dizilerle Sık Yapılan Hatalar
<= son turda a[a.length]'e erişir → istisna.for (i = 0; i < a.length; i++)length / length()Dizide alan, String'de metot.a.length · s.length()= kopya değildirb = a aynı diziyi gösterir; kopya için clone / copyOf.int[] b = a.clone();== ile içerik== referansları karşılaştırır.Arrays.equals(a, b)println(a) tür@adres basar ([I@…).Arrays.toString(a)new int[3][] sonrası m[0][0] → NullPointerException.m[i] = new int[k];binarySearch yanlış sonuç verir; 2B dizide sütun sayısı için her satırda m[i].length kullanılmalıdır.Özet
Özet
= referansı kopyalar, Arrays.copyOf öğeleri.m[i][j].| İşlem | Maliyet | İşlem | Maliyet |
|---|---|---|---|
Erişim a[i] | O(1) | Araya ekleme / silme | O(n) |
| Doğrusal arama | O(n) | Tersine çevirme | O(n) |
| Seçimli sıralama | O(n²) | Transpoz (m×n) | O(m·n) |
Özet
Örnek Problemler
int[] a = new int[4];sonrasıa[4]ifadesi ne olur?a.lengthkaçtır?int[] b = a; b[0] = 9;sonrasıa[0]kaçtır? Neden?- n öğeli dizide en büyük öğeyi bulan metodu yazın. Karmaşıklığı nedir?
- {5, 1, 4, 2, 8} dizisine seçimli sıralamanın ilk iki turundan sonra dizi nasıl görünür?
- 1000 öğeli
double[]dizinin veri kısmı kaç bayttır? - 3×4 bir matrisin transpozu kaç satır, kaç sütundur?
t[2][1]hangi öğedir?
Cevapları göster
ArrayIndexOutOfBoundsException(geçerli indisler 0–3);a.length= 4.- 9:
bveaaynı dizi nesnesini gösterir. int max = a[0]; for (int x : a) if (x > max) max = x;→ O(n) (boş dizi ayrıca kontrol edilmeli).- 1. tur: {1, 5, 4, 2, 8}; 2. tur: {1, 2, 4, 5, 8}.
- 1000 × 8 = 8000 bayt (+ dizi başlığı).
- 4 satır, 3 sütun;
t[2][1] = m[1][2].
Özet
Alıştırmalar
int[] a = {3, 1, 2}; int[] b = a; b = new int[] {9};sonrasıa[0]veb.lengthkaçtır?- {7, 3, 5, 1} dizisine eklemeli sıralamada her dış turdan sonra dizi nedir? Kaç kaydırma yapılır?
int[][] m = new int[3][]; m[1] = new int[4];sonrasım.length,m[1].length,m[0]nedir?- Yeri olan sıralı diziye, sırayı bozmadan öğe eklemenin en kötü maliyeti nedir?
sifrele("XYZ", 2)ne döndürür? Çözmek içinkkaç olmalı?- Diziyi yerinde bir adım sola döndüren (
a[0]sona gider) metodu yazın. Maliyeti?
Cevaplar / ipuçları
- 3 ve 1:
b'ye yeni dizi atamaka'yı etkilemez. - {3, 7, 5, 1} → {3, 5, 7, 1} → {1, 3, 5, 7}; 5 kaydırma (ters sıralı çift sayısı).
- 3, 4,
null(m[0][0]→NullPointerException). - O(n): yer O(log n)'de bulunsa da sağdakiler kaydırılır.
"ZAB"(Y: 26 % 26 = 0 → A);k = 24.t = a[0];öğeleri bir sola kaydır,a[n-1] = t;→ O(n) zaman, O(1) ek bellek.
Ö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
ArraysveSystemAPI belgeleri.