Programlamaya Giriş ve Algoritmalar Araş. Gör. Yasemin POYRAZ İletişim: Tel : 0212 473 70 70-18563 E-mail :yasemin.poyraz@istanbul.edu.tr
DiZiLER Bellekte bitişik bir biçimde bulunan, ayni türden nesnelerin oluşturduğu veri yapısına dizi denir. Dizi veri yapısının en önemli özelliği, mantıksal bir ilişki içindeki aynı türden verilerin bellekte bitişik olarak tutulmasıdır. Bunun da uygulamalarda sağladığı fayda sudur: Dizinin bir elemanına, elemanın konum bilgisiyle değişmez bir zamanda ulaşılabilir. Yani dizinin eleman sayısı ne olursa olsun, konumu bilinen bir elemana ulaşım zamanı aynıdır. Bu da bazı uygulamaların etkin bir şekilde gerçekleştirilmesini kolaylaştırır. Dizilerin Tanımlanması Dizi tanımlamalarının genel biçimi: <tür> <dizi ismi> [<eleman sayısı>]; Yukarıdaki genel biçimde köseli ayraç, eleman sayısının seçimlik olduğunu değil, eleman sayısı bilgisinin köşeli ayraç içine yazılması gerektiğini gösteriyor. tür : Dizi elemanlarının türünü gösteren anahtar sözcüktür. dizi ismi : İsimlendirme kurallarına uygun olarak verilecek herhangi bir isimdir. eleman sayısı : Dizinin kaç elemana sahip olduğunu gösterir. Örnek dizi bildirimleri: double a[20]; int ave[10]; char path[80];
int x = 100; int a[x]; /* Geçersiz */ int b[5.]; /* Geçersiz */ int c[10 * 20]; int d[sizeof(int) * 100]; Dizi bildirimlerinde eleman sayısını belirten ifade yerine sıklıkla simgesel değişmezler kullanılır: #define ARRAY_SIZE 100 int a[ARRAY_SIZE]; Program içinde dizi boyutu yerine hep ARRAY_SIZE simgesel değişmezi kullanılabilir. Böylece programda daha sonra dizi boyutuna ilişkin bir değişiklik yapılmak istendiğinde, yalnızca simgesel değişmezin değerinin değiştirilmesi yeterli olur. Diğer değişken bildirimlerinde olduğu gibi, virgül ayracıyla ayrılarak, birden fazla dizi, tür belirten sözcüklerin bir kez kullanılmasıyla tanımlanabilir: int x[100], y[50], z[10]; x, y ve z, elemanları int türden olan dizilerdir. Diziler ve diğer nesneler türleri ayni olmak kaydıyla tek bir tanımlama deyimiyle tanımlanabilir: int a[10], b, c; a int türden 10 elemanlı bir dizi, b ve c int türden nesnelerdir.
Dizi elemanlarının her biri ayrı birer nesnedir Dizi elemanlarının her biri ayrı birer nesnedir. Dizi elemanlarına köseli ayraç işleciyle [] ulaşılabilir. T bir tür bilgisi olmak üzere T a[SIZE]; gibi bir dizinin ilk elemani a[0] son elemani ise a[SIZE - 1]‘ dır. Örnekler: dizi[20] /* a dizisinin 20 indisli yani 21. elemani olan nesne */ ave[0] /* ave dizisinin 0 indisli yani birinci elemani olan nesne */ total[j] /* total dizisinin j indisli elemani olan nesne*/ Görüldüğü gibi "bir dizinin n. elemanı" ve "bir dizinin n indisli elemanı" terimleri dizinin farkli elemanlarini belirtir. Bir dizinin n indisli elemani o dizinin n + 1 . elemanidir. Bir dizi tanımlaması ile karşılaşan derleyici, tanımlanan dizi için bellekte yer ayırır. Ayrılacak yer şüphesiz dizinin eleman sayisi * bir elemanin bellekte kapladigi yer kadar byte olur. Örneğin: int a[5]; gibi bir dizi tanımlaması yapığını düşünelim. Windows işletim sisteminde çalışıyorsa derleyici a dizisi için bellekte 4 * 5 = 20 byte yer ayırır.
Dizi indis ifadelerinde ++ ya da -- işleçleri sık kullanılır: int a[20]; int k = 10; int i = 5; a[k++] = 100; deyimiyle dizinin 10 indisli elemanına yani dizinin 11. elemanına 100 değeri atanıyor. Daha sonra k değişkeninin değeri 1 artırılarak 11 yapılıyor. a[--i] = 200; deyimiyle dizinin 4 indisli elemanına yani dizinin 5. elemanına 200 değeri atanıyor. Daha sonra i değişkeninin değeri 1 azaltılarak 4 yapılıyor. Köşeli ayraç işlecinin kullanilmasiyla artık dizinin herhangi bir elemanı diğer deişkenler gibi kullanılabilir. Aşağıdaki örnekleri inceleyin: a[0] = 1; a dizisinin ilk elemanına 1 değeri atanıyor. Diziler üzerinde işlem yapmak için sıklıkla döngü deyimleri kullanılır. Bir döngü deyimi yardımıyla bir dizinin tüm elemanlarına ulaşmak, çok karşılaşılan bir durumdur. Aşağıda SIZE elemanlı a isimli bir dizi için for ve while döngü deyimlerinin kullanıldığı bazı kalıplar gösteriliyor: a dizisinin bütün elemanlarına 0 değeri atanıyor: for (i = 0; i < SIZE; ++i) a[i] = 0; Ayni is bir şüphesiz bir while döngü deyimiyle de yapılabilirdi: i = 0; while (i < SIZE) a[i++] = 0;
Dizilerin Taşırılması Bir dizi tanımlamasını gören derleyici dizi için bellekte dizinin tüm elemanlarının sığacağı büyüklükte bir alan ayırır: double a[10]; Gibi bir tanımlama yapıldığında, çalışılan sistemde double türünün bellekte 8 byte yer kapladığı var sayılırsa, dizi için bellekte bitişik toplam 80 byte'lik bir yer ayrılır. Dizinin son elemanı a[9] olur. Çok sik yapılan bir hata, dizinin son elemanına ulaşmak amacıyla yanlışlıkla bellekte derleyici tarafından ayrılmamış bir yere değer atamak, yani diziyi taşırmaktır: a[10] = 5.; deyimiyle bellekte ne amaçla kullanıldığı bilinmeyen 8 byte' lık bir alana, yani güvenli olmayan bir bellek bölgesine değer aktarma girişiminde bulunulur. Dizi taşmaları derleme zamanında kontrol edilmez. Böyle hatalar programın çalışma zamanı ile ilgilidir. Dizilere İlkdeğer Verilmesi Değişken tanımlamalarında tanımlanan bir değişkenin "ilkdeğer verme sözdizimi" diye isimlendirilen bir kural ile belirli bir değerle başlatılması sağlanabiliyordu. Tanımlanan dizilere de ilkdeğer verilebilir: double sample[5] = {1.3, 2.5, 3.5, 5.8, 6.0}; char str[4] = {'d', 'i', 'z', 'i'}; unsigned a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; bir dizinin bütün elemanlarına 0 değeri verilmek isteniyorsa bunun en kısa yolu aşağıdaki gibidir: int a[20] = {0};
Bir diziye ilkdeğer verme işleminde, dizi eleman sayısından daha fazla sayıda ilkdeğer vermek geçersizdir: int b[5] = {1, 2, 3, 4, 5, 6}; /* Geçersiz */ Yukaridaki örnekte b dizisi 5 elemanli olmasina karsin, ilkdeger verme deyiminde 6 deger kullanılıyor. Bu durum derleme zamanında hata oluşturur. İlkdeger verme işleminde dizi boyutu belirtilmeyebilir. Bu durumda derleyici dizi uzunluğunu, verilen ilkdeğerleri sayarak kendi hesaplar. Dizinin o boyutta açıldığını kabul eder. Örneğin: int a[] = {1, 2, 3, 4, 5}; Derleyici yukarıdaki deyimi gördüğünde a dizisinin 5 elemanlı olduğunu kabul eder. Bu durumda yukarıdaki gibi bir bildirimle aşağıdaki gibi bir bildirim eşdeğerdir: int a[5] = {1, 2, 3, 4, 5}; Dizilerin Birbirine Atanması Dizilerin elemanları nesnedir. Ancak bir dizinin tamamı bir nesne olarak işlenemez: int a[SIZE], b[SIZE]; gibi bir tanımlamadan sonra, a dizisi elemanlarına b dizisinin elemanları kopyalanmak amacıyla, aşağıdaki gibi bir deyimin yazılması sözdizim hatasıdır. a = b; /* Geçersiz */ İki dizi birbirine ancak bir döngü deyimi ile kopyalanabilir: for (i = 0; i < SIZE; ++i) a[i] = b[i];
Dizilerin Kullanımına İlişkin Örnekler main işlevinde yer alan ilk for döngü deyimiyle a dizisinin elemanlarına standart rand işlevi çağrılarıyla 0 – 99 aralığında rastgele değerler atanıyor. Yine ayni döngü içinde dizinin her bir elemanının değeri ekrana yazdırılıyor. Bunu izleyen ikinci for deyimiyle a dizisinin her bir elemanının değeri sırasıyla toplam isimli değişkene katılıyor. #include <stdio.h> #include <stdlib.h> #include <time.h> #define SIZE 10 int main() { int a[SIZE]; int toplam = 0; int k; srand(time(0)); for (k = 0; k < SIZE; ++k) { a[k] = rand() % 100; printf("%d ", a[k]); } for (k = 0; k < SIZE; ++k) toplam += a[k]; printf("\na elemanlari toplami = %d\n", toplam); return 0;
min isimli değişken, dizinin en küçük elemanının değerini tutması için tanımlanıyor. Önce dizinin ilk elemanının dizinin en küçük elemanı olduğu var sayılıyor. Daha sonra bir for döngü deyimiyle dizinin 1 indisli elemanından başlanarak dizinin diğer elemanlarının değerlerinin min değişkeninin değerinden daha küçük olup olmadığı sınanıyor. Eğer dizinin herhangi bir elemanın değeri min değişkeninin değerinden daha küçük ise min değişkeninin değeri değiştiriliyor ve yeni bulunan elemanın değeri min değişkenine atanıyor. Döngü çıkısında artik min değişkeni, dizinin en küçük elemanının değerini tutar #include <stdio.h> #include <stdlib.h> #include <time.h> #define SIZE 10 int main() { int a[SIZE]; int toplam = 0; int k, min; srand(time(0)); for (k = 0; k < SIZE; ++k) { a[k] = rand() % 100; printf("%d ", a[k]); } min = a[0]; for (k = 1; k < SIZE; ++k) if (min > a[k]) min = a[k]; printf("\nen kucuk eleman = %d\n", min); return 0;
#include <stdio.h> #define SIZE 10 int main() { int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10}; int teklerinToplami = 0; int ciflerinToplami = 0; int tekSayisi = 0; int k; for (k = 0; k < SIZE; ++k) if (a[k] % 2) { teklerinToplami += a[k]; tekSayisi++; } else ciflerinToplami += a[k]; if (tekSayisi) printf("Teklerin ortalamasi = %lf\n",(double)teklerinToplami/tekSayisi); printf("Dizide tek sayi yok!\n"); if (SIZE - tekSayisi) printf("Ciftlerin ortalamasi = %lf\n",(double)ciflerinToplami/(SIZE - tekSayisi)); printf("Dizide cift sayi yok!\n"); return 0; Yandaki programda ise int türden bir dizinin tek ve çift sayı olan elemanlarının aritmetik ortalamaları ayrı ayrı hesaplanıyor
#include <stdio.h> #define SIZE 10 int main() { int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10}; int k; int searched_val; printf("aranacak degeri girin : "); scanf("%d", &searched_val); for (k = 0; k < SIZE; ++k) if (a[k] == searched_val) break; if (k < SIZE) printf("a[%d] = %d\n", k, a[k]); else printf("aranan deger dizide yok!\n"); return 0; } searched_val isimli değişken, dizide aranacak değeri tutmak için tanımlanıyor. Bu değişkenin değeri standart scanf işleviyle klavyeden alınıyor. Daha sonra oluşturulan bir for döngüsüyle, dizinin her bir elemanının aranan değere eşitliği döngü gövdesinde yer alan bir if deyimiyle sınanıyor. Eğer dizinin herhangi bir elemanı aranan değere eşit ise break deyimi ile döngüden çıkılıyor. Döngü çıkısında eğer döngü değişkeni olan k, SIZE değerinden küçük ise aranan değer bulunmuş yani döngüden break deyimi ile çıkılmıştır.
Dizinin elemanlarını küçükten büyüğe ya da büyükten küçüğe sıralamak için farklı algoritmalar kullanılabilir. Yanda, algısal karmaşıklığı çok yüksek olmayan "kabarcık sıralaması" isimli algoritma ile bir dizi sıralanıyor. #include <stdio.h> #define SIZE 10 int main() { int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10}; int i, k, temp; for (i = 0; i < SIZE - 1; ++i) for (k = 0; k < SIZE -1 - i; ++k) if (a[k] > a[k + 1]) { temp = a[k]; a[k] = a[k + 1]; a[k + 1] = temp; } for (k = 0; k < SIZE; ++k) printf("%d ", a[k]); return 0;
#include <stdio.h> #define SIZE 10 int main() { Dizinin ters çevrilmesi için dizi boyutunun yarısı kadar dönen bir döngü içinde, dizinin bastan n. elemanı ile sondan n. elemanı takas ediliyor. #include <stdio.h> #define SIZE 10 int main() { int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10}; int k; for (k = 0; k < SIZE / 2; ++k) { int temp = a[k]; a[k] = a[SIZE - 1 - k]; a[SIZE - 1 - k] = temp; } for (k = 0; k < SIZE; ++k) printf("%d ", a[k]); return 0;
#include <stdio.h> #include <stdlib.h> #include <time.h> #define KOLON_SAYISI 8 void kolon_yaz() { int numaralar[50] = {0}; int k, no; for (k = 0; k < 6; ++k) { while (numaralar[no = rand() % 49 + 1]) ; numaralar[no]++; } for (k = 1; k < 50; ++k) if (numaralar[k]) printf("%2d ", k); int main() int k; srand(time(0)); for (k = 0; k < KOLON_SAYISI; ++k) { printf("kolon %2d : ", k + 1); kolon_yaz(); printf("\n"); return 0; Yandaki program, rastgele üretilen bir sayısal loto kuponunu ekrana yazıyor:
Yandaki programda bir dizinin en büyük ikinci elemanının değeri bulunuyor. #include <stdio.h> #define SIZE 10 int main() { int a[SIZE] = {12, 34, 3, 56, 2, 23, 7, 18, 91, 4}; int k; int max1 = a[0]; int max2 = a[1]; if (a[1] > a[0]) { max1 = a[1]; max2 = a[0]; } for (k = 2; k < SIZE; ++k) if (a[k] > max1) { max2 = max1; max1 = a[k]; else if (a[k] > max2) max2 = a[k]; printf("en buyuk ikinci deger = %d\n", max2); return 0;
#include <stdio.h> #include <stdlib.h> #include <time.h> #define SIZE 100 int main() { int a[SIZE]; int i, k; int counter; srand(time(0)); for (k = 0; k < SIZE; ++k) { a[k] = rand() % 30; printf("%d ", a[k]); } for (i = 0; i < SIZE; ++i) { counter = 0; for (k = 0; k < SIZE; ++k) if (a[k] == a[i]) if (++counter == 2) break; if (counter == 1) printf("%d ", a[i]); printf("\n"); return 0; Yandaki programda yalnızca bir dizinin içinde tek olan elemanların değerleri ekrana yazdırılıyor.
#include <stdio.h> #include <stdlib.h> #include <time.h> #define SIZE 50 #define MAX 100 int main() { int a[SIZE]; int k,i,val; srand(time(0)); for (k = 0; k < SIZE; ++k) { while (1) { val = rand() % MAX; for (i = 0; i < k; ++i) if (val == a[i]) break; if (i == k) } a[k] = val; for (k = 0; k < SIZE; ++k) printf("%d ", a[k]); printf("\n"); return 0; Yandaki program SIZE elemanlı bir dizinin tüm elemanlarına 0 - MAX aralığında birbirinden farklı rastgele değerler yerleştiriyor.
#include <stdio.h> #define SIZE 10 int main() { int a[SIZE] = {2, 3, 6, 7, 8, 9, 13, 45, 78, 79}; int b[SIZE] = {1, 2, 4, 5, 7, 9, 10, 18, 33, 47}; int c[SIZE + SIZE]; int k; int index1 = 0, index2 = 0; for (k = 0; k < SIZE + SIZE; ++k) if (index1 == SIZE) c[k] = b[index2++]; else if (index2 == SIZE) c[k] = a[index1++]; else { if (a[index1] < b[index2]) else } printf("%d ", c[k]); return 0; Yandaki programda sıralı iki dizi, bir sıralı dizi biçiminde birleştiriliyor.