Anda di halaman 1dari 10

Temel Veri Yaplar

(Veri Yaplar 1. Blm)


Kaan Aslan
10 Haziran 2013

1. Giri
Programlarmzda tanmladmz nesneler ya tek paradan ya da birden fazla paradan oluurlar. Tek
paradan oluan nesnelerin trlerine tekil trler, birden fazla paradan oluan nesnelerin trlerine ise
bileik trler denilmektedir. rnein, int tr tekil bir trdr. nk int trden bir nesne tek paradan
olumaktadr. Halbuki diziler bileik trlerdir. Bir dizi trnden nesne tanmladmzda o nesne kendi
ierisinde birden fazla paradan oluur. rnein:
int a;

/* a, int trden */

Burada a int trden tekil bir nesnedir:

Fakat rnein:
int b[3];

/* b, int[3] trnden */

Burada b kendi ierisinde 3 tane nesneden oluan bileik bir nesnedir:

Benzer biimde:
struct POINT {
int x, y;
};
struct POINT pt;
Burada ekrandaki bir noktay temsil eden POINT yaps iki paradan olumaktadr: x ve y paralar:

Bileik trler iin ngilizce genellikle aggregate types terimi kullanlmaktadr. Diziler, yaplar, birlikler ve
snflar bileik trlerdir.

Belli bir amaca ynelik olarak organize edilmi bir grup nesnenin oluturduu toplulua veri yaps (data
structure) denilmektedir. Veri yaps denildiinde aklmza bir grup nesne gelir. Baz veri yaplar ok
gereksinim duyulan baz olgularn temsil edilmesinde kullanlr. Bunlara temel veri yaplar diyeceiz. Temel
veri yaplar genellikle programlama dillerinde, dile entegre edilmi bir biimde bulundurulmakta ve dilin
sentaksyla desteklenmektedir. rnein diziler (arrays), yaplar (structures), birlikler (unions), snflar
(classes) temel veri yaplardr ve pek ok programlama dili bunlar dilin bir paras olarak bnyesinde
bulundurmaktadr. Dier veri yaplar ise dil tarafndan dorudan desteklenmeseler de temel veri yaplar
kullanlarak prosedrel teknikte fonksiyonlarla, nesne ynelimli teknikte snflarla gerekletirilebilirler.
rnein bal listeler (linked lists) pek ok dilde programlama dili tarafndan dorudan
desteklenmemektedir. Fakat yaplar kullanlarak birtakm fonksiyonlarla bal listeler oluturulabilir.
Pek ok programlama dili bir sentaks ve semantik sunmann yan sra standart bir ktphaneye de
sahiptir. rnein C Programlama Dilinin fonksiyonlardan ve makrolardan oluan standart bir ktphanesi
vardr. C++ hem Cnin standart ktphanesini destekler hem de template tabanl ayr ve geni bir snf
ktphanesine de sahiptir. Benzer biimde C# ve Java ile alrken bu dillerin kullanld ortamlarn
sunmu olduu geni snf ktphanelerinden faydalanrz. te dil tarafndan dorudan desteklenmeyen
pek ok veri yaps szn ettiimiz bu ktphanelerde hazr olarak bulundurulmaktadr. Biz bu ortamlarda
alrken ou kez gereksinim duyduumuz veri yapsn sfrdan oluturmak yerine bize sunulan hazr
fonksiyonlar ya da snflar kullanrz. rnein dinamik bytlen diziler C++n standart ktphanesinde
vector isimli snfla, .NETin ve Java platformlarnn ktphanelerinde de ArrayList isimli snfla temsil
edilmektedir. Bu ortamlarda alan programclar dinamik bytlen dizilere gereksinim duyduklarnda
dorudan bu snflar kullanabilirler.
Veri yaplar konusunda ok karlalan dier bir kavram da Soyut Veri Trleri'dir (Abstract Data Types).
Bu kavram veri yapsn oluturan veriler ile onlar zerinde ilem yapan fonksiyonlardan oluan
organizasyonu belirtir. Buradaki soyutluk "ayrntlarn gz ard edilmesi ve dikkatin veri yaps zerinde
ilem yapan fonksiyonlara evrilmesi" srecini anlatmaktadr. Bylelikle soyut veri trlerini kullanan
programclar onlarn nasl gerekletirildii hakknda ayrntl bir bilgiye sahip olmak zorunda kalmazlar.
Soyut veri trleri nesne ynelimli dillerde tipik olarak snflarla gerekletirilirler.

2. Temel Veri Yaplar


Bu blmde pek ok programlama dilinde sentaks tarafndan dorudan desteklenen dizi, yap, birlik ve
snflar zerinde durulacaktr.

2.1. Diziler (Arrays)


Elemanlar ayn trden olan ve bellekte ardl bir biimde bulunan veri yaplarna dizi denir. Tanmda da
belirtildii gibi, diziyi dizi yapan iki nemli zellik vardr:
1) Dizi tipik olarak birden fazla elemandan oluur ve bu elemanlar ayn trdendir.
2) Dizi elemanlar bellekte ardl bir biimde tutulurlar.
Dizi elemanlarna O(1) karmaklkta yani ok hzl bir biimde eriilir. Eriim dizinin tm elemanlarna ayn
srede yaplmaktadr. (Bu tr eriim sistemlerine genellikle rastgele eriimli (random access) sistemler
denilmektedir.) phesiz dizi elemanlarna ok hzl eriilmesi onlarn bellee ardl yerletirilmelerinden
kaynaklanmaktadr.
Programlama dillerinde diziler tr ve uzunluk belirtilerek belli bir sentaksla oluturulurlar. rnein C ve
C++ta dizilerin tanmlanmas aadaki gibi bir sentaksla yaplmaktadr:
int a[10];

C ve C++ta dizilerin uzunlular sabit ifadesi (constant expression) biiminde verilmek zorundadr. nk
derleyici dizinin uzunluunu derleme zaman srasnda belirlemek ister [1]. Bu dillerde eer dizilerin gerek
uzunluu programn alma zaman srasnda belirleniyorsa bu durumda dizinin de programn alma
zaman srasnda dinamik olarak yaratlmas gerekir. rnein Cde malloc ve calloc gibi dinamik bellek
fonksiyonlar heap denilen alanda ardl byte tahsisat yaparlar. Elde edilen alann adresi bir gstericiye
atanrsa o blge bir dizi gibi kullanlabilir. rnein:
int *pi;
...
pi = (int *) malloc(sizeof(int) * 10);
C# ve Javada diziler de snfsal bir biimde temsil edilmilerdir. Bu dillerde diziler new operatr ile dinamik
olarak yaratlmak zorundadr. rnein:
int[] a;
a = new int[10];
Pekiyi dizilere neden gereksinim duyulmaktadr? Dizilerin en nemli faydas bir dng ierisinde bir indis
yardmyla elemanlar gzden geirebilmemizi salamasdr. rnein diziler olmasayd int trden 100 tane
nesneyi nasl tanmlayabileceinizi ve bunlarn hepsine nasl deer atayacanz bir dnn. Oysa diziler
sayesinde tek bir dng ile tm elemanlar gzden geirebiliyoruz. rnein, bir dizinin elemanlarnn
toplamn bulan kod yle olabilir:
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int i;
int total;
total = 0;
for (i = 0; i < 10; ++i)
total += a[i];
Dizi elemanlarnn bellekte ardl bir biimde bulunmas onlar yalnzca balang adresleri yoluyla
fonksiyonlara geirebilmemizi mmkn hale getirir. rnein:

int GetTotal(const int *pi, int size)


{
int k;
int total;
total = 0;
for (k = 0; k < size; ++k)
total += pi[k];
return total;
}
/*...*/
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int result;
result = GetTotal(a, 10);
C ve C++'ta dizi isimleri o dizilerin bellekteki balangcna ilikin adres bilgisi belirtirler. Baka bir deyile
dizi isimleri (yani dizi nesneleri) ileme sokulduunda derleyici tarafndan otomatik olarak adres bilgisine
dntrlmektedir. Yani biz programmzda bir dizi ismini kullandmzda aslnda o dizinin ilk elemannn

adresini kullanyor gibi oluruz. Yukardaki rneimizde Foo fonksiyonuna biraz daha genellik katmak iin
uzunluk parametresi de ekledik. Java ve C#'ta diziler zaten snfsal bir biimde temsil edildiklerinden dolay
onlarn uzunluu bu snfsal temsilin ierisinde zaten belirtilmektedir. Dolaysyla bu dillerde dizileri
parametre olarak alan metotlara ayrca uzunluk parametresi eklemeye gerek yoktur. C#ta Length
propertysi yoluyla, Javada da length eleman yoluyla dizi uzunluklar elde edilebilir. rnein:
public static int GetTotal(int[] a)
{
int total;
total = 0;
for (int i = 0; i < a.Length; ++i)
total += a[i];

// C#'ta Length, Java'da length

return total;
}
C# ve Java'da dizi isimleri dizi nesnelerinin adreslerine ilikin referans belirtmektedir. Bu dillerde bir dizi
referansn yle dnebiliriz:

2.2. Yaplar (Structures)


Elemanlar farkl trlerden olabilen ve bellekte ardl bir biimde bulunan veri yaplarna yap (structure)
denilmektedir. Yine buradaki ardllk yapnn balang adresinin bilinmesi durumunda onun tm
elemanlarna sabit zamanl, yani O(1) karmaklkta eriilmesini salar. yle ki, eer biz bir yap nesnesinin
balang adresini biliyorsak onun herhangi bir elemanna tek bir makine komutuyla eriebiliriz. Yap
elemanlar farkl trlerden olabildiine gre hangi elemann hangi trden olduunun da bir biimde
derleyiciye aklanmas gerekmektedir. Yap elemanlarnn trlerinin ve isimlerinin derleyiciye tantlmas
ilemine yap bildirimi denilmektedir. rnein C/C++'ta bir yap aadaki gibi bildirilir:
struct PERSON {
char name[32];
int no;
float weight;
};
Bu bildirimle derleyici bileik yap nesnesinin hangi paralarnn hangi trden olduunu ve offsetten
baladn anlar.

rnein per.no ya da per.weight gibi ifadelerle yapnn elemanlarna eriilmesi tek bir makina komutuyla
yaplabilmektedir. Benzer biimde p bir yap nesnesinin adresini belirtiyor olsun. p->no ve p->weight gibi
eriimler
de
yap
elemanlarnn
ardl
olmasndan
dolay
birka
makina
komutuyla
gerekletirilebilmektedir. Pekiyi yaplarn bize salad yararlar nelerdir?
1) Yaplar gerek bir nesnenin ya da kavramn birbirleriyle ilikili birtakm zelliklerini temsil etmek iin
mantksal bir kme olutururlar. rnein bu sayede biz bir tarih bilgisini DATE isimli bir yapyla, bir noktay
POINT isimli bir yapyla temsil edebiliriz. Bu tr temsiller soyutlamay artrarak alglamay
kolaylatrmaktadr.
2) Yaplar farkl trlerden ok sayda bilgiyi fonksiyonlara tek bir parametre olarak geirmemize olanak
salarlar. rnein eer yap kavram olmasayd yukardaki PERSON yapsnn elemanlarn fonksiyonlara
tek tek geirmek zorunda kalrdk:
void Foo(char *name, int no, float weight);
...
Foo("Ahmet Kaya Aslan", 123, 78.3);
Halbuki yaplar sayesinde tm bu bilgileri tek bir parametreyle fonksiyona aktarabiliriz:
void Foo(const struct PERSON *per);
...
struct PERSON per = {"Ahmet Kaya Aslan", 123, 78.3};
Foo(&per);
Aktarm yap nesnesinin balang adresiyle yapld iin, yap ne kadar byk olursa olsun gerekte
fonksiyona aktarlan yalnzca bir adres bilgisidir (32 bit sistemlerde 4 byte, 64 bit sistemlerde 8 byte).
3) Fonksiyonlarn tek bir geri dn deeri vardr. Eer biz bir fonksiyondan birden fazla deer elde etmek
istiyorsak ona bir yap nesnesinin adresini gndererek onun o yap nesnesinin iini doldurmasn
salayabiliriz. rnein:
void Foo(const struct PERSON *per);
...
struct PERSON per;
Foo(&per);
Bu noktada yaplarla ilgili nemli bir anmsatma yapmak istiyoruz: C/C++ta yap elemanlar derleyici
tarafndan aralarnda boluklar olacak biimde bellee yerletirilebilmektedir. Yap elemanlarnn ve genel
olarak nesnelerin belirli saynn katlarnda olacak biimde bellee yerletirilmelerine hizalama (alignment)

deniyor. Pek ok modern ilemci, eer nesneler bellekte belli saynn katlarnda bulunuyorsa (rnein 32 bit
ilemcilerde 4'n katlarnda) onlara daha hzl eriebilmektedir. rnein, 32 bit Intel ilemcilerinde:
MOV EAX, [XXXXXXXX]
gibi bir makina komutu eer XXXXXXXX adresi 4'n katlarndaysa daha hzl almaktadr. Varsaylan
hizalama pek ok derleyicide DWORD yani 4'n katlar biimindedir. imdi hizalamann etkisini aadaki
gibi bir yapyla gsterelim:
struct SAMPLE {
char a;
int b;
short c;
};
4 byte'n (DWORD) katlarna gre yaplan hizalamada bir SAMPLE nesnesi bellee yle yerletirilecektir:

Grld gibi derleyici yap elemanlarn 4'n katlarna yerletirebilmek iin elemanlar arasna da
boluklar brakabilmektedir.
Javada C/C++taki gibi bir yap kavram yoktur fakat C#ta vardr. C#ta yaplar kategori olarak deer
trlerine (value types) ilikindir ve genel kullanm C/C++takine olduka benzemektedir.

2.3. Birlikler (Unions)


Elemanlarn akk olarak yerletirildii veri yaplarna birlik (union) denilmektedir. Birlikler C/C++ta
yaplara benzer bir sentaksla bildirilirler. rnein:
union SAMPLE {
char a;
int a;
double c;
};

Bir birlik iin birliin en byk eleman kadar yer ayrlr. Yukardaki rnekte birliin en byk eleman double
olduundan s isimli birlik nesnesi iin toplam 8 byte yer ayrlmtr. Birlik elemanlarnn akk
yerletirildiine dikkat ediniz. Elemanlarn bu biimde akk yerletirilmesi onlarn birinde deiiklik
yaplmas durumunda hepsinin bundan etkilenecei anlamna gelir. Birlikler iki amala kullanlmaktadr:
1) Farkl bilgilerden herhangi birinin ekonomik bir biimde tutulmas gerektii durumlarda. rnein bir
kiinin T.C. numaras ya da adresi yeterli ise bu bilginin akk olmas yer kazanc salar. Tabi bylesi
durumlarda hangi bilginin dolu olduunun ayrca bir bayrakla tutulmas gerekecektir.
2) Btn paralara ayrmak veya paralardan btn oluturmak iin. rnein 4 byte iaretsiz bir tamsay
trnn byte'larn ayr ayr oluturup onu bir btn olarak almak ya da btn oluturup herhangi bir
byte'n elde etmek iin yle bir birlik oluturulabilir:
union DWORD {
unsigned int dword;
struct {
unsigned char b0, b1, b2, b3;
} bytes;
};

dw.bytes.b0
dw.bytes.b1
dw.bytes.b2
dw.bytes.b3

=
=
=
=

0x12;
0x34;
0x56;
0x78;

printf("%x\n", dw.dword);
/* Litte Endian: 0x78563412, Big Endian:

0x12345678 */

Yukardaki rnekte 4 byte'lk bir nesnenin byte'larna srasyla baz deerler yerletirilmi ve deerin btn
elde edilmitir. Bir byte'tan uzun olan nesnelerin isel byte yerleimlerinin ilemcinin Endian'lk durumuna
gre deiebileceini anmsaynz. Intel gibi Little Endian ilemciler saylar dk anlaml byte deerleri
dk adreste olacak biimde yerletirirler.
Java'da C/C++'taki gibi birlik veri yaps yoktur. Fakat yukardaki birinci maddede belirttiimiz farkl
bilgilerden herhangi birinin ekonomik bir biimde tutulmas amacn gerekletirmek iin yapay bir birlik
temsili oluturulabilir. Bunun iin bir taban snf alnr. Bu snftan iki ayr snf tretilir. Bu iki ayr snf iki ayr
bilgiyi temsil etmektedir. Taban snfn sanal metotlaryla tremi snfn veri elemanlarna eriim yaplabilir:
class U<A, B>
{
public A getA() { return null; }
public B getB() { return null; }
}
class UA<A, B> extends U<A, B>
{
private A m_a;
public UA(A a)
{
m_a = a;
}
public A getA()
{
return m_a;
}
//...
}
class UB<A, B> extends U<A, B>
{
private B m_b;
public UB(B b)
{
m_b = b;
}
public B getB()
{
return m_b;
}
//...
}

C#ta birlik etkisi yaratmak iin snf ya da yap StructLayoutAttribute snf ile, veri elemanlar da
FieldOffsetAttribute snf ile zniteliklendirilir. FieldOffsetAttribute znitelik snf ilgili elemann belli offset'te
bulunmasn salamaktadr. rnein:
[StructLayout(LayoutKind.Explicit)]
public struct DWord
{
[FieldOffset(0)] public byte b0;
[FieldOffset(1)] public byte b1;
[FieldOffset(2)] public byte b2;
[FieldOffset(3)] public byte b3;
[FieldOffset(0)] public uint dword;
}
//...
DWord dw = new DWord();
dw.b0
dw.b1
dw.b2
dw.b3

=
=
=
=

0x12;
0x34;
0x56;
0x78;

Console.WriteLine("{0:X4}", dw.dword);
// Little Endian: 78563412, Big Endian: 12345678

2.4. Snflar (Classes)


Snflar nesne ynelimli programlama (object oriented programming) tekniinin yap talarn oluturan
veri yaplardr. Nesne ynelimli programlama tekniinin tek bir cmleyle tanmn yapmak olanaksz olsa da
eksik bir biimde "snflar kullanlarak program yazma tekniidir" denebilir. Snflar nesne ynelimli
programlama tekniinde belli bir konudaki gerek bir nesneyi ya da kavram temsil etmek iin kullanlrlar.
Bir proje nesne ynelimli olarak modellenecekse nce projeye konu olan btn gerek nesneler ve
kavramlar snflarla temsil edilir; sonra snflar arasndaki ilikiler belirlenerek kodlama yaplr. Snflar hem
veri elemanlarn hem de fonksiyonlar tutan veri yaplardr. Snflar C'deki yaplarn fonksiyon ieren
biimlerine benzetilebilir. Snflarn veri elemanlar (data'lar) snflarn fonksiyonlar tarafndan ortak bir
biimde kullanlrlar. Snflarn veri eleman organizasyonu tamamen yaplara benzemektedir. Snflarn
fonksiyonlar snf nesnesi ierisinde yer kaplamazlar, fonksiyonlar mantksal olarak snfla
ilikilendirilmilerdir. Bir snf fonksiyonlara ya da veri elemanlarna sahip olmak zorunda deildir. Snflarn
veri elemanlar o dillerin standartlarnda aka belirtilmese de tpk yaplarda olduu gibi nesne ierisinde
ardl bir biimde yerletirilirler. rnein: [2]
class Sample {
public:
void Foo();
void Bar();
void Tar();
//...
private:
int m_a;
int m_b;
int m_c;
};

[1]:

Derleyicilerin dizi uzunluklarn derleme aamasnda belirlemeleri daha etkin kod retimini mmkn hale
getirmektedir. Tipik olarak derleyiciler yerel bir dizi iin yer ayrrken yn gstericisini (stack pointer) dizinin
byte uzunluu kadar geri ekerler. Baz dillerde dizi uzunluklarnn sabit ifadeleriyle belirlenmesi biiminde
bir zorunluluk yoktur. (rnein C99'da yerel dizi uzunluklar deikenlerle belirtilebiliyor). Bu dillerde dier
yerel deikenlerin yerlerinin belirlenmesi ek bir hesap ya da bellek alan gerektirdiinden etkinliin
azalaca sylenebilir.
[2]:

Nesne ynelimli programlama pek ok ayrnts olan bir programlama modelidir. Burada amacmz nesne
ynelimli programlama modeli hakknda bilgi vermek deil, bir veri yaps olarak snflar konusuna
deinmektir. Dolaysyla bu balamda bu kadar bilgiyi yeterli gryoruz.

10

Anda mungkin juga menyukai