C++

Siyahılar

Siyahılar

Bu mövzuda biz C++ dilində yazılmış proqramlarda çox geniş istifadə olunan yeni tiplərlə - siyahılarla tanış olacağıq. Siyahıların C++ dilində tətbiqi olduqca genişdir və siyahısız C++ dilində yazılmış proqramları təsəvvür etmək mümkün deyil. Praktiki cəhətdən siyahılar cərgələrə oxşardır, onlar da cərgələr kimi özündə verilmiş tipdən olan elementlər ardıcıllığını saxlayır. Lakin siyahıların cərgələrdən fundamental üstün cəhətləri odur ki, cərgə elan edən zaman biz onun elementlərinin sayını əvvəlcədən elan etməliyiksə və sonra biz cərgəyə əlavə element yerləşdirə və ya onun elementlərinin sayını dəyişdirə bilməriksə, siyahının elementləri ilə istədiyimiz kimi manipulyasiya edə bilərik. Yəni proqramın icrası boyu biz siyahıya istənilən sayda yeni element əlavə edə və ya mövcud elementləri siyahıdan silə bilərik.

Misal üçün:

Kompüterdə hal-hazırda icra olunan proqramlara nəzarət etmək üçün nüvə task_struct adlı siyahıdan istifadə edir. İstifadəçi yeni proqramlar yüklədikcə, nüvə task-lar siyahısına yeni element əlavə edir və bu elementdə yeni proqram barədə müvafiq məlumatları (yükləndiyi yerin ünvanı, adı, təşkil olunduğu hissələr, açdığı fayllar, və s.) yerləşdirir. Daha sonra, hər hansı proqram sona çatdıqda nüvə müvafiq elementi task-lar siyahısından silir. Əgər bu zaman siyahı əvəzinə cərgədən istifadə olunsaydı, onda biz kompüterdə müəyyən saydan artıq proqram yükləyə bilməzdik.

Cərgənin elementlərinin sayını böyük götürdükdə isə, lazım olmayan elementlər boş-boşuna yaddaşda yer tutar.

 

9.1 Siyahının elan edilməsi

int tipindən biz adi dəyişən, ünvan dəyişəni və cərgə elan etmək qaydalarını bilirik.

int x, *y, z[10];

Yuxarıdakı misalda biz int tipindən x dəyişəni, y ünvan dəyişəni və 10 elementdən ibarət z cərgəsi elan etdik. İndi isə, hər bir elementində int tipli dəyişən olan siyahı elan edək. Bunun üçün, əvvəlcə siyahını təşkil edən obyektlərin tipini yaratmalıyıq. Yəni, qeyd elədik ki, siyahı da cərgə kimi elementlər (obyektlər) ardıcıllığıdır və bu elementlərin (obyektlərin) hər birində müxtəlif məlumatlar yerləşdirmək olar. İndi biz həmin bir obyekti yaratmağa çalışırıq, daha sonra bir neçə bu cür obyekti bir-biri ilə əlaqələndirib siyahı yaratma qaydasını öyrənəcəyik. Baxdığımız sadə halda yaratmaq istədiyimiz obyekt özündə bir məlumat - int tipindən olan dəyişən saxlayır. Bu obyekti yaratmaq üçün biz struct tipdən istifadə edəcəyik.

Aşağıdakı kimi:

struct syh_el {

int x;

}

Yuxarıda biz özündə int tipindən olan dəyişən, x-i saxlayan yeni struct tipi yaratdıq. İndi bu tipdən olan bir neçə dəyişən elan edək.

syh_el dey1, dey2, dey3, dey4;

 

Hal-hazırda yaddaşda vəziyyət aşağıdakı kimidir:

 

 

Biz isə, siyahı almaq üçün bu obyektləri bir-biri ilə əlaqələndirməliyik, aşağıdakı kimi:

Bir az daha səliqəli göstərsək, aşağıdakı kimi:

 

Siyahı yaratma qaydası:

Əsas məsələ bir obyekti başqa obyekt ilə əlaqələndirməkdir. Əgər yaratmış olduğumuz obyektlərdən birini, digəri ilə əlaqələndirə bilsək, daha sonra yeni obyekti digər başqa biri ilə əlaqələndirə bilərik. Beləliklə də, siyahıya istənilən sayda yeni obyekt əlavə edib siyahımızı istədiyimiz qədər uzada bilərik.

Bəs bir obyekti digəri ilə necə əlaqələndirək?

Bunun üçün proqramlaşdırmada aşağıdakı, ilk baxışda elə də anlaşılmayan qaydadan istifadə edirlər. Siyahıda hər bir obyekt özündən sonra gələn obyektin yaddaşdakı ünvanını bilməlidir. Bunun üçün obyektin daxilində onun öz tipindən olan ünvan dəyişəni yerləşdirirlər və bu ünvan dəyişəninə siyahının növbəti obyektinin ünvanını mənimsədirlər.

Aşağıdakı elana nəzər salaq:


struct syh_əl {
int x;
syh_əl *novb_əl;
}

Bu elanın yuxarıdakı elandan yeganə fərqi o oldu ki, biz burada struct syh_el tipinin daxilində bu tipdən olan *novb_el ünvan dəyişəni yerləşdirdik. Artıq bu bizə siyahı yaratmağa imkan verir. Əvvəlcə biz siyahımızı elan etməliyik.

Aşağıdakı kimi:

syh_el *mənim_syh;

Yaddaşın vəziyyəti:

Siyahı yaratmaq üçün syh_el tipindən olan daha iki ünvan dəyişəninə ehtiyacımız olacaq. Bunları p və q ilə işarə edək. Bunlardan biri - p, yeni obyektlərin yaradılması və inisializasiyası (ilkin qiymətin mənimsədilməsi), digəri - q isə iterasiya üçündür (siyahı boyu hərəkət etmək).

Gəlin, bu dəyişənləri də elan edək:

syh_el *p,*q;

Yeri gəlmişkən, yaddaşa da bir ötəri nəzər salaq:

 

Hər şey hazırdır, siyahının ilk elementini yarada bilərik.

Bunun üçün yazırıq:

p = new syh_el;

Bu zaman yaddaşın vəziyyəti aşağıdakı kimi olar:

Növbəti addım mənim_syh dəyişənini bu yeni yaratdığımız obyektə mənimsətməkdir.

Bunun üçün sadəcə yazırıq:

mənim_syh = p;

Yaddaşın vəziyyəti aşağıdakı kimidir:

Artıq siyahıya element əlavə etmək üçün menim_syh dəyişənindən istifadə etməyəcəyik. O siyahının ilk elementinə istinad edir və siyahıya müraciət etmək üçün bu dəyişəndən istifadə edəcəyik. Hələlik isə, siyahının yaradılmasını davam etdirək.

İkinci elementi yaratmaq üçün hazırlıq işləri görək.

Bunun üçün iterasiya dəyişənini siyahının ilk elementinə (p-yə), ilk elementin ikinci elementlə əlaqələndirmə həddini (novb_el) isə, NULL qiymətinə mənimsətməliyəm.

NULL adətən ünvan dəyişənlərinin yaddaşda heç bir yerə ünvanlanmadığını bildirmək üçün istifadə olunur.

Bu bizə siyahının sonunu müəyyənləşdirmədə lazım olacaq.

q = p;

p->novb_el = NULL;

Yaddaşın vəziyyəti aşağıdakı kimidir:

 

Siyahının ikinci elementini yaradaq, eyni ilə birinci elementi yaratdığımız kimi:

p = new syh_el;

Yaddaşın vəziyyətinə baxaq:

Heey, diqqət! Əsas anlardan biri. İlk element ilə yeni yaratdığımız elementi birləşdiririk.

Bunun üçün sadəcə yazırıq:

q->novb_el = p;

Yaddaşa nəzər salaq:

Artıq əlaqəmiz var.

Növbəti 3-cü elementi yaratmaq üçün hazırlıq işləri görək (bayaq bunu eləmişdik).

q = p;

p->novb_el = NULL;

Yaddaşa baxırıq:

 

Artıq bu şəkildə davam edərək, siyahıya istədiyimiz qədər yeni element əlavə edə bilərik. Tutaq ki, siyahıya müəyyən qədər element əlavə etmişik və siyahımız aşağıdakı şəkildədir:

Ən sonda p və q dəyişənlərinin siyahıya istinadlarını ləğv etməliyik.

p=NULL;

q=NULL;

Bununla da siyahı yaratma prosesini tamamlamış olduq.

 

 

Çətin görünə bilər, amma siyahılar proqramlaşdırmada əvəzedilməzdir və çox praktikdirlər. Aşağıdakı nümunə proqramları yerinə yetirdikdən sonra siyahılarla işləmə bacarığımız bir qədər də artmış olar.

 

Proqram nümunələri:

Gəlin, yuxarıda daxil etdyimiz nümunəyə uyğun proqram hazırlayaq.

Yəni sadə bir proqram tərtib edək, bu proqramda özündə ancaq bir hədd, int x; saxlayan obyektlərdən ibarət siyahı tərtib edək, bu siyahının obyektlərinin həddlərinə (x) qiymətlər mənimsədək, daha sonra siyahının elementlərini çap edək.

Əlbəttə hələlik biz hər şeyi əlimizlə edəcəyik, bir az sonra isə prosesi avtomatlaşdırmaq məqsədilə funksiyalardan istifadə edəcəyik.

 

Proqram 1.


// prg_9_1.cpp

#include <iostream>
#include <string.h>

struct syh_el
{
int x;
syh_el *novb_el;
};

int main(int argc, char *argv[])
{

// istifade edəcəyimiz dəyişənləri elan edirik
syh_el *menim_syh, *p, *q;
int dey;

// ilk elementi yaradaq
p = new syh_el;

// lazımi mənimsətmələri aparaq
mənim_syh = p;
q = p;
p->novb_el = NULL;
// hər şey hazırdır, ikinci elementi yaradırıq
p = new syh_el;

// siyahı ilə ikinci elementin əlaqəsini qururuq
q->novb_el = p;

// lazımi mənimsətmələri edirik
q = p;
p->novb_el = NULL;

// artıq siyahıda iki obyekt var, 3-cünü yaradaq
// 3-cü elementi yaradırıq
p = new syh_el;

// siyahının sonu ilə üçüncü elementin əlaqəsini qururuq
q->novb_el = p;

// lazımi mənimsətmələri edirik
q = p;
p->novb_el = NULL;

// siyahıda hal-hazırda 3 element var, hələlik bəsdir.
// p ve q-nu siyahıdan ayıraq
p=NULL;
q=NULL;

/* vəssalam, indi mənim_syh dəyişəni yeni yaratdıgımız siyahının ilk
elementinə istinad edir ve onun vasitəsile siyahının bütün obyektlərinə müraciət edə bilərəm */

/* Siyahının elementlərinə qiymətlər mənimsədək, daha sonra bu
qiymətləri çap edəcəyik */

// Yenə p-yə ehtiyacımız olacaq
p = mənim_syh;

// indi p siyahının əvvəlində dayanıb, aşagıdakı koda diqqət edin
std::cout<<"Siyahının hədlərinin qiymətlərini daxil edin.\n";
std::cout<<"Siyahının birinci həddinin qiymətini daxil edin. \n";
std::cin>>dey;

/* Siyahının ilk obyektinin x həddinə istifadəçinin daxil etdiyi
qiyməti mənimsədirəm */
p->x = dey;

/* Siyahının ikinci obyekti üzərinə sürüşmək üçün aşagıdakı
qaydadan istifadə olunur */
p = p->novb_el;

/* Artiq p siyahının ikinci obyektinə istinad edir, 
onun x həddinə qiymət mənimsədək */
std::cout<<"Siyahının ikinci həddinin qiymətini daxil edin. \n";
std::cin>>dey;
p->x = dey;
p = p->novb_el;

// Nəhayət 3-cü obyekt
std::cout<<"Siyahının üçüncü həddinin qiymətini daxil edin. \n";
std::cin>>dey;
p->x = dey;

/* p öz işini bitirdi, siyahını ondan azad edirəm.
Çalışın, siyahınızda lazım olmayan, əlavə istinadlar saxlamayasınız */
p = NULL;

// Siyahının elementlərinə qiymətlər mənimsətdik, indi onlari çap edək
// p-ni siyahının ilk elementinə mənimsədək, bunu etməyi bilirik
p = mənim_syh;

// mənim_syh-nın funksiyası ancaq siyahının başlanğıc ünvanını
// özündə saxlamaqdır
std::cout<<"Siyahının elementləri aşağıdakılardır: \n\n";
dey = p->x;
std::cout<<"Birinci element "<<dey<<"\n";

// ikinci elementin üzərinə sürüşək
p = p->novb_el;
dey = p->x;
std::cout<<"İkinci element "<<dey<<"\n";

// Üçüncü elementin üzərinə sürüşək
p = p->novb_el;
dey = p->x;
std::cout<<"Üçüncü element "<<dey<<"\n";

std::cout<<"\nSiyahının elementləri çap olundu \n";

return 0;
}

Nümunə

Proqramı yerinə yetirək:


C:\cpp\prog2\Debug>
C:\cpp\prog2\Debug>prog2.exe
Siyahının hədlərinin qiymətlərini daxil edin.
Siyahının birinci həddinin qiymətini daxil edin.
65 
Siyahının ikinci həddinin qiymətini daxil edin.
345 
Siyahının üçüncü həddinin qiymətini daxil edin.
78 
Siyahının elementləri aşağıdakılardır: 

Birinci element 65
İkinci element 345
Üçüncü element 78

Siyahının elementləri çap olundu
C:\cpp\prog2\Debug>
C:\cpp\prog2\Debug>

Bu nümunədə biz 3 elementdən ibarət sadə siyahı yaratdıq, siyahının hədlərinə qiymətlər mənimsətdik və bu qiymətləri çap etdik. Praktikada bu cür məsələlərin həllində funksiyadan istifadə etmək zəruridir. Gəlin, yuxarıdakı proqramın funksiyaların tətbiqi ilə olan variantını nəzərdən keçirək. Funksiyalardan istifadə etməklə yuxarıda baxdığımız proqram aşağıdakı kimi olar: Bizə mahiyyət etibarilə 2 funksiya lazımdır: biri siyahını yaratmaq və ona elementləri yerləşdirmək, digəri isə, siyahının elementlərini çap etmək. Bu funksiyaları uyğun olaraq siyahi_yarat və siyahını_çap_et kimi adlandıraq.

Birinci funksiya 2 parametr qəbul edir: syh_el * tipindən olan dəyişən - yaratmaq istədiyimiz siyahı və int tipli dəyişən - siyahıya daxil etmək istədiyimiz elementlərin sayı. İkinci funksiya isə bir parametr qəbul edir: çap etməli olduğumuz siyahıya istinad, struct syh_el * tipli.

Funksiyaların elanları aşağıdakı kimi olar:

syh_el * siyahı_yarat(syh_el *syh, int elem_say); void siyahını_çap_et( syh_el *);

Proqramı daxil edək:

Proqram 2.


// prg_9_2.cpp

#include <iostream>
#include <string.h>

struct syh_el
{
int x;
syh_el *novb_el;
};

syh_el *siyahı_yarat(struct syh_el *syh, int elem_say);
void siyahını_çap_et(struct syh_el *);


int main(int argc, char *argv[])
{

// istifadə edəcəyimiz dəyişənləri elan edirik
struct syh_el *mənim_syh;

// siyahının boş olduğunu bildirmək üçün
mənim_syh = NULL;
int say;

std::cout<<"Siyahının elementlərinin sayını daxil edin \n";
std::cin>>say;

mənim_syh = siyahı_yarat(mənim_syh,say);

siyahını_çap_et(menim_syh);

return 0;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

syh_el *siyahı_yarat( syh_el *syh, int elem_say)
{
syh_el *p, *q;
p=syh;
q=syh;
int i,dey;

for (i=1; i<=elem_say; ++i)

{

std::cout<<"siyahının "<<i
<<"-ci elementini daxil edin \n";
std::cin>>dey;

p = new syh_el;
p->x = dey;
p->novb_el = NULL;

if (syh==NULL)
{
// siyahı boşdur, ilk element
syh=p;
q = p;
p = NULL; 
}
else 
{
// siyahıda element var
q->novb_el = p;
q = p; 
}

}

return syh;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void siyahını_çap_et( syh_el *syh)
{
syh_el *p;
int dey;
p = syh;

if (syh == NULL ) 
{
std::cout<<"Siyahı boşdur \n";
return;
}
std::cout<<"Siyahının elementləri \n";
while(p!=NULL)
{
dey = p->x;
std::cout<<dey<<" ";
p = p->novb_el; // növbəti elementə keç
}

std::cout<<"\n";
}

Nümunə

Proqramı yerinə yetirək:


C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>prog2.exe 
Siyahının elementlərinin sayını daxil edin 
5 
siyahının 1-ci elementini daxil edin 
23 
siyahının 2-ci elementini daxil edin 
45 
siyahının 3-ci elementini daxil edin 
567 
siyahının 4-ci elementini daxil edin 
1 
siyahının 5-ci elementini daxil edin 
789 
Siyahının elementleri 23 45 567 1 789 
C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>

9.2 Siyahılardan elementlərin silinməsi.

Biz qeyd etdik ki, siyahılara proqramın icrası boyu istədiymiz zaman istədiyimiz qədər yeni obyekt əlavə edə və siyahıda olan obyektləri silə bilərik. Gəlin, indi də siyahıdan elementlərin silinməsi qaydasını göstərək.

Tutaq ki, bizim 5 obyekti olan aşağıdakı kimi siyahımız var:

Əlbəttə siyahının aşağısında göstərdiyimiz nömrələrin siyahı ilə heç bir əlaqəsi yoxdur, sadəcə konkret obyektlərə müraciəti asanlaşdırmaq üçün göstərmişik. Biz bu siyahıdan üçüncü obyekti silmək istəyirik. Əvvəlcə qrafik şəkildə görəcəyimiz işi təsvir edək, daha sonra müvafiq proqram kodunu daxil edərik. Bunun üçün ilk olaraq, 2-ci obyektin 3-cü obyektə olan istinadını 4-cü obyektə mənimsədirik:

 

Daha sonra 3-cü obyektin 4-cü obyektə olan istinadını ləğv edirik.

Hal-hazırda biz qarşımıza qoyduğumuz məqsədə nail olmuşuq, artıq siyahıdan 3-cü obyekt kənar edilib və 2-ci obyekt birbaşa 4-cü obyektə birləşir.

Amma 3-cü obyekt hələ də yaddaşdadır və əgər o bizə lazım deyilsə, biz onu yaddaşdan silməliyik.

Görəcəyimiz iş ilə tanış olduq, indi isə gəlin, bu işi yerinə yetirən müvafiq proqram kodunu daxil edək. Sadəlik üçün siyahı tipi olaraq yuxarıda elan etdiyimiz syh_el tipindən istifadə edək. Tutaq ki, syh_el * tipindən olan syh dəyişəni elan olunub (siyahının başlanğıcı) və siyahıya 5 element əlavə olunub.

syh_el * tipindən olan p və q dəyişənlərini elan edək.

struct syh_el *p, *q;

p-ni siyahının başlanğıcına mənimsədək.

p = syh;

p-ni siyahının ikinci obyekti üzərinə sürüşdürək.

p = p->novb_el;

q-nü də ikinci obyektə mənimsətməliyik.

Bu bizə ikinci obyektin novb_el həddinə müraciət etməyə imkan verəcək. Hal-hazırda p ikinci obyektə istinad etdiyindən, daha siyahını əvvəldən başlamağa ehtiyac yoxdur.

Sadəcə yazırıq:

q = p;

p-ni siyahının 3-cü obyektinin üzərinə sürüşdürək.

p = p->novb_el;

Siyahının ikinci obyektinin novb_el həddini 4-cü obyektə mənimsədək:

q->novb_el = p->novb_el;

3-cü obyektin siyahı ilə əlaqəsini ləğv edirik :

p->novb_el = NULL;

Əgər 3-cü obyekt artıq bizə lazım deyilsə, onu yaddaşdan silirik:

delete p;

İndi isə, gəlin, bütün bu dediklərimizi icra edən konkret proqram nümunəsi daxil edək.

Proqram 3.


// prg_9_3.cpp

#include <iostream>
#include <string.h>

struct syh_el{
int x;
struct syh_el *novb_el;
};

syh_el *siyahı_yarat(struct syh_el *syh, int elem_say);
syh_el *siyahı_sil(struct syh_el *syh, int elem);
void siyahını_çap_et(struct syh_el *);

int main(int argc, char *argv[])
{

// istifadə edəcəyimiz dəyişənləri elan edirik
syh_el *mənim_syh;

// siyahının boş olduğunu bildirmək üçün
mənim_syh = NULL;
int say,elem;

std::cout<<"Siyahının elementlərinin sayını daxil edin \n";
std::cin>>say;

mənim_syh = siyahı_yarat(mənim_syh,say);
siyahını_çap_et(mənim_syh);

std::cout<<"Siyahıdan silmek istədiyiniz elementin indeksini daxil edin\n";
std::cin>>elem;

mənim_syh = siyahı_sil(mənim_syh, elem);
siyahını_çap_et(mənim_syh);

return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

syh_el *siyahı_yarat( syh_el *syh, int elem_say)
{
syh_el *p, *q;
p=syh;
q=syh;
int i,dey;

for (i=1; i<=elem_say; ++i)
{
std::cout<<"siyahinin "<<i<<"-ci elementini daxil edin \n";
std::cin>>dey;
p = new syh_el;
p->x = dey;
p->novb_el = NULL;

if (syh==NULL){
// siyahı boşdur, ilk element
syh=p;
q = p;
p = NULL; }
else {
// siyahıda element var
q->novb_el = p;
q = p;
}
}

return syh;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void siyahını_çap_et( syh_el *syh)
{
syh_el *p;
int dey;
p = syh;

if (syh == NULL ) {
std::cout<<"Siyahı boşdur \n";
return;
}

std::cout<<"Siyahının elementləri \n";

while(p!=NULL){
dey = p->x;
std::cout<<dey<<" ";
p = p->novb_el; // novbeti elemente kec
}

std::cout<<"\n";
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

syh_el *siyahı_sil(syh_el *syh, int elem)
{
syh_el *p, *q;
p=syh;
int i,dey;

if (syh==NULL)
return NULL; // siyahı boşdur

if (elem==1){
// silmək istədiyimiz element ilk elementdir
syh = p->novb_el;
p->novb_el = NULL;
delete p;
return syh;
}

for (i=1; i<elem-1; ++i)
if (p==NULL) break;
else
p = p->novb_el;

if (p==NULL){
std::cout<<"Siyahıda "<<elem<<" sayda element mövcud deyil\n";
return syh; 
}

q=p;
p = p->novb_el;

if (p->novb_el==NULL)
{
// silmək istədiyimiz element sonuncu elementdir
q->novb_el=NULL;
delete p;
p=NULL;
q=NULL;

return syh;
}

// silmək istədiyimiz element aralıq elementdir
q->novb_el = p->novb_el;
p->novb_el = NULL;
delete p;
q=NULL;

return syh;
}

Nümunə

C:\cpp\prog2\Debug>prog2.exe 
Siyahının elementlərinin sayını daxil edin 
7 
siyahının 1-ci elementini daxil edin 
23 
siyahının 2-ci elementini daxil edin 
45 
siyahının 3-ci elementini daxil edin 
123 
siyahının 4-ci elementini daxil edin 
567 
siyahının 5-ci elementini daxil edin 
78 
siyahının 6-ci elementini daxil edin 
345 
siyahının 7-ci elementini daxil edin 
99 
Siyahının elementləri 
23 45 123 567 78 345 99 
Siyahıdan silmək istədiyiniz elementin indeksini daxil edin 
3 
Siyahının elementləri 
23 45 567 78 345 99 
C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>