Çok Boyutlu Diziler - Matrisler

Verileri satır ve sütunlardan oluşan tablolar halinde saklayan yapıdır

🗂️ Veri Yapıları 📅 20 February 2026 👁️ 16 görüntülenme

Matris Nedir?

Matris, verilerin satır ve sütunlardan oluşan iki boyutlu bir tablo yapısında saklandığı veri yapısıdır. Tek boyutlu diziler verileri yan yana bir sıra halinde tutarken, matrisler verileri bir ızgara (grid) üzerinde organize eder. Matematikteki matris kavramıyla doğrudan ilişkilidir ve programlamada çok boyutlu dizi (multi-dimensional array) olarak adlandırılır.

Bunu bir elektronik tabloya (Excel) benzetebilirsiniz: her hücrenin bir satır numarası ve bir sütun numarası vardır. "3. satır, 2. sütun" dediğinizde tam olarak hangi hücreden bahsettiğiniz bellidir. İşte matris de bellekte tam olarak bu mantıkla çalışır.

3×4 Matris Yapısı (3 Satır, 4 Sütun)
sütun 0
sütun 1
sütun 2
sütun 3
satır 0
10
20
30
40
satır 1
50
60
70
80
satır 2
90
10
11
12
Erişim: matris[satır][sütun] → matris[1][2] = 70

Temel Kavramlar ve Terminoloji

Satır (Row) ve Sütun (Column)

Matristeki yatay sıralara satır, dikey sıralara sütun denir. Bir matrisin boyutu her zaman "satır × sütun" (m × n) şeklinde ifade edilir. Örneğin 3×4'lük bir matris 3 satır ve 4 sütundan oluşur, toplamda 12 eleman içerir. Satır sayısı her zaman önce yazılır; bu evrensel bir kural olduğu için karıştırmamaya dikkat etmek gerekir.

Kare Matris (Square Matrix)

Satır ve sütun sayısı eşit olan matrislere kare matris denir. Örneğin 3×3, 4×4, n×n boyutundaki matrisler kare matristir. Kare matrislerin köşegen (diagonal) elemanları, determinant hesabı ve birim matris gibi özel kavramları vardır. Bu özellikler özellikle lineer cebir ve bilgisayar grafiği uygulamalarında çok önemlidir.

Köşegen (Diagonal) Nedir?

Kare bir matriste sol üst köşeden sağ alt köşeye uzanan elemanlara ana köşegen (main diagonal) denir. Bu elemanların ortak özelliği satır ve sütun indekslerinin eşit olmasıdır: matris[i][i].

3×3 Kare Matris — Ana Köşegen
1
2
3
4
5
6
7
8
9
Köşegen elemanlar: [0][0]=1, [1][1]=5, [2][2]=9

Birim Matris (Identity Matrix)

Köşegen elemanları 1, diğer tüm elemanları 0 olan kare matrise birim matris denir. Birim matris, çarpma işleminde etkisiz elemandır: herhangi bir matrisi birim matris ile çarptığınızda sonuç yine kendisidir. Matematikte sayılar için 1'in oynadığı rolü, matrisler dünyasında birim matris üstlenir.

3×3 Birim Matris (Identity Matrix)
1
0
0
0
1
0
0
0
1

Matris Bellekte Nasıl Saklanır?

İşte matrislerle ilgili en kritik nokta burası: bilgisayarın belleği tek boyutludur. RAM'de "satır" veya "sütun" diye bir kavram yoktur; bellek ardışık byte'lardan oluşan düz bir şerittir. Peki iki boyutlu bir yapı tek boyutlu bir bellekte nasıl saklanır? Bunun iki yöntemi vardır.

Row-Major Order (Satır Öncelikli)

C, C++, Java, Python (NumPy) gibi diller bu yöntemi kullanır. Matrisin satırları bellekte birbiri ardına dizilir. Yani önce 0. satırın tüm elemanları, ardından 1. satırın tüm elemanları şeklinde devam eder.

Row-Major Order — Bellekteki Görünüm
Mantıksal Görünüm (2D)
1
2
3
4
5
6
7
8
9
↓ bellekte şöyle saklanır ↓
Fiziksel Görünüm (1D — Bellek)
1
2
3
4
5
6
7
8
9
 
satır 0
satır 1
satır 2

Column-Major Order (Sütun Öncelikli)

Fortran, MATLAB ve R gibi diller bu yöntemi kullanır. Matrisin sütunları bellekte birbiri ardına dizilir. C dilinde çalıştığımız için biz row-major order ile ilgileneceğiz, ancak bu farkı bilmek önemlidir çünkü farklı diller arasında veri aktarırken veya performans optimizasyonu yaparken bu bilgiye ihtiyaç duyarsınız.

Adres Hesaplama Formülü (Row-Major)

Bir matristeki herhangi bir elemanın bellek adresini şu formülle hesaplayabilirsiniz:

Adres = Başlangıç + (satır × sütun_sayısı + sütun) × eleman_boyutu
m[0][0] → 0x200 + (0×3 + 0) × 4 = 0x200
m[0][2] → 0x200 + (0×3 + 2) × 4 = 0x208
m[1][0] → 0x200 + (1×3 + 0) × 4 = 0x20C
m[1][2] → 0x200 + (1×3 + 2) × 4 = 0x214
m[2][1] → 0x200 + (2×3 + 1) × 4 = 0x21C
Performans ipucu: Row-major düzende satır satır dolaşmak, sütun sütun dolaşmaktan çok daha hızlıdır. Çünkü ardışık bellek adreslerine erişim CPU önbelleği (cache) ile uyumludur. Bu kavrama "cache locality" denir ve büyük matrislerde performans farkı 10 kata kadar çıkabilir.

Matris Oluşturma

C dilinde iki boyutlu dizi tanımlamanın birkaç farklı yolu vardır:

matris_olusturma.c
// Yöntem 1: Boyut belirleyip sonra değer atama
int matris[3][4];
matris[0][0] = 10;
matris[0][1] = 20;
// ... tek tek atama

// Yöntem 2: Tanımlarken değer atama (en yaygın)
int matris[3][4] = {
    {10, 20, 30, 40},    // satır 0
    {50, 60, 70, 80},    // satır 1
    {90, 100, 110, 120}  // satır 2
};

// Yöntem 3: Düz liste olarak (satır satır sırayla)
int matris[3][4] = {10,20,30,40,50,60,70,80,90,100,110,120};

// Yöntem 4: Kısmi atama (geri kalanlar 0 olur)
int matris[3][4] = {
    {10, 20},     // → {10, 20, 0, 0}
    {30},          // → {30, 0, 0, 0}
    {40, 50, 60}  // → {40, 50, 60, 0}
};

// Yöntem 5: Tamamını sıfırlama
int matris[3][4] = {0};  // tüm elemanlar 0
Önemli: C dilinde iki boyutlu dizi tanımlarken satır sayısını boş bırakabilirsiniz ama sütun sayısını asla boş bırakamazsınız. Bunun nedeni derleyicinin bellekte ne kadar yer ayıracağını hesaplayabilmesi için sütun sayısını bilmesi gerektiğidir.

int m[][4] = {{1,2,3,4}, {5,6,7,8}}; ✅ Geçerli
int m[2][] = {{1,2,3,4}, {5,6,7,8}}; ❌ Derleme hatası

Satır ve Sütun Erişimi

Matristeki herhangi bir elemana matris[satır][sütun] şeklinde erişilir. İlk indeks satırı, ikinci indeks sütunu belirtir. Tek boyutlu dizilerde olduğu gibi indeksler 0'dan başlar.

erisim.c
int m[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// Tek bir elemana erişim
printf("%d\n", m[0][0]);  // 1 (sol üst köşe)
printf("%d\n", m[1][2]);  // 6 (2. satır, 3. sütun)
printf("%d\n", m[2][2]);  // 9 (sağ alt köşe)

// Belirli bir satırın tüm elemanlarını yazdır (satır 1)
for (int j = 0; j < 3; j++) {
    printf("%d ", m[1][j]);  // 4 5 6
}

// Belirli bir sütunun tüm elemanlarını yazdır (sütun 2)
for (int i = 0; i < 3; i++) {
    printf("%d ", m[i][2]);  // 3 6 9
}
m[1][2] = 6'ya Erişim
[0]
[1]
[2]
[0]
1
2
3
[1]
4
5
6
[2]
7
8
9
Satır 1 (turuncu) → Sütun 2 (kesişim) → Değer: 6

Matris Dolaşma (Traverse)

Matristeki tüm elemanları ziyaret etmek için iç içe iki döngü kullanılır. Dıştaki döngü satırlar, içteki döngü sütunlar üzerinde ilerler. Bu yapı matris işlemlerinin neredeyse tamamının temelini oluşturur.

traverse.c
#include <stdio.h>

int main() {
    int m[3][4] = {
        {10, 20, 30, 40},
        {50, 60, 70, 80},
        {90, 100, 110, 120}
    };

    int satir = 3, sutun = 4;

    for (int i = 0; i < satir; i++) {
        for (int j = 0; j < sutun; j++) {
            printf("%4d", m[i][j]);
        }
        printf("\n");
    }

    return 0;
}

// Çıktı:
//   10  20  30  40
//   50  60  70  80
//   90 100 110 120

Satır Satır mı, Sütun Sütun mu?

Bu soru basit gibi görünse de performans açısından büyük öneme sahiptir. C dilinde matrisler row-major order ile saklandığı için satır satır dolaşmak (row-wise traversal) bellekteki ardışık adresleri takip eder ve CPU cache'ini verimli kullanır. Sütun sütun dolaşmak ise (column-wise traversal) her adımda belleğin farklı bölgelerine atlar ve cache miss'lere neden olur.

cache_karsilastirma.c
// ✅ HIZLI: Satır satır dolaşma (cache-friendly)
for (int i = 0; i < SATIR; i++)
    for (int j = 0; j < SUTUN; j++)
        toplam += m[i][j];  // bellekte ardışık erişim

// ❌ YAVAŞ: Sütun sütun dolaşma (cache-unfriendly)
for (int j = 0; j < SUTUN; j++)
    for (int i = 0; i < SATIR; i++)
        toplam += m[i][j];  // bellekte zıplama
Ne kadar fark eder? 10000×10000'lik bir matris üzerinde yapılan testlerde, satır satır dolaşma sütun sütuna göre tipik olarak 3-10 kat daha hızlı çalışır. Bu fark matris büyüdükçe daha da belirginleşir.

Matris Toplama

İki matrisin toplanabilmesi için boyutlarının aynı olması gerekir. Toplama işleminde karşılıklı elemanlar bire bir toplanır: A matrisinin [i][j] elemanı ile B matrisinin [i][j] elemanı toplanarak C matrisinin [i][j] elemanı elde edilir.

A + B = C
Matris A
1
2
3
4
5
6
+
Matris B
7
8
9
1
2
3
=
Matris C
8
10
12
5
7
9
matris_toplama.c
#define SATIR 2
#define SUTUN 3

void matrisTopla(int A[SATIR][SUTUN], int B[SATIR][SUTUN], int C[SATIR][SUTUN]) {
    for (int i = 0; i < SATIR; i++) {
        for (int j = 0; j < SUTUN; j++) {
            C[i][j] = A[i][j] + B[i][j];
        }
    }
}

// Kullanım:
int A[2][3] = {{1,2,3}, {4,5,6}};
int B[2][3] = {{7,8,9}, {1,2,3}};
int C[2][3];
matrisTopla(A, B, C);
// C = {{8,10,12}, {5,7,9}}

Matris Çarpma

Matris çarpma, toplama kadar basit değildir. İki matrisin çarpılabilmesi için birinci matrisin sütun sayısı ile ikinci matrisin satır sayısının eşit olması gerekir. A matrisi m×n ve B matrisi n×p boyutundaysa, sonuç C matrisi m×p boyutunda olur.

Çarpma işleminde C[i][j] değeri, A'nın i. satırı ile B'nin j. sütununun karşılıklı elemanlarının çarpılıp toplanmasıyla elde edilir. Bu işleme "dot product" (iç çarpım) denir.

A(2×3) × B(3×2) = C(2×2)
A (2×3)
1
2
3
4
5
6
×
B (3×2)
7
8
9
10
11
12
=
C (2×2)
58
64
139
154
C[0][0] = (1×7) + (2×9) + (3×11) = 7 + 18 + 33 = 58
matris_carpma.c
#define M 2  // A satır sayısı
#define N 3  // A sütun = B satır sayısı
#define P 2  // B sütun sayısı

void matrisCarp(int A[M][N], int B[N][P], int C[M][P]) {
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < P; j++) {
            C[i][j] = 0;  // önce sıfırla
            for (int k = 0; k < N; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

// Kullanım:
int A[2][3] = {{1,2,3}, {4,5,6}};
int B[3][2] = {{7,8}, {9,10}, {11,12}};
int C[2][2];
matrisCarp(A, B, C);
// C = {{58, 64}, {139, 154}}
Karmaşıklık: Matris çarpma O(n³) zaman karmaşıklığına sahiptir. 1000×1000'lik iki matrisi çarpmak yaklaşık 1 milyar çarpma ve toplama işlemi gerektirir. Bu yüzden büyük matrislerle çalışan uygulamalar (yapay zeka, bilgisayar grafikleri) GPU gibi paralel işlem birimlerine ihtiyaç duyar.

Transpose Alma

Bir matrisin transpozu, satır ve sütunlarının yer değiştirilmesiyle elde edilir. Yani orijinal matrisin [i][j] elemanı, transpoze matrisin [j][i] elemanı olur. Bir m×n matrisin transpozu n×m boyutundadır.

Transpose işlemi lineer cebirde çok sık kullanılır. Örneğin bir veri tablosunun satır ve sütunlarını değiştirmek, kovaryans matrisi hesaplamak veya bir denklem sistemini çözmek için transpose'a ihtiyaç duyarsınız.

Transpose: Satır → Sütun, Sütun → Satır
Orijinal A (2×3)
1
2
3
4
5
6
→ Aᵀ
Transpose Aᵀ (3×2)
1
4
2
5
3
6
A'nın 1. satırı (1,2,3) → Aᵀ'nin 1. sütunu oldu
transpose.c
#define SATIR 2
#define SUTUN 3

void transpose(int A[SATIR][SUTUN], int T[SUTUN][SATIR]) {
    for (int i = 0; i < SATIR; i++) {
        for (int j = 0; j < SUTUN; j++) {
            T[j][i] = A[i][j];  // satır↔sütun yer değiştir
        }
    }
}

// Kare matris için yerinde (in-place) transpose
void transposeInPlace(int m[3][3], int n) {
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {  // j = i+1 dikkat!
            int temp = m[i][j];
            m[i][j] = m[j][i];
            m[j][i] = temp;
        }
    }
}
Neden j = i + 1? Kare matrisin yerinde transpozunu alırken j = 0'dan başlarsanız her elemanı iki kez yer değiştirirsiniz ve sonuçta orijinal matrise geri dönersiniz. Sadece köşegenin üstündeki elemanları yer değiştirmek yeterlidir, köşegen elemanları zaten yerinde kalır.

Matrisi Fonksiyona Geçirme

C dilinde iki boyutlu diziyi fonksiyona geçirmek, tek boyutlu diziye göre biraz daha karmaşıktır. Fonksiyon parametresinde sütun sayısını belirtmek zorunludur. Bu kısıtlama, derleyicinin adres hesaplamasını yapabilmesi için gereklidir.

fonksiyona_gecirme.c
// Yöntem 1: Sabit sütun sayısı ile (en yaygın)
void yazdir(int m[][4], int satir) {
    for (int i = 0; i < satir; i++) {
        for (int j = 0; j < 4; j++)
            printf("%4d", m[i][j]);
        printf("\n");
    }
}

// Yöntem 2: Pointer ile (daha esnek, C99+)
void yazdir2(int satir, int sutun, int m[satir][sutun]) {
    for (int i = 0; i < satir; i++) {
        for (int j = 0; j < sutun; j++)
            printf("%4d", m[i][j]);
        printf("\n");
    }
}

// Yöntem 3: Tek boyutlu pointer olarak (en esnek)
void yazdir3(int *m, int satir, int sutun) {
    for (int i = 0; i < satir; i++) {
        for (int j = 0; j < sutun; j++)
            printf("%4d", *(m + i * sutun + j));
        printf("\n");
    }
}

Matrisler Nerelerde Kullanılır?

Görüntü İşleme

Dijital bir görüntü aslında bir piksel matrisidir. Siyah-beyaz bir görüntü tek bir 2D matris iken, renkli bir görüntü 3 ayrı matristen (Red, Green, Blue kanalları) oluşur. Bulanıklaştırma, keskinleştirme, kenar algılama gibi filtreler matrislerin birbirleriyle çarpılmasıyla gerçekleştirilir.

Bilgisayar Grafikleri ve Oyun Geliştirme

3D oyunlarda bir nesneyi döndürmek, taşımak veya ölçeklemek için 4×4 dönüşüm matrisleri kullanılır. Kameranın bakış açısı, ışık hesaplamaları ve perspektif projeksiyonu tamamen matris çarpımlarıyla yapılır. GPU'ların temel işi, saniyede milyarlarca matris çarpımı gerçekleştirmektir.

Yapay Zeka ve Derin Öğrenme

Sinir ağlarının her katmanı aslında bir matris çarpımıdır. Girdi verisi bir matris olarak temsil edilir, ağırlıklar başka bir matristir ve bunların çarpımı bir sonraki katmanın çıktısını verir. Modern derin öğrenme tamamen matris aritmetiği üzerine kuruludur.

Graflar ve Ağ Yapıları

Bir grafın düğümleri arasındaki bağlantılar komşuluk matrisi (adjacency matrix) ile temsil edilebilir. N düğümlü bir graf için N×N'lik bir matris oluşturulur. Eğer i. düğüm ile j. düğüm arasında bağlantı varsa matris[i][j] = 1, yoksa 0 olur. Bu konu müfredatın graf bölümünde detaylı ele alınacaktır.

Elektronik Tablo ve Veritabanları

Excel, Google Sheets gibi araçlar verilerini matris yapısında saklar. SQL'deki tablolar da kavramsal olarak bir matristir: her satır bir kayıt, her sütun bir alandır.

Zaman Karmaşıklığı Özeti

İşlemKarmaşıklıkAçıklama
Erişim m[i][j]O(1)Adres formülü ile doğrudan erişim
TraverseO(m × n)Her eleman bir kez ziyaret edilir
Matris ToplamaO(m × n)Karşılıklı elemanlar toplanır
Matris ÇarpmaO(m × n × p)Üçlü iç içe döngü gerektirir
TransposeO(m × n)Her eleman bir kez kopyalanır
Satır/Sütun AramaO(n) / O(m)Tek satır veya sütun taranır
Eleman AramaO(m × n)Tüm matris taranır

Sık Yapılan Hatalar

1. Satır ve Sütun İndeksini Karıştırmak

Matris işlemlerinde en sık yapılan hata, m[i][j] ile m[j][i]'yi karıştırmaktır. Özellikle çarpma ve transpose işlemlerinde bu hata çok yaygındır. Kodunuzda i'yi her zaman satır, j'yi her zaman sütun olarak kullanmayı alışkanlık haline getirin.

2. Çarpma İçin Boyut Uyumunu Kontrol Etmemek

A(m×n) ile B(n×p) çarpılabilir ama A(m×n) ile B(m×p) çarpılamaz. A'nın sütun sayısının B'nin satır sayısına eşit olması şarttır. Bu kontrolü yapmadan çarpma işlemine girişmek bellekte geçersiz bölgelere erişmeye neden olur.

3. Çarpma Sonuç Matrisini Sıfırlamamak

Matris çarpmada sonuç matrisinin her elemanı kümülatif toplama ile hesaplanır. Eğer başlangıçta C matrisini sıfırlamazsanız, içindeki çöp değerlerin üzerine toplama yapılır ve yanlış sonuçlar elde edersiniz.

sifirlamama_hatasi.c
// ❌ YANLIŞ: C matrisi sıfırlanmadı
int C[2][2];
for (int i = 0; i < 2; i++)
    for (int j = 0; j < 2; j++)
        for (int k = 0; k < 3; k++)
            C[i][j] += A[i][k] * B[k][j];  // çöp değer üzerine toplama!

// ✅ DOĞRU: Önce sıfırla
int C[2][2] = {0};  // veya döngü içinde C[i][j] = 0;
for (int i = 0; i < 2; i++)
    for (int j = 0; j < 2; j++) {
        C[i][j] = 0;
        for (int k = 0; k < 3; k++)
            C[i][j] += A[i][k] * B[k][j];
    }

Tek Boyutlu Dizi vs Matris Karşılaştırma

ÖzellikTek Boyutlu DiziMatris (2D Dizi)
Erişimarr[i]m[i][j]
BellekArdışık blokArdışık blok (row-major)
TraverseTek döngü — O(n)İç içe döngü — O(m×n)
Boyut bilgisi1 parametre (n)2 parametre (satır, sütun)
Kullanım alanıListeler, diziler, tamponlarTablolar, görüntüler, graflar
Fonksiyona geçirmeBoyut bilgisi opsiyonelSütun sayısı zorunlu

Sonuç

Matrisler, tek boyutlu dizilerin iki boyuta genişletilmiş halidir ve yazılımın pek çok alanında karşımıza çıkar. Bellekte nasıl saklandığını anlamak, özellikle performans gerektiren uygulamalarda doğru kararlar vermenizi sağlar. Row-major ve column-major kavramları, cache locality bilgisi ve adres hesaplama formülü, bir matrisin sadece "satır ve sütunlardan oluşan tablo" olmadığını gösterir.

Matris toplama ve çarpma gibi temel operasyonlar, ileride karşılaşacağınız yapay zeka, bilgisayar grafikleri ve graf algoritmaları konularının altyapısını oluşturur. Bu temeli sağlam attıysanız, bir sonraki konumuz olan bağlı listelere (linked list) geçmeye hazırsınız. Bağlı listeler, dizilerin en büyük zayıflığı olan sabit boyut ve ekleme/silme maliyetini çözmek için tasarlanmış yapılardır.

← Veri Yapıları