327
Z.T. Məhərrəmov H.P. Vəliyev VERİLƏNLƏRİN STRUKTURU ALQORİTMLƏR ALİ MƏKTƏB TƏLƏBƏLƏRİ ÜÇÜN DƏRS VƏSAİTİ BAKI - 2020

Z.T. Məhərrəmov H.P. Vəliyev VERİLƏNLƏRİN STRUKTURU …

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Z.T. MəhərrəmovH.P. Vəliyev

VERİLƏNLƏRİN STRUKTURUVƏ

ALQORİTMLƏR

ALİ MƏKTƏB TƏLƏBƏLƏRİ ÜÇÜNDƏRS VƏSAİTİ

BAKI - 2020

Elmi redaktor:Sumqayıt Dövlət Universitetinin “Texniki kibernetika” kafedrasının professoru, t.e.d., professor Ə.H.Nağıyev

Rəy verənlər:Bakı Dövlət Universitetinin “Tətbiqi riyaziyyat” ETİ direktoru, AMEA-nın həqiqi üzvü, f.-r. e.d., professor F.Ə.Əliyev

Bakı Dövlət Universitetinin “Riyazi kibernetika” kafedrasının professoru, f.-r. e.d., professor K.Ş.Məmmədov

Məhərrəmov Z.T., Vəliyev H.P.Verilənlərin strukturu və alqoritmlər. Ali məktəb tələbələri üçün dərs vəsaiti.

ADPU-nəşriyyatı. Bakı, 2020. - 326 s.Kitab istənilən proqramlaşdırma dilinin əsasını təşkil edən verilənlərin

strukturunu və alqoritmləri öyrənməyə həsr edilmişdir. Verilənlərin baza tipləri, göstəricilər, massivlər, yazılar, sətirlər, fayllar və bir istiqamətli si­yahılar, iki istiqamətli siyahılar və halqavari siyahılar, steklər, növbələr və deklər, binar ağaclar, xeş-cədvəllər kimi strukturlar ilk dəfə olaraq bir kitab­da tam əhatə edilmişdir və C# dilində proqramlaşdınlaraq kompüterdə icra edilmişdir. Sadalanan bütün strukturlar müqayisə edilmiş, onların üstün və çatışmaz cəhətləri göstərilmiş və alqoritmik mürəkkəblikləri təhlil edilmiş­dir.

Dərs vəsaitində, habelə, çoxhədlinin hesablanması üçün Hörner sxe­minin alqoritmi, verilənlərin axtarışı üçün ardıcıl və binar axtarış alqoritm­ləri, verilənlərin nizamlanması üçün ardıcıl, yerləşdirməklə, “qabarcıq”, Şell və sürətli nizamlama alqoritmləri, cəbri və transendent tənliklərin həlli üçün yanya bölmə, iterasiya və Nyuton metodlarının alqoritmləri, xətti tənliklər sisteminin həlli üçün Qauss və Xoleski (kvadratlar) metodlarının alqo­ritmləri, rekursiv alqoritmlər kompüterdə icra edilmiş və onlarm ən yaxşı, orta və ən pis hallarda mürəkkəbliyi araşdırılmışdır.

Kitab ali məktəb tələbələri tərəfindən bilavasitə “Verilənlərin strukturu və alqoritmlər” fənninin öyrənilməsi üçün dərs vəsaiti kimi nəzərdə tutulmuşdur. Lakin dərs vəsaitindən istənilən proqramlaşdırma dilini, o cümlədən, Pascal, C++, C#, Python və s. dilləri öyrənmək istəyən şəxslər və proqramlaşdırma dillərini, verilənlər bazalarını, alqoritmlər nəzəriyyəsini və s. tədris edən müəllimlər və öz tədqiqatlarında əlavələr layihələndirmək istəyən magistrlər, doktorantlar istifadə edə bilərlər.

19478120020©------------------------------ - Qnfli nəsr

1957(F)125020

MÜNDƏRİCAT

GİRİŞ........................................................................................ 7

BİRİNCİ FƏSİL. ALQORİTMLƏRİN ANALİZİNİNRİYAZİ ƏSASLARI...................................................... 13

I. I. Alqoritm anlayışı.................................................... 131.2. Alqoritmin formal xassələri və təsvir üsulları...... 171.3. Alqoritmlərin təhlili..................................................20

1.3.1. Təhlil nədir?...................................................... 201.3.2. Yaddaşa görə təhlil............................................221.3.3. Alqoritmin mürəkkəbliyi.................................. 231.3.4. Alqoritmlərdə müxtəlif halların təhlili.......... 32

İKİNCİ FƏSİL. VERİLƏNLƏRİN STATİK VƏ DİNAMİK STRUKTURLARI..........................33

2.1. Verilənlərin strukturlarının təsnifatı........................332.2. Verilənlərin strukturları üzərində yerinə yetirilən

əməliyyatlar......................................................... 382.3. Verilənlərin baza tipləri............................................392.4. Göstəricilər.................................................................40

2.4.1. Dəyişənlərə göstəricilər.................................... 412.4.2. Göstəricilərə göstəricilər.................................. 452.4.3. Massivlərə göstəricilər..................................... 46

4 Mündaricat2.5. Massivlər............................................................................. 482.6. Dinamik massivlər............................................................. 552.7. Sətirlər................................................................................ 582.8. Yazılar................................................................................ 642.9. Çoxluqlar............................................................................ 672.10. Siyahılar........................................................................... 71

2.10.1. Bir əlaqəli siyahılar və onların kompüterdə reallaşdırılması........................................... 76

2.10.2. İki əlaqəli siyahılar və onların kompüterdə reallaşdırılması........................................... 81

2.10.3. Halqavari siyahılar və onların kompüterdə reallaşdırılması........................................... 92

2.11. Stek və onun kompüterdə reallaşdırılması...................... 1002.12. Növbə və onun kompüterdə reallaşdırılması.................. 1092.13. Dek.................................................................................... 1132.14. Fayllar............................................................................... I 15

2.14.1. Mətn faylları............................................................ 1182.14.2. İkilik fayllar............................................................. 125

ÜÇÜNCÜ FƏSİL. VERİLƏNLƏRİN İYERARXİKQEYRİ-XƏTTİ DİNAMİK STRUKTURLARI............134

3.1. Qraf və ağacların təsviri.................................................... 1 343.2. Binar ağaclar...................................................................... 1383.3. Ağacların yaddaşda təsviri............................................... 141

3.3.1. Massiv və siyahılar əsasında ağacların təsviri........ 1413.3.1.1. Massivlər əsasında təsvir................................ 1423.3.1.2. Siyahılar əsasında təsvir................................. 144

3.4. Binar ağaclarda dövrə vurma........................................... 1453.4.1. Dövrə vurma əməliyyatlarının kompüterdə

reallaşdırılması................................................. 1473.5. Ağaclar üzərində əməliyyatlar və onların kompüterdə

reallaşdırılması............................................................. 1593.5.1. Düyünlərin yaradılması və əlavə edilməsi............... 1603.5.2. Düyünlərin sayının hesablanması............................ 1653.5.3. Əməliyyatların nəticələrinin müşahidə edilməsi.... 165

Münıbricat_________________________________________J3.5.4. Düyünün axtarılması...........................................1673.5.5. Minimal və ya maksimal düyünün axtarılması... 1693.5.6. Düyünün silinməsi..............................................1703.5.7• Binar axtarış ağacı üzərində əməliyyatların

kompüterdə reallaşdırılması........................180

DÖRDÜNCÜ FƏSİL. VERİLƏNLƏRİN ƏLDƏ EDİLMƏSİNİN SÜRƏTLƏNDİRİLMƏSİ METODLARI............................................................ 190

4.1. Xeş-cədvəl....................................................................1904.2. Verilənlərin xeşləşdirilməsi........................................ 1934.3. Kolliziyanın həlli metodları........................................ 1994.4. Xeş-funksiyanın keyfiyyətinin qiymətləndirilməsi. ...2024.5. Xeş-cədvəlin kompüterdə reallaşdırılması................ 209

4.5.1. Hashtable sinfi............................................... 2094.5.2. Xeş-cədvəlin yaradılması, elementlərin əlavə

edilməsi və onlar üzərində əməliyyatlar.210

BEŞİNCİ FƏSİL. AXTARIŞ ALQORİTMLƏRİ.........216

5.1. Ardıcıl axtarış metodu................................................ 2165.2. Binar (ikili) axtarış metodu.........................................222

ALTINCI FƏSİL. NİZAMLAMA ALQORİTMLƏRİ...................................................230

6.1. Nizamlama alqoritmləri haqqında ümumi məlumatlar.............................................................................2306.2. Xətti nizamlama alqoritmi.......................................... 2326.3. Yerləşdirməklə nizamlama alqoritmi......................... 2366.4. Qabarcıq alqoritmi.......................................................2426.5. Şell alqoritmi................................................................ 2476.6. Sürətli nizamlama alqoritmi........................................2536.7. Nizamlama alqoritmlərinin müqayisəsi.....................259

___________________________________________ MündaricatYEDDİNCİ FƏSİL. ƏDƏDİ ÜSUL

ALQORİTMLƏRİ.................................................. 262

7.1. Çoxhədlilərin qiymətinin hesablanması........................2637.1.1. Hörner sxemi...........................................................263

7.2. Matrislərin vurulması..................................................... 2717.3. Cəbri və transendent tənliklərin həll üsulları............... 274

7.3.1. Yarıya bölmə üsulu................................................. 2747.3.2. İterasiya üsulu..........................................................2777.3.3. Nyuton üsulu............................................................281

7.4. Xətti cəbri tənliklər sisteminin həll üsulları................. 2867.4.1. Qauss üsulu.............................................................. 2887.4.2. Xoleski üsulu...........................................................2957.4.3. İterasiya üsulu..........................................................3027.4.4. Zeydel üsulu............................................................307

7.4.4.1. İterasiya prosesinin yığılması......................3097.4.4.2. Zeydel üsulunun alqoritmi......................... 311

SƏKKİZİNCİ FƏSİL. REKURSİV ALQORİTMLƏR.................................................... 315

8.1. Faktorialın rekursiv hesablanması................................ 3168.2. Ən böyük ortaq bölənin rekursiv hesablanması......... 3188.3. Fibonaççi ədədlərinin rekursiv hesablanması..............3208.4. Rekursiyanın çatışmazlıqları........................................ 322

ƏDƏBİYYAT.......................................................................... 324

CTpyKTypbi paHHbix

GİRİŞ

Kompüterlərin proqram təminatı dedikdə onların fəaliyyəti və həm də müəyyən tətbiqi sahələrin faydalı funksional məsələlərinin həlli üçün nəzərdə tutulmuş proqramların məcmusu başa düşülür. “Proqram” terminini istifadə etdikdə yalnız proqramlaşdırma dilinin operator­larının ardıcıllığı deyil, həm də üzərində bu və ya digər əməliyyatların yerinə yetirilə biləcəyi müxtəlif informasiya obyektləri yığımı nəzərdə tutulur. Proqramın belə informasiya obyektlərini verilənlər adlandırırlar.

Verilənlər - müəyyən proses və ya alqoritmlərin köməyi ilə emal və interpretasiya üçün yararlı olan, həm insanlar, həm də texniki vasitələrlə ünsiyyətdə ola bilən və ya ötürülə bilən faktların, anlayışların, təlimatların, ideyaların və ya hər hansı informasiyanın formallaşmış şəkildə təsviridir.

8 Məhərrəmov Z. T., Vəliyev H.P.

Verilənlər istənilən proqramın çox vacib atributlarıdır. Verilənlər ayrı-ayrı bitlər, müstəqil bitlər ardıcıllıqları, müxtəlif formalarda təsvir edilmiş ədədlər (qeyd olunmuş və ya sürüşkən nöqtəli, adi və ya ikiqat dəqiqlikli və s.), müxtəlif kodlaşdırma sistemlərində simvolları təsvir edən baytlar və müstəqil baytlar qrupları, ədədlər massivləri, kompüterin yaddaşında yerləşən əlaqəli siyahılar formasında saxlanan informasiya, həmçinin kompüterin xarici yaddaş qurğularında ayrı-ayrı fayllar və qarşılıqlı əlaqəli fayllar sistemləri şəklində təşkil edilmiş informasiya ola bilər. Sadaladığımız misallar verilənlərin müxtəlif mürəkkəblik və ya təşkil edilmə səviyyəsini nümayiş etdirir. Bu təşkil edilmə səviyyəsinin xarakteri məhz ''verilənlərin strukturu’' anlayışının təcəssüm­lərindən biridir.

‘"Verilənlərin strukturu” anlayışı ən azı iki müxtəlif mənada istifadə edilə bilər. Birincisi, verilənlərin strukturu - verilənlərin təşkil edilməsinin məntiqi və ya riyazi modelidir. Faktiki olaraq, verilənlərin strukturuna məhz bu verilənlərin kompüterin yaddaşında təsviri kimi baxıla bilər (fiziki struktur), həm də o hər hansı proqramda istifadə edilən istənilən informasiya obyektinin ümumi xassəsi olur.

İkincisi, verilənlərin strukturu - proqramda və kompüterin yaddaşında verilənlərin, obyektin məntiqi anlayışının məxsusi reallaşdırılmasıdır. Bu, ayrıca bir dəyişən, massiv və ya daha mürəkkəb proqram obyekti, məsələn, siyahı, ağac və s. ola bilər. Yadda saxlamaq lazımdır ki, verilənlərin istənilən strukturu kompüterin yaddaşında (ilk növbədə operativ yaddaşda) yerləşir, müəyyən qədər, hətta mümkündür ki, olduqca böyük miqdarda yaddaş xanaları tutur və yerləşdikləri yerin başlanğıc ünvanı ilə xarakterizə olunur. Bu vəziyyəti təsvir etmək üçün "yaddaşdayer" anlayışı istifadə olunur.

Adətən, verilənlərin strukturlarına verilənləri emal edən alqoritmlərin qarşılıqlı əlaqəsi şəklində baxılır.

Giriş 9

Alqoritmlər və verilənlərin strukturu - istənilən proqramın, proqram sistemlərinin və ya komplekslərinin zəruri komponentləridir. Belə proqram, proqram sistemləri və ya kompleksləri kimi adi sadə proqramlar, paylanmış sistemlər, mobil əlavələr, verilənlər bazaları, web-əlavələr və s. ola bilər. Buna görə verilənlərin strukturu və alqoritmlər nəzəriyyəsini, xüsusi halda, məntiqi və maşın səviyyələrində verilənlərin təsvir edilməsi metodlarını və, həmçinin, müxtəlif strukturlar üzərində mümkün əməliyyatların yerinə yetirilməsini bilmək avtomatlaşdırılmış idarəetmə sistem­lərinin, proqramlaşdırma dillərinin kompilyatorlarının, əməliyyat sistemlərinin, habelə imitasiya modelləşdirməsi üçün proqram sistemlərinin, verilənlər bazalarını idarəetmə sistemlərinin, süni intellekt və s. kimi bölmələrin dərindən öyrənilməsi, aydınlaşdırılması və layihələndirilməsi üçün lazımdır. Bütün bunlar kompüter elmləri və proqram mühəndisliyi sahələrində sonrakı biliklər üçün əsas bünövrə kimi xidmət edir.

“Alqoritmlər” və “verilənlərin strukturu” kompüter elmlərinin əsas anlayışlarından biridir. N.Virt iddia edir kı, proqramçı üçün müvəffəqiyyətin klassik düsturu belədir:

"Yaxşı proqram — ağıllı düşünülmüş alqoritmin və verilənlərin effektiv strukturlarının vəhdətindən ibarətdir".

Əgər nəzərə alsaq ki, proqramın yazılması və reallaşdırılması üçün alqoritmik dil də lazımdır, onda aşağı­dakı düstur alınar:

Proqram = Alqoritm Verilənlərin strukturu + Alqoritmik dil.

Alqoritmlərin və verilənlərin strukturunun tədqiqi proqramlaşdırmamn əsaslarından, həmçinin mükəmməl texnologiyaların və mürəkkəb riyazi araşdırmaların zəngin sahələrindən biridir. Həm də bu, nəzəri hazırlıqlı mütəxəs­sislər üçün nə isə sadəcə bir əyləncə sahəsi deyil: yaxşı alqoritm və ya verilənlərin strukturu problemi bir neçə saniyə

10 Məhərrəmov Z. T., Vəliyev H.P.

ərzində həll etməyə imkan verə bilər, onların yoxluğu isə həmin problemin həlli üçün illərlə vaxt tələb edə bilər.

Məsələnin həllinin mümkünlüyü tamamilə xüsusi alqoritmlərin mövcudluğundan və verilənlərin strukturundan asılıdır. Əgər Siz, Sizin üçün yeni olan proqramlaşdırma sahələrində proqramlar hazırlayırsınızsa, onda aydınlaşdırma­lısınız ki, bu sahədə hansı hazır işlənmələr artıq mövcuddur, əks halda Siz kiminsə tərəfindən yaxşı yerinə yetirilmiş bir işi pis yerinə yetirmək üçün boş vaxt sərf edəcəksiniz. Hər proqram alqoritmlərdən və verilənlərin strukturundan asılıdır, amma nadir hallarda yeni alqoritmlər icad etmək lazım gəlir. Hətta mürəkkəb proqramlarda, məsələn, kompilyatorlarda və ya Web-brauzerlərdə verilənlərin strukturu, ümumiyyətlə, massiv, siyahı, ağac və xeş-cədvəllərdən ibarət olur. Proqrama daha təkmilləşmiş struktur lazım gəldikdə isə o, çox ehtimal ki, həmin bu sadə strukturlara əsaslanacaq. Müvafiq olaraq, proqramçınm işi, hansı alqoritmlərin və strukturların əlçatan olduğunu bilmək, həmçinin, onların arasında ən səmərəlisini necə seçməyi anlamaqdır.

Əgər insan özü üçün proqramçı və ya veb-istehsalçı yolunu seçməyə qərar vermişdirsə, onda o bir və ya bir neçə proqramlaşdırma dili ilə rastlaşmalı olacaq. Yaxşı ilkin kod yazmaq üçün alqoritmləri və verilənlərin strukturlarını mütləq öyrənmək lazımdır. Hazırda ən məşhur proqramlaş­dırma dilləri bunlardır:

• PHP;• C#;• JavaScript;• Python;• Java;• C++.Dillərdən hər biri sintaksis adlanan əmrlər (operatorlar)

və qaydalar yığımına malikdir. Bu sintaksisdə iki əhəmiyyətli komponentə fikir yönəltmək lazımdır: kodda bu və ya digər

Giriş 11

operatorların düzgün istifadə edilməsi və verilənlərin təsvir edilməsini düzgün seçmək.

Verilənlərin strukturunun seçilməsi proqramların hazırlanmasının əhəmiyyətli mərhələlərindən biridir və proqramın effektivliyi, onun yazılmasına tələb olunan zəhmət və proqram tərəfindən həll edilən məsələlərin yerinə yetirilmə vaxtı bu seçimin düzgünlüyündən asılıdır. Bu həm də verilənləri emal edən alqoritmlər və onların strukturları üçün doğrudur. Müasir proqramlaşdırma dillərinin tərkibində mövcud olan kitabxanaların və verilənlərin strukturları siniflərinin, məsələn, müxtəlif növ siyahıların, müxtəlif növ ağacların, steklərin, deleqatların və s. meydana çıxması yüksək ixtisaslı mütəxəssislər tərəfindən verilənlərin bu strukturlarından istifadənin incəliklərini və onların emalı alqoritmlərini bilmək zərurətini aradan qaldırmır.

İstənilən proqram konkret qiymətlərlə və ya verilənlərlə işləyir. Onların üzərində müxtəlif hesablama əməliyyatları aparmaq olar, onları dəyişdirmək və ya silmək olar. Bir proqram çərçivəsində onlar iki cür təsvir oluna bilər: dəyişənlər və sabitlər.

Dəyişərilər - proqram kodunun icrası prosesində aldıqları qiymətlərini dəyişən kəmiyyətlərdir və onlar müxtəlif proqramlaşdırma dillərində müxtəlif qaydalarda elan edilir. Məsələn, Pascal. C++ və C# dillərində qabaqcadan dəyişənləri elan etmək lazım gəldiyi halda, Python dili onlarla lazım olan yerdə işləməyə imkan verir. Hər dilin verilənlərinin öz strukturları mövcuddur. Dəyişənlərin, demək olar ki, bütün dillərdə mövcud olan bir neçə baza tipləri var: tam ədəd, həqiqi (qeyd olunmuş və sürüşkən nöqtəli), sətir, simvol, məntiqi və sair.

Sabitlər isə proqramın icrası prosesində dəyişikliklərə məruz qalmayan kəmiyyətlərdir, məsələn, “pi" ədədi.

Seçilmiş tipə uyğun dəyişən operativ yaddaşda müəyyən xanada yerləşir. Verilənləri strukturlaşdırdıqda dəyişənləri tiplərə görə rasional bölmək lazımdır.

12 Məhərrəmov Z. T., Vəliyev H.P.

Dəyişənlərin bu sadaladığımız tipləri konkret dillərdə geniş əhatə olunduğu üçün biz bu fənn çərçivəsində onları təkrarən öyrənməyəcəyik.

"Verilənlərin strukturu və alqoritmlər" kursunun öyrənilməsi hər hansı konkret proqramlaşdırma dilinin tətbi­qinə əsaslanmır, amma biz, bu dərs vəsaitində əhatə etdiyimiz alqoritmləri və verilənlərin strukturunu C# dilinin əsasında izah edəcəyik. Alqoritmlərin mürəkkəbliyinin təhlilində isə, bəzi hallarda, psevdokodlardan istifadə ediləcəkdir.

*Bonpoc N-1

*Hto ma/ıropuTM?

FƏSİL

ALQORİTMLƏRİNANALİZİNİNRİYAZİ ƏSASLARI

1.1. Alqoritm anlayışı

Hələ eramızdan 300 il əvvəl Evklid bucaqların yarıya bölünməsi, üçbucaqların bərabərliyi və digər həndəsi məsələlərin həlli üçün alqoritmlər yazmışdı. O, “Paralel xətlər heç vaxt kəsişmir” kimi aksiomlar lüğətindən başlayaraq, sonralar daha mürəkkəb alqoritmlər yaratmışdır. Evklidin bizə gəlib çatan ilk alqoritmi iki ədədin ən böyük ortaq böləninin tapılması alqoritmidir. Həmin alqoritm aşağıdakı bəndlərdən ibarətdir:

1. x və y ədədlərini müqayisə et. Əgər x>y olarsa, onda dördüncü bəndi yerinə yetir, əks halda ikinci bəndi yerinə yetir.

2. y və x ədədlərini müqayisə et. Əgər y>x olarsa, onda beşinci bəndi yerinə yetir, əks halda üçüncü bəndi yerinə yetir.

14 Məhərrəmov Z. T., Vəliyev H.P.

3. Ən böyük ortaq böləni nəticə kimi qəbul et (z=x) və hesablamam dayandır.

4. x=x-y qəbul et və birinci bəndi yerinə yetir.5. y=y-x qəbul et və birinci bəndi yerinə yetir.

“Alqoritm” anlayışı VHI-IX əsrlərdə (780-847-ci illər) yaşamış və yaratmış məşhur özbək riyaziyyatçısı Məhəmməd ibn Musa-Xarəzminin (Xarəzmli Musa, Xarəzm - hazırda Özbəkistanda vilayət adıdır) adı ilə bağlıdır. Əl-Xarəzminin riyaziyyata aid ərəb dilində yazdığı iki əsəri latın dilinə tərcümə edilərək yalnız XII əsrdə Avropaya aparılmışdı. Əl- Xarəzminin "Hind hesabı haqqında kitab” əsərinin orijinalı indiyədək tapılmamışdır, lakin 1857-ci ildə bu əsərin XII əsrdə tərcümə edilmiş “Əl-Xarəzmi hind hesabı haqqında” adı altında latın variantı aşkar edilərək nəşr edilmişdir. Bu tərcümə “Dixit Algorizmi", yəni, “Alqorizm (Əl-Xarəzmi) söylədi"' sözləri ilə başlayır. Elə buradan da, yəni, Əl- Xarəzminin adının latınlaşdırılmış adından hazırda riyaziyyatda çox geniş yayılmış “alqoritm” sözü əmələ gəlmişdir.

Alqoritm müəyyən məsələnin həlli üçün əmrlər, təlimatlar yığımıdır. Bu və ya digər məsələnin, hadisənin izahı əslində elə alqoritmdir. Kompüter üçün alqoritm yazdıqda isə o bütün incəliklərinə qədər dəqiq tərtib edilməlidir. Kompüterin lüğəti (proqramlaşdırma dilləri) isə çox məhduddur və bütün əmrlər maşının başa düşə biləcəyi dildə yazılmalıdır.

Alimlərin bütün cəhdlərinə baxmayaraq, indiyə kimi alqoritmin dəqiq tərifini vermək mümkün olmamışdır. Cürbəcür təriflər içərisində nisbətən dolğun olan tərif böyük rus alimləri Kolmoqorov və Markova məxsusdur. Həmin təriflər belədir (tərcümənin fikri tam dəqiq ifadə etməsinə əmin olmadığımız üçün onları əslində olduğu kimi də əlavə edirik):

Birincifəsil. Alqoritmlərin analizinin riyazi əsasları 15

Alqoritmin Kolmoqorov tərifi: Alqoritm — müəyyən ciddi qaydalar əsasında yerinə yetirilən hesablamalar sistemidir ki, o bir neçə addımdan sonra hökmən qoyulmuş məsələnin həllinə gətirir.

«AmopumM - sto BCSKan cuctəmb BbmncneHnü, BbinonHAeMbix no CTporo onpefleneHHbiM npaBMnaM, KOTopaa nocne KaKoro-nnöo uucna LuaroB 3ƏBeflOMO npuBOflUT k peıueHnıo nocTaBneHHOü3aaaMM».

Alqoritmin Markov tərifi: Alqoritm - dəyişən ilkin verilənlərdən axtarılan nəticəyə gətirən hesablama prosesini müəyyən edən dəqiq təlimatdır.

«AnropuTM - əto tomhoə npeflnucaHue, onpefleriRiomee BbmucnuTenbHbiiı npoqecc, naymuüı ot sapbupyeMbix ucxoflHbix flaHHbix k ncKOMOh/ıy pe3ynbTƏTy».

Öz sözlərimizlə alqoritmə belə tərif verə bilərik:Alqoritm - müəyyən tip məsələlərin həlli üçün sonlu

sayda addımlarla ilkin verilənlərdən son nəticə almaq üçün sonlu əməliyyatlar ardıcıllığı və ya təlimatdır.

1931-ci ildə alman riyaziyyatçısı Kurt Hedel (Kıırt Friedrich Gödel) tərəfindən isbat edilmiş teoremi müasir alqoritmlər nəzəriyyəsinin mənbəyi hesab etmək olar. O, göstərdi ki, bəzi riyazi problemlər müəyyən sinif alqoritmlərlə həll edilə bilməz. Hedelin bu işi alqoritm nəzəriyyəsinin inkişafına təkan verdi. Alqoritmlər nəzəriyyəsinə aid ilk sanballı işlər 1930-cu illərin ortalarında Alan Türinq (Alan Mathison luring), Alonzo Çerç (Alonzo Church} və Emil Post (Post Emil Leo) tərəfindən nəşr edildi. Onlar tərəfindən təklif edilmiş Türinq maşını, Post maşını və rekursiv hesablanan Çerç funksiyaları sinfi alqoritmin ilk formal təsvirləri idi ki, bu alqoritmlərdə ciddi hesablama modelləri istifadə olunmuşdu. Bu işlərin inkişafı nəticəsində

16 Məhərrəmov Z.T., Vəliyev H.P.

alqoritmik həll edilməzlik problemlərinin mövcudluğu isbat edildi. Alqoritmik həll edilməzlik o deməkdir ki, elə ümumi alqoritm (Türinq maşını) yoxdur ki, istənilən alqoritmin və onun ilkin verilənlərinin təsvirinə görə, bu verilənlərlə bu alqoritmin icrasının dayanacağını və ya sonsuz işləyəcəyini müəyyən etmək mümkün olsun. Bu problemlərin bir neçəsi ilə tanış olaq.

I. ir ədədinin yazılışında, məsələn, 9 rəqəminin paylanması.

f(n) = i funksiyasını tapaq. Burada, n - k ədədinin onluq yazılışında ardıcıl 9 rəqəmlərinin sayı, i isə n sayda ardıcıl 9 rəqəmləri içərisində, vergüldən sonra ən solda duran 9 rəqəminin sıra nömrəsidir. Məlumdur ki,

?r= 3,141592 ...və7T = 48arctg (1/18) + 24arctcj(l/57)

- 20arctg(l/239).ədədinin qiymətində f(l)=5 olur. Məsələ ixtiyari n

üçün f(n) funksiyasını tapmaqdan ibarətdir, äədədi irrasional və transendent ədəd olduğu üçün biz n ədədinin onluq yazılışında 9 rəqəminin və eləcə də digər rəqəmlərin paylanması haqqında heç bir məlumat bilmirik. f(n) funksiyasının hesablanması tt ədədinin n sayda ardıcıl 9 rəqəmi alınana qədər ayrılması ilə əlaqədardır. Lakin, biz f(n) funksiyasının hesablanması üçün ümumi metod bilmirik, ona görə də bir neçə n üçün hesablama sonsuz davam edə bilər. Biz, hətta, prinsipcə, ixtiyari n üçün məsələnin həllinin olub- olmadığını da bilmirik. Bu /rədədinin təbiəti ilə bağlıdır.

2. Mükəmməl ədədlərin hesablanması.Mükəmməl ədədlər elə ədədlərə deyilir ki, o özünün

bölənlərinin cəminə bərabər olsun, məsələn:S(l) =1 = 1,5(2) = 6 = 1 + 2 + 3,5(3) =28 = 1 + 2 + 4 + 7 + 14.İxtiyari n üçün 5(n) funksiyasını tapmaq tələb olunur.

Mükəmməl ədədlərin hesablanması üçün ümumi metod

Birinci fəsil. Alqoritmlərin analizinin riyazi əsasları 17

yoxdur, biz, hətta, sonlu və ya müəyyən miqdarda mükəmməl ədədlər çoxluğunun varlığını da bilmirik və ona görə də alqoritm bütün ədədlərin mükəmməl olub-olmadığını yoxlamaqla hər bir ədədi araşdırmalıdır. Ümumi metodun olmaması alqoritmin dayanması haqqında suala cavab verməyə imkan vermir.

Qeyd edək ki, 2019-cu ilə kimi 51 mükəmməl cüt ədəd müəyyən edilmişdir, mükəmməl tək ədədlərin mövcud olması indiyə kimi aşkar edilməmişdir, eyni zamanda, isbat edilməmişdir ki, onlar mövcud deyil.

3. Hilbertin 10-cu problemi.Fərz edək ki, n dərəcəli tam əmsallı P çoxhədlisi

verilmişdir. Elə bir alqoritm mövcuddurmu ki, tam ədədlər daxilində P-0 tənliyini həll etsin? Sovet və Rusiya alimi Motiyaseviç isbat etmişdir ki, P=0 tənliyinin tam ədədlər şəklində köklərinin tapılmasına imkan verən alqoritm və, ümumiyyətlə, ümumi metod yoxdur.

1950-ci illərdə akademik Kolmoqorov alqoritmlər nəzəriyyəsi sahəsində fundamental işlər gördü ki, bu işlər Markov normal alqoritmlərinə əsaslanırdı. Türinq. Post və Çerç alqoritmlərinin formal modellərinin və eləcə də Kolmoqorov və Markov modellərinin ekvivalent olduğu aşkar edildi, yəni, göstərildi ki, müəyyən modellərlə həll oluna biləcək istənilən problem digər modellərlə də həll edilə bilər. XX əsrin ikinci yarısında elektron-hesablama maşınlarının yaradılması alqoritmlər nəzəriyyəsinin inkişafına çox böyük təkan verdi və bu sahədə çox ciddi praktiki nəticələr əldə edildi.

1.2. Alqoritmin formal xassələri və təsvir üsulları

Müxtəlif sinif məsələlərin həllində ən müxtəlif alqoritmlər mövcuddur və ya onların işlənməsi tələb olunur.

18 Məhərrəmov Z. T., Vəliyev H.P.

Bütün bu alqoritmlər formal olaraq aşağıdakı xassələrə malik olmalıdır:

1. Alqoritm diskret olmalıdır, yəni alqoritm məsələnin həlli prosesini bir neçə sadə ardıcıl addımların yerinə yetirilməsi kimi təsvir etməlidir. Alqoritmin hər addımının yerinə yetirilməsi üçün sonlu zaman kəsiyi olmalıdır, başqa sözlə, ilkin verilənlərin son nəticəyə çevrilməsi zamana görə diskret şəkildə həyata keçirilir.

2. Alqoritm müəyyən (determinik) olmalıdır, yəni verilənlərin emal olunması üçün ciddi əməliyyatlar ardıcıllığı mövcud olmalıdır. Alqoritm ilkin verilənlərin eyni qiymətlərində həmişə eyni nəticələr verməlidir. Bundan başqa, alqoritmlərdə sıfra bölmə, mənfi ədədlərdən kvadrat kökalma, mənfi ədədlərin loqarifmlərinin hesablanması və s. kimi əməliyyatlara yol verilməməlidir.

3. Alqoritm kütləvi olmalıdır, yəni tərtib olunmuş alqoritm ilkin verilənlərin qiymətlərinin geniş intervallarda dəyişməsi halları üçün də yararlı olmalıdır. Alqoritmin kütləviliyi müəyyən çərçivə daxilində başa düşülməlidir, yəni, mütləq universal alqoritm yoxdur. Müəyyən bir məsələnin həlli üçün tərtib olunmuş alqoritm yalnız bu qəbildən olan müəyyən sinif məsələlərin həlli üçün yararlı ola bilər. Məsələn, xətti cəbri tənliklər sisteminin həlli üçün tərtib olunmuş alqoritm istənilən sayda tənlikdən ibarət xətti tənliklər sistemi üçün yararlı olmalıdır, lakin bu o demək deyildir ki, həmin alqoritm, məsələn, xətti diferensial tənliklər sisteminin həlli üçün də yararlı olmalıdır.

4. Alqoritm nəticəli olmalıdır, yəni hər bir alqoritm üzrə hesablama nəticəsində sonlu sayda addımlardan sonra cavab alınmalıdır, başqa sözlə, axtarılan nəticə alınmaqla alqoritmik proses öz axını ilə dayanmalıdır.

Alqoritmin bu əsas xassələrinin yerinə yetirilməsini istənilən misalda müşahidə etmək olar.

Məlumdur ki, verilmiş üç a, b və c ədədlərindən ən böyüyünün tapılması aşağıdakı ardıcıllıqla müəyyən edilir:

Birinci fəsil. Alqoritmlərin analizinin riyazi əsasları 19

1. a və b ədədlərinin müqayisə et. Əgər a<b olarsa, onda x=b, əks halda isə x=a qəbul et və ikinci bəndi yerinə yetir.

2. x və c ədədlərini müqayisə et. Əgər x>=c olarsa, onda üçüncü bəndi yerinə yetir, əks halda x-c qəbul et və üçüncü bəndi yerinə yetir.

3. x ədədini nəticə kimi qəbul et və dayan.

Asanlıqla görünür ki, bu sadə alqoritmdə bütün xassələrə əməl olunur. Belə ki, bu alqoritm a, b və c dəyişənlərinin istənilən qiymətlərində doğrudur, bundan başqa, ədədlərin müqayisəsi və ən böyük ədədin seçilmə ardıcıllığı o qədər müəyyəndir ki, səhv nəticə alınması ehtimalını tamamilə aradan qaldırır. Eləcə də bu xassələrin yuxarıda göstərdiyimiz Evklid alqoritmi üçün də doğru olmasını asanlıqla yoxlamaq olar.

Alqoritmlərin təsvir olunması üçün əsasən iki formadan - mətn və qrafik formalardan istifadə olunur. Alqoritmlərin mətnlə yazılışında izahedici mətnlərlə müşayiət olunan müxtəlif riyazi işarə və ifadələrdən istifadə olunur. Əslində alqoritmin bu təsvir forması məsələnin həlli qaydasının müfəssəl yazılışıdır. Alqoritmin belə təsvir formasına yuxarıda göstərdiyimiz ən böyük ortaq bölənin və ən böyük ədədin tapılması məsələlərinin alqoritmlərini misal göstərə bilərik. Alqoritmlərin mətn forması ilə təsvir üsuluna operator sxemi üsulu və alqoritmik dillər də aiddir.

Alqoritmlərin qrafik təsvir üsulunda isə hər biri müəyyən funksiyanı yerinə yetirən və blok adlanan müxtəlif həndəsi fiqurlardan istifadə olunur. Bloklar nömrələnir və bir-biri ilə istiqamətlənmiş üfqi və şaquli xətlərlə birləşdirilir. Lazım gələrsə, blokların daxilində qısa izahatlar yazmaq olar. Blokların həndəsi ölçüləri və sxemlərin qurulma qaydaları mövcud standartlar əsasında yerinə yetirilir.

20 Məhərrəmov Z.T., Vəliyev H.P.

1.3. Alqoritmlərin təhlili

1.3.1. Təhlil nədir?

Eyni bir məsələni bir neçə alqoritmlə həll etmək olar. Hər bir alqoritmin səmərəliliyi müxtəlif xarakteristikalarla təsvir olunur. Alqoritmin səmərəli olub-olmadığını araşdırmazdan əvvəl, bu alqoritmin qoyulmuş məsələni düzgün həll edib-etməməsini sübut etmək lazımdır. Əgər alqoritm məsələni düzgün həll etmirsə, onun səmərəliyinin mənası itir. Alqoritmi təhlil edildikdə onun yerinə yetirilməsi üçün lazım olan vaxtın miqdarı müəyyən edilir. Belə vaxt dedikdə alqoritmin dəqiq olaraq neçə saniyəyə və ya dəqiqəyə (saata) yerinə yetirilməsi deyil, alqoritmin yerinə yetirilməsi üçün təxminən neçə əməliyyatın yerinə yetirilməsi nəzərdə tutulur. Əməliyyatların sayı dolayı yolla elə alqoritmin nisbi yerinə yetirilmə vaxtını müəyyən edir. Ona görə də alqoritmin hesablama mürəkkəbliyinə bəzən vaxt deyirlər. Alqoritmin yerinə yetirilməsinin faktiki saniyələrinin miqdarı və ya əməliyyatların faktiki sayı alqoritmin təhlilində bir o qədər də əhəmiyyət kəsb etmir. Bunun əvəzinə bizi daha çox konkret alqoritmin əməliyyatlarının sayının ilkin verilənlərin ölçüsündən asılılığı maraqlandırır. Biz iki alqoritmi əməliyyatların sayının artma sürəti ilə müqayisə edə bilərik. Məhz artma sürəti alqoritmlərin təhlilində əsas rol oynayır, məsələn, ilkin verilənlərin kiçik qiymətlərində A alqoritmi ola bilər ki, B alqoritminə nisbətən daha az əməliyyat tələb etsin, lakin ilkin verilənlərin həcmi artdıqda bu mənzərə tamamilə dəyişə bilər. Qeyd edək ki, yalnız eyni bir məsələni həll edən müxtəlif alqoritmlər müqayisə edilə bilər. Ona görə də heç vaxt nizamlama alqoritmi ilə, məsələn, matrislərin vurulması alqoritmini müqayisə etmək olmaz, yalnız müxtəlif nizamlama alqoritmləri bir-biri ilə müqayisə edilə bilər. Müqayisə nəticəsində saniyələrin miqdarını və ya kompüter

Birinci fəsil. Alqoritmlərin analizinin riyazi əsasları 21

dövrlərinin sayını dəqiq hesablayan düsturlar axtarılmır. Bunun heç mənası da yoxdur. Belə ki, bu halda gərək kompüterin tipi də nəzərə alınsın.

Alqoritmlərin təhlilinin digər üsulu alqoritmin Pascal, C++, Java, C#, Python kimi yüksək səviyyəli dillərdə və ya ümumi psevdokodda yazılmasını nəzərdə tutur. Əgər psevdokod bütün alqoritmlər üçün ümumi olan idarəetmənin əsas strukturlarını reallaşdırırsa, onda onun xüsusiyyətləri əhəmiyyətli rol oynamır, for və ya while kimi dövrlər, if, case və ya switch şəklində budaqlanma mexanizmi istənilən proqramlaşdırma dilində mövcuddur və istənilən belə dil bizim məqsədimizə uyğun gələcək. Hər dəfə biz bir konkret alqoritmə baxacağıq, burada bir funksiya və ya proqramın fraqmenti iştirak edəcək və buna görə də yuxarıda sadaladığımız dillər heç bir rol oynamır. Ona görə də biz alqoritmləri təhlil etdikdə bəzi hallarda psevdokodlardan istifadə edəcəyik.

Alqoritmlərin mürəkkəbliyinin zəruriliyini bilmək üçün misala baxaq. Müasir kompüterlər çox böyük sürətə malikdir. Lakin praktikada elə məsələlərə rast gəlirik ki, bu sürət bizi qane etmir. Məsələn, O-dan 9-a kimi ədədlərin bütün ardıcıllığını əks etdirən n uzunluqlu bütün variantlar üçün ən azı 10” addım tələb olunur. Fərz edək ki, hər bir ardıcıllığı təhlil etmək üçün milyonda bir saniyə vaxt tələb olunur. Onda, rəqəmlərinin sayı 5 olan ədəd üçün - onda bir saniyə, 10 olan ədəd üçün - artıq 2 saat 40 dəqiqə. 1 I üçün - bir sutkadan çox, 12 üçün - 10 sutkaya qədər, 13 üçün, demək olar ki, - 4 ay, 14 üçün - 3 ildən çox, 15 üçün isə 30 ildən artıq vaxt tələb olunar. İlk baxışdan bu sanki problem yaratmır, axı indiki kompüterlərin sürəti çox böyükdür! Lakin, baxsaq görərik ki, 1998-ci ildən 2003-cü ilə qədər fərdi kompüterlərin sürəti təxminən 10 dəfə artmışdır. Belə nəticəyə gələ bilərik ki, hər 5 ildən bir kompüterlərin sürəti 10 dəfə artacaqdır. Və. əgər biz bu gün n uzunluqlu məsələni həll edə biliriksə, deməli, 1 üçün bu məsələni yalnız 5

22 Məhərrəmov Z.T., VəliyevH.P.

ildən sonra həll edə biləcəyik. Baxdığımız konkret misal üçün biz n^ll halı üçün bu gün bu məsələni həll edə biliriksə, onda yalnız 20 ildən sonra n = 15 halı üçün həmin məsələni həll edə biləcəyik. n=20 halı üçün məsələni həll etmək istəyən proqramçının halına isə acımaqdan başqa bir şey qalmır!

1.3.2. Yaddaşa görə təhlil

Biz alqoritmləri təhlil etdikdə onların mürəkkəbliyini əsasən vaxta görə təhlil edəcəyik. Bununla yanaşı, hər hansı proqramın işləməsi üçün nə qədər yaddaşın tələb olunması da əsas məsələlərdən biridir. Kompüterlərin inkişafının ilkin mərhələlərində, yəni kompüterlərin yaddaşının çox kiçik olduğu vaxtlarda, bu məsələ çox prinsipial əhəmiyyət kəsb edirdi. Alqoritmlər kifayət qədər məhdud yaddaş tələb edən və ya əlavə yaddaş tələb edən alqoritmlərə bölünürdü. Əksər hallarda proqramçılar daha az sürətli alqoritmlərə üstünlük verirdilər, çünki, onlar öz sərəncamlarında olan kiçik yaddaşa qane olmalı idilər. Ona görə də proqramçılar yaddaşdan qənaətlə istifadə etmək üsulları axtarırdılar. Fərz edək ki, (-10,10) intervalında həqiqi ədədləri yazmaq lazımdır. Əksər kompüterlərdə həqiqi ədədləri yerləşdirmək üçün adətən 4-8 bayt tələb olunur. Lakin, həmin ədədi əvvəlcədən 10-a vurub tam ədədə çevirsək, onun yerləşdirilməsi üçün 1 bayt kifayət edər. Deməli, 3-7 bayta qənaət etdik. 1000 belə ədədi yadda saxlayan proqramçı 300-700 bayta qənaət edəcəkdir. Nəzərə alsaq ki, 80-ci illərdə əksər kompüterlərin yaddaşı 32 Kb və ya 64 Kb idi, onda bu qənaət çox əhəmiyyətli olur. Məhz bu qənaət və proqramların uzun ömürlülük zərurəti 2000-ci ilin probleminə gətirib çıxarmışdı. Belə ki, əgər proqramda çoxlu müxtəlif tarixlərdən istifadə olunarsa, onda ilin yazılması üçün yaddaşın yarısına qənaət etmək mümkündür. Yəni, hər yerdə 1999 əvəzinə sadəcə

Birinci fəsil. Alqoritmlərin analizinin riyazi əsasları 23

olaraq 99 yazsaq böyük qənaət əldə oluna bilər. Məhz 80-ci illərdə yazılmış proqramların aqibəti bu səbəbdən 2000-ci ildə acınacaqlı oldu!

Hal-hazırda kompüter yaddaşı çox böyük olduğu üçün proqramçılar yaddaşa qənaət etmirlər, bəzən sadə proqramlar çox böyük yer tutur. Bu proqramı istifadə edənlər isə vəziyyətdən çıxış yolunu əlavə yaddaş almaqda görürlər. Məhz bunun nəticəsidir ki, kompüterlər öz dövrlərindən qat- qat əvvəl köhnəlir.

Alqoritmlərin təhlilinin digər problemi yaddaş və sürət arasında seçim etməkdən ibarətdir. Alqoritmi elə tərtib etmək olar ki, o, böyük həcm istifadə etməklə məsələni tez həll etsin və ya tərsinə, yavaş işləyərək az yaddaş tutsun. Buna misal olaraq ən qısa məsafə axtarışı alqoritmini göstərmək olar. Şəhərin xəritəsini şəbəkə şəklində təsvir edib iki nöqtə arasında ən qısa yolu tapmaq alqoritmini tərtib etmək olar. Hər dəfə hesabat aparmamaq üçün iki nöqtə arasındakı məsafəni cədvəl şəklində kompüterin yaddaşında saxlamaq olar. Böyük şəhərlər üçün belə nöqtələrin sayı bir neçə yüz minlərlə ola bilər. Onda bizə 10 milyarddan çox yaddaş xanası lazım gələrdi. Göründüyü kimi, bu halda seçim etmək üçün sadəcə olaraq əlavə 10 Gb yaddaş istifadə etməklə proqramı daha sürətli etmək olar.

1.3.3. Alqoritmin mürəkkəbliyi

Müxtəlif alqoritmləri müqayisə etdikdə onların mürəkkəbliyinin həll edilən məsələnin mürəkkəbliyindən necə asılı olduğu müəyyən etmək lazımdır. Hər hansı bir alqoritm üzrə 1000 ədədi nizamladıqda 1 saniyə, milyon ədədi nizamladıqsa isə 10 saniyə vaxt tələb olunduğu halda, başqa bir alqoritm üzrə həmin hesablamalara, uyğun olaraq, 2 və 5 saniyə tələb oluna bilər. Belə halda hansı proqramın yaxşı olması haqqında birmənalı fikir yürütmək mümkün

24 Məhərrəmov Z.T., Vəliyev H.P.

olmur. Emaletmə sürəti nizamlanacaq verilənlərin növündən asılıdır. Alqoritmlərin məhsuldarlığı müxtəlif mürəkkəbliyə malik olan məsələlərin yerinə yetirilməsindən asılıdır. Alqoritmin sürətini kəmiyyətin tərtibinə uyğun qiymətləndirmək olar. Bu məqsədlə böyük 0(/(n)) funksiyasından istifadə edilir. Əgər n giriş verilənlərinin ölçüsü artdıqda alqoritmin yerinə yetirilmə vaxtı f(n) funksiyasının artma sürəti ilə artırsa, onda alqoritm O(/(n)) mürəkkəbliyinə malik olur.

Mürəkkəbliyin izahında tez-tez “Böyük O" funksiyasının aşağıdakı işarələrinə rast gəlirik:

/(n) = 0(1) -sabit;/(n) = O(log(n)') -loqarifmik artım;f(n) = 0(n) -xətti artım;/(n) = 0(n * log(n)') -kvazi xətti artım;/(n) = 0(nAm) -polinomial artım;f(n) = 0(2An) -eksponensial artım.

Bu funksiyalarda A simvolu qüvvət üstünü bildirir, m isə ixtiyarı müsbət ədəddir.

/(n) = 0(g(ny) yazılışı onu müəyyən edir ki, ixtiyari böyük c=cl və n = N ədədləri üçün f(n) funksiyası g(n) funksiyasından daha yavaş artır. Başqa sözlə, c=cl və n>-N olduqda c*g(n)>=f(n). Burada, c hər hansı sabit, N isə giriş verilənlərinin sayıdır. Beləliklə, sadə dildə desək, O - alqoritmin yuxarıdan məhdudluğunu bildirir. Əgər biz bu iki funksiyanın qrafıkini çəksək, onda f(n) funksiyası özünün g(n) yuxarı sərhəddini aşmamalıdır (şəkil 1.1).

Alqoritmlərin hesablanması mürəkkəbliyini qiymətlən­dirmə növlərinin artma sırası ilə yerləşdirsək, aşağıdakı ardıcıllığı alarıq:

0(1), O(log n), 0(n), O(nlogn),O(n' k),O(k''n), 0(n!), 0(nAn).

Birinci fəsil. Alqoritmlərin analizinin riyazi əsasları 25

Bu siyahıda ilk sıralarda yerləşən mürəkkəbliyə uyğun alqoritmlər daha sürətlə işləyir.

Telefon məlumat kitabçası nümunəsində yuxarıdakı mürəkkəbliklərin bəzilərinə uyğun alqoritmlərin təsvirinə baxaq.

0(1) sabit mürəkkəbliyindən başlayaq. Təsəvvür edək ki, tələbə Samir telefon məlumat kitabçasında qrup yoldaşı Kamilin nömrəsi yazılmış səhifəni qatlamışdır. Bu, Kamilin nömrəsini orta hesabla sabit vaxt ərzində axtarmağa imkan verir, çünki, burada nömrələrin miqdarından düz asılılıq yoxdur və ya o, o qədər kiçikdir ki, onu nəzərə almamaq olar. Niyə orta hesabla? Çünki ona bu səhifədə müəyyən sayda digər yazıları nəzərdən keçirmək lazım olmuşdur ki, onu da kiçik olduğu üçün nəzərə almamaq olar.

Misal kimi bir “zənbildə” bir obyektin axtarışını göstərmək olar.

0(log n) — loqarifmik mürəkkəblik. Loqarifmik mürəkkəblik nisbətən çətindir. Təsəvvür edək ki, Samir Kamillə təzəcə tanış olmuşdur. O, onun soyadını bilir. Bəs

26 Məhərrəmov Z.T., Vəliyev H.P.

indi Kamilin nömrəsi olan səhifəni o necə axtaracaqdır? O. məlumat kitabçasını ortadan açır və hər hansı bir yazıya baxır və görür ki, burada soyadın baş hərfi Kamilin soyadındakı baş hərfdən əvvəldə yerləşir. Deməli, Kamilin nömrəsi məlumat kitabçasının ikinci yarısındadır. İndi o, məlumat kitabçasının Kamilin nömrəsi olan tərəfindən vərəqlər qalağını götürür və onun təxminən orta hissəsini açır və sair. Beləliklə, binar (ikili) axtarış alınır. Ona lazım olacaq müqayisələrin miqdarı məlumat kitabçasında səhifələrin miqdarının 2 əsasa görə loqarifminə bərabər olacaqdır. Hətta, əgər bu məlumat kitabçasına 10000 nömrədən ibarət daha 100 səhifə əlavə etsək də, müqayisələrin miqdarı kəskin artmayacaqdır. Bu, binar ağacı xatırladır ki, burada ən aşağı səviyyədəki obyekti tapmaq üçün ağacın hündürlüyünə bərabər sayda və ya yazıların ümumi sayının iki əsasdan loqarifmi qədər müqayisələr etmək lazımdır. Əgər məlumat kitabçasında 1000 səhifə olarsa, onda təxminən 10, 4000 səhifə olduqda isə təxminən 12 müqayisə etmək lazımdır. Göründüyü kimi, səhifələrin sayı 4 dəfə də artdıqda müqayisələrin sayı yalnız 2 vahid qədər artır.

Misal kimi binar ağacda axtarışı göstərə bilərik. Burada müqayisələrin miqdarı təxminən ağacın hündürlüyünə bərabər olur (əgər ağac, əlbəttə, tarazlaşdırılmışdırsa).

O(n) - xətti mürəkkəblik. Burada izahat daha sadədir. Tutaq ki, bizim telefon məlumat kitabçamızda bütün nömrələr təsadüfi qaydada yerləşmişdir. Onda ehtimal ki, Samir çox uzun müddət ərzində kitabda bütün nömrələri kor- koranə araşdıraraq Kamilin nömrəsini axtaracaqdır. Nə qədər çox axtararsa, o, əmin olacaq ki, belə səylər əziyyətə dəyməz. Əgər nömrələrin sayını 4 dəfə artırsaq, onda Samir də 4 dəfə daha çox vaxt sərf edəcək.

Bu mürəkkəbliyə aid misal kimi siyahıda qiymətə görə lazım olan yazının axtarışını göstərə bilərik.

O(n * log n) - kvaziloqarifmik mürəkkəblik. İndi fərz edək ki, Samirin əlinə bütün səhifələri qarışdırılmış məlumat

Birinci fəsil. Alqoritmlərin analizinin riyazi əsasları 27

kitabçası keçmişdir. O, əlbəttə, ağıllı olduğu üçün məlumat kitabçasının səhifələrini əlifba sırası ilə düzməyə qərar verəcək. Səhifədə birinci adamın soyadının birinci hərfi səhifəyə uyğun gəlir. Samir birinci səhifəni götürür və onu başqa cildə yerləşdirir. Sonra ikincini götürür və birinci adın birinci hərfindən asılı olaraq onu birincidən solda və ya sağda yerləşdirir. Kifayət qədər çox yığdıqdan sonra, o vərəqlər qalağının orta hissəsini açır, baxır və növbəti səhifənin solda və ya sağda olmasını müəyyənləşdirir. Müəyyən etdikdən sonra, daha kiçik qalaqlardan birini açır və həmin əməlləri təkrarlayır... ümumiyyətlə, yenə ikili axtarış alınır.

Burada biz iki hissədən ibarət məsələ alırıq: birinci - ilkin kitabın səhifələrinin araşdırılması və ikinci - yeni cildə yerləşdirmə. Əgər bunu proqramlaşdırmağa çalışsaydıq, yəqin ki, dövrdə yerləşdirərdik. Dövrə yerləşdirməyə sərf edilmiş vaxtı yuxarıdan təxminən vərəqlərin sayından 2 əsasa görə loqarifm ilə məhdudlaşdırmaq olar. Birinci yerləşdirmələri nəzərə almamaq olar. Bu halda isə bütün dövr yuxarıdan n * logn qədər məhdudlaşdırılacaq, harada ki, n kitabda səhifələrin sayıdır.

Misal olaraq sürətli nizamlamanı göstərmək olar.0(nA2) - polinomial mürəkkəblik. Fərz edək ki,

nəşriyyat nəyi isə qarışdırdı və telefon kitabında hər yazıya bir artıq rəqəm əlavə etdi və yazıların sayı qədər məlumat kitabçaları çap etdi.

Bu səhvi düzəltməyi Samirdən xahiş etdilər. O. n sayda məlumat kitabçalarını araşdırmalı və hər məlumat kitabçasının N sayda yazılarında bu son rəqəmin üstünü rəngləməlidir. Əgər biz bunu proqramlaşdırsaydıq, hər birində n iterasiya olmaqla bir-birinin daxilində olan 2 dövr alardıq. Nəticədə bu əməllər üçün n2 mürəkkəbliyini alırıq.

Müstəqil olaraq hər hansı alqoritmin mürəkkəbliyini qiymətləndirməyi bacarmaq üçün onun necə işləməsini dərk etmək lazımdır.

28 Məhərrəmov Z.T., Vəliyev H.P.

A(nxn) matrisinin hər sətrində ən böyük elementin tapılması kodunun nümunəsində O(f(Ny) funksiyasını araşdıraq:

for(int i=l; i<=n; i++){max:=A[i,1];for (int j = l; j<=n; j4 + )

if (A[i,j]>max) max:=A[i,j ] ; writeln(max);

Bu alqoritmdə i dəyişəni 1-dən n-ə qədər qiymətlər alır, i-nin hər bir qiymətində j da 1-dən n-ə kimi qiymətlər alır. Daxili dövrdə iterasiyaların ümumi sayı n*n və ya n2 olur. Bu alqoritmin mürəkkəbliyi 0(n2) olur (yəni, n2 ilə mütənasib olur). Alqoritmin mürəkkəbliyini qiymətləndirdik­də dövrün yalnız daha sürətlə artan hissəsini istifadə etmək lazımdır. Tutaq ki, alqoritmin işçi dövrü n3 + n düsturu ilə verilmişdir. Bu halda alqoritmin mürəkkəbliyi O(n3) olacaqdır, n artdıqda alqoritmin özünü necə aparması onun daha sürətlə artan hissəsindən asılıdır, n3 + n dövründə tənliyin birinci hissəsi (n3) üstünlük təşkil edir və funksiya n3-un qiyməti ilə müqayisə oluna bilər. Əgər n=100 olarsa, onda n3+n=1000100 ilə n3=1000000 arasında fərq 100-ə bərabər olur ki, bu da 0,01% təşkil edir. Nəzərdə tutmaq lazımdır ki, bu hökm yalnız böyük n üçün doğrudur. Əgər n=2 olarsa, onda n3 -I- n=10 və n3 = 8 olur və fərq 2-ə bərabər olur ki, bu da 2 0% təşkil edir. '"Böyük O" qiymətini hesabladıqda ifadələrdəki sabit ədədləri nəzərə almaq lazım gəlmir. Əgər n-nin qiymətini 2 dəfə artırsaq, onda 2 kvadrata yüksəldilir (n2) və alqoritmin yerinə yetirilmə vaxtı 4 dəfə artır. Yuxarıdakı alqoritmdə daxili dövr n2 dəfə hesablanır. Bəs hər bir dövr neçə addıma yerinə yetirilir? Bu suala cavab vermək üçün dövr daxilində neçə if operatorunun olduğunu

Birinci fəsil. Alqoritmlərin analizinin riyazi əsasları 29

bilmək lazımdır. Bundan başqa, xarici dövr daxilində çap operatoru yerləşir. Bunu da saymaq lazımdırmı? n2, 3*n2 və 3*n2+n alqoritmlərinin mürəkkəbliyi eyni bir O(n2) verir, ona görə də alqoritmin dəqiq neçə addıma yerinə yetirilməsini bilmək vacib deyildir.

Alqoritmin digər mürəkkəbliyi metodlara (prosedurlara) müraciətlə bağlıdır. Aşağıdakı metodlara baxaq:

static void Leng() {

int i,j,k;for (i=l; i<=n; for (j=l; j<=n; for (k=l; k<=n; (əməliyyatlar

}

i + +) j++) k + +)

static void Suret(){

int i,j;for (i=l; i<=n; i++) for (j = l; j<=n; j++) {Leng();əməliyyatlar

1

static void Birge') {

Suret ();əməliyyatlar

30 Məhərrəmov Z.T., Vəliyev H.P.

Burada, Leng() metodunun mürəkkəbliyi 0(n3), SuretO metodunun mürəkkəbliyi isə O(n2)-dır. Bütün proqramın mürəkkəbliyi isə bu iki metodun bir-birinə müraciətindən asılıdır. SuretO metodunun dövrləri icra olunduqda hər dəfə Leng () metoduna müraciət olunduğu üçün metodların mürəkkəbliyi bir-birinə vurulur, yəni, ümumi mürəkkəblik hər iki mürəkkəbliyin hasilinə bərabər olur. Baxılan hal üçün ümumi mürəkkəblik O(n2) * O(n3) və ya O(n2 * n3) = O(n5) olur.

Digər tərəfdən, əgər əsas proqram alt proqramları ayrı- ayrılıqda çağırarsa, onda ümumi mürəkkəblik metodların mürəkkəblikləri cəminə bərabər olur. Məsələn, aşağıdakı kodlara uyğun alqoritmin mürəkkəbliyi O(n3+n2) = O(n3) olacaqdır:

{əməliyyatlar

}

static void Leng()i

int i, j,k;for (i=l ; i<=n; i + +)for (j = l; j< = n; j+ + )for (k=l; k<=n; k++)

1

static void Suret() (

int i,j;for (i=l; i<=n; i++) for (j=l; j<=n; j++) {əməliyyatlar

}

static void BirgeO

Birinci fəsil. Alqoritmlərin analizinin riyazi əsasları 31

{Suret();Leng();

}

Nəhayət, sonda saniyədə milyon əməliyyat yerinə yetirən kompüterin bəzi yavaş alqoritmləri nə qədər müddətə yerinə yetirməsini göstərək (cədvəl 1.1).

Cədvəl 1.1. Yavaş alqoritmlərin yerinə yetirilmə müddətləriN=10 N=20 N=30 N=4FÖ N=50

N3 0,01 s. 0,01 san. 0,027 san. 0,064 san. 0,125 san.2n 0,01 s. 0,008 san. 17,9 dəq. 1,29 gün 35,7 il3n 0,059 s. 58,1 dəq. 6,53 il 3,86*105 il 2,28* 101(l ilM! 3,63 s. 7,71 * 104 i! 8,41 * 10,sil 2,59*10” il 9,64* 10İU il

1.3.4. Alqoritmlərdə müxtəlif halların təhlili

Alqoritmləri təhlil etdikdə üç müxtəlif halı araşdırmaq lazımdır:

• ən yaxşı hal;• ən pis hal;• orta hal.

Ən yaxşı hal. Alqoritmin ən yaxşı halı odur ki. bu alqoritm ən qısa vaxt ərzində yerinə yetirilir. Bu zaman verilənlər yığımı elə qiymətlər kombinasiyasından ibarət olur ki, alqoritm çox az əməliyyat yerinə yetirir. Əgər biz axtarış alqoritmini təhlil etsək, aşkar edərik ki, elə verilənlər yığımı ən yaxşı olacaq ki, orada axtarılan element alqoritmin birinci yoxlanılan xanasında yerləşsin. Belə alqoritmin mürəkkəbli­yindən asılı olmayaraq yalnız bir müqayisə əməliyyatı yerinə yetiriləcəkdir və alqoritm həmişə sabit vaxt ərzində işini başa

32 Məhərrəmov Z.T., Vəliyev H.P.

çatdıracaqdır. Belə alqoritmlər çox sadə olduğu üçün, adətən, alqoritmin ən yaxşı halını tədqiq etməyə ehtiyac qalmır.

Ən pis hal. Ən pis halın araşdırılması çox vacibdir, çünki, bu halda proqramın icrası maksimal vaxt tələb edir. Ən pis halı tədqiq etdikdə verilənlərin elə yığımını tapmaq lazımdır ki, proqram ən çox iş görsün. Axtarış alqoritmi üçün belə verilənlər yığımı axtarılan elementin siyahının sonunda olduğu haldır. Ən pis halın təhlili nəticəsində proqramın iş vaxtının ən yuxarı qiyməti müəyyən edilir.

Orta hal. Orta vəziyyətin təhlili ən mürəkkəb haldır, çünki, bu zaman külli miqdarda müxtəlif əməliyyatlar araşdırılır. Təhlilin əsasını ilkin verilənlər yığımının müəyyən qruplara bölünərək təhlil edilməsi təşkil edir. İkinci addımda verilənlərin hansı qrupa aid olması ehtimalı hesablanır. Üçüncü addımda alqoritmin hər bir qrupda işləməsi vaxtı hesablanır. Bu vaxt bütün qruplar üçün eyni olmalıdır. Orta iş vaxtı

mA(n) = ^piti

1=1

düsturu ilə hesablanır. Burada, n - ilkin verilənlərin ölçüsü, m - qrupların sayı, p, - verilənlərin z-ci qrupa daxil olması ehtimalı, t( isə z-ci qrupda alqoritmin yerinə yetirilmə vaxtıdır.

Bəzi hallarda ilkin verilənlərin qrupa daxil olması ehtimalı eyni qəbul edilir. Məsələn, qrupların sayı 5 olduqda verilənlərin l-ci, 2-ci və s. qruplara aid olması ehtimalı eyni, yəni, 0.2 olacaqdır. Bu halda orta iş vaxtı aşağıdakı düsturla hesablanır:

Qeyd edək ki, təhlillə əlaqədar bu faktlar və gələcəkdə istifadə ediləcək bir sıra yanaşmalar J.Makkonnellin çox mükəmməl yazılmış “Alqoritmlərin analizi” kitabından götürülmüşdür.

VERİLƏNLƏRİNSTATİK VƏ DİNAMİKSTRUKTURLARI

2.1. Verilənlərin strukturlarının təsnifatı

Verilənlərin strukturlarını bir neçə müxtəlif əlamətlərə görə təsnif etmək olar. Ən azı təsnifatın iki variantına baxaq. Onlardan birinə görə verilənlərin strukturları kifayət qədər böyük miqdarda kateqoriyalara bölünür. Müvafiq nümunələr göstərməklə bu kateqoriyalara baxaq.

Təsnifatın ən sadə və aydın kriterisi verilənlərin strukturlarının mürəkkəblik səviyyəsidir.

Mürəkkəblik, səviyyəsinə görə verilənlərin strukturu aşağıdakılara bölünür:

1. sadə strukturlar - proqramlaşdırma dillərinin tipləri üçün standart adi dəyişənlər və ya sabitlər, həmçinin bu tiplərin dinamik dəyişənləri;

2. eyni tipli verilənlər yığımı - birölçülü (və ya vektorlar), ikiölçülü (matrislər) və çoxölçülü massivlər;

3. massivlərdən fərqli tərkibli strukturlar - yazılar və sinif obyektləri və onlara oxşar strukturlar;

34 Məhərrəmov Z.T,, Vəliyev H.P.

4. daxili əlaqəli dinamik strukturlar - əlaqəli siyahılar, ağaclar, qraflar.

Arxitektura nöqteyi-nəzərindən verilənlərin strukturunu belə təsnif etmək olar:

1. xətti strukturlar - birölçülü massivlər (və ya vektorlar), xətti siyahılar, xətti növbələr, steklər;

2. düzbucaqlı strukturlar - ikiölçülü (matrislər) və çoxölçülü massivlər;

3. halqavari (halqa şəkilli və ya dövrü) strukturlar - halqavari siyahılar, halqavari növbələr, qrafların bəzi realizasiyaları;

4. budaqlanan strukturlar - müxtəlif növ ağaclar, qrafların bəzi realizasiyaları;

5. şəbəkə strukturları - qraflar.

Yaradılma üsuluna görə verilənlərin strukturunu belə təsnif etmək olar:

1. adi - standart tip deyişənlər, adi (yəni dinamik olmayan) massivlər, yazılar və s.;

2. dinamik (xüsusi əməliyyatların və ya yaddaşı dinamik ayıran və boşaldan metodların köməyi ilə yaradılan və məhv edilən) - dinamik massivlər, dinamik dəyişənlər, əlaqəli siyahılar, ağaclar.

Verilənlərin strukturunun elementləri arasında əlaqələrin olub-olmamasından asılı olaraq:

I. əlaqəsiz strukturlar - vektorlar, massivlər, sətirlər, steklər, növbələr;

2. əlaqəli strukturlar - siyahılar, ağaclar, qraflar.

Proqramın işi zamanı daimilikdən asılı olaraq:I. statik (dəyişməyən) struktur - müxtəlif tip

dəyişənlər, yazılar, massivlər, siyahılar, ağaclar və qraflar (nə

İkinci fəsil. Verilənlərin statik və dinamik strukturları 35

vaxt ki, onlar qeyd olunmuşdur və, məsələn, massiv əsasında qurulmuşdur);

2. dinamik (dəyişən) - siyahılar, ağaclar, növbələr, steklər, ümumi halda qraflar.

Burada ona diqqəti yönəltmək 'azımdır ki, ‘"dinamik” termini müxtəlif mənalarda istifadə edilir və yaradılma üsuluna görə dinamik olan strukturlar özlərini statik kimi apara bilər.

Statik strukturlar primitiv olmayan strukturlar kateqoriyasına aiddir ki, onlar faktiki olaraq, strukturlaşdırılmış primitiv çoxluqlar, baza və strukturlardan ibarətdir. Məsələn, vektor nizamlanmış ədədlər çoxluğu kimi təsvir edilə bilər. Tərifinə görə statik strukturlar dəyişməz olduğundan onlar üçün yaddaş bir dəfə ayrılır və onların həcmi struktur məhv edilənə qədər dəyişməz qalır. "Statik" sözü verilənlərin abstrakt tiplərindən daha çox strukturların reallaşdırılmasına aiddir. Verilənlərin ən sadə statik strukturu - massivdir.

Tərifinə görə dinamik strukturlar strukturun elementlərinin yaddaşda fiziki olaraq ardıcıl (yanaşı) yerləşməməsi ilə və onun emalı prosesində strukturun ölçüsünün (elementlərin sayının) sabit olmaması və gözlənilməzliyi ilə xarakterizə olunur.

Verilənlərin dinamik strukturu aşağıdakılarla xarakterizə olunur:

• o ada malik deyil;• proqramın icrası prosesində yaddaş onun tərəfindən

ayrılır;• strukturun elementlərinin miqdarı qeyd edilməyə

bilər;• strukturun ölçüsü proqramın icrası prosesində dəyişə

bilər;• proqramın icrası prosesində strukturun elementləri

arasında qarşılıqlı əlaqənin xarakteri dəyişə bilər.

36 Məhərrəmov Z. T., Vəliyev H. P.

Verilənlərin dinamik strukturlarına ehtiyac, adətən, aşağıdakı hallarda yaranır:

• kifayət qədər böyük ölçülü dəyişənlər istifadə olunur (məsələn, böyük ölçülü massivlər) ki, onlar proqramın bir hissəsində lazım olduğu halda, digər hissələrdə tamamilə lazım olmur.

• Proqramın işi prosesində massiv, siyahı və ya başqa struktur lazım olur ki, onun ölçüsü geniş həddə dəyişir və əvvəlcədən bu ölçünü bilmək mümkün olmur.

• proqram tərəfindən emal edilən verilənlərin ölçüsü verilənlər seqmentinin həcmini aşır.

Dinamik strukturun elementləri yaddaşın gözlənilməz ünvanlarında yerləşdiyi üçün belə strukturun elementinin ünvanını ilkin və ya özündən əvvəlki elementin ünvanına əsasən hesablamaq mümkün olmur. Dinamik strukturun elementlərinin arasında əlaqənin qurulması üçün göstəricilərdən (istinadlardan) istifadə olunur ki, onlar elementlər arasında aşkar əlaqələr yaradır. Yaddaşda verilənlərin belə təsviri əlaqəli təsvir adlanır. Dinamik strukturun elementi iki sahədən ibarətdir:

• informasiya sahəsi və ya verilənlər sahəsi. Burada o verilənlər saxlanır ki, məhz onların xatirinə struktur yaradılır. Ümumi halda informasiya sahəsi inteqrallaşdırılmış strukturdur, yəni o vektor, massiv, hər hansı digər dinamik struktur və s. ola bilər;

• əlaqə sahəsi. Bu sahə cari elementi strukturun digər elementləri ilə əlaqələndirən bir və ya bir neçə göstəricidən ibarət olur.

Verilənlərin əlaqəli təsvirinin üstünlükləri strukturların əhəmiyyətli dərəcədə dəyişkənliyini təmin etmək imkanının mümkün olmasıdir, yəni:

• strukturun ölçüsü yalnız kompüterin yaddaşının mümkün həcmi ilə məhdudlaşır;

İkinci fəsil. Verilənlərin statik və dinamik strukturları 37

• strukturun elementlərinin məntiqi ardıcıllığım dəyişdikdə yaddaşda verilənlərin yerdəyişməsi tələb olunmur, yalnız göstəricilərə düzəlişlər etmək kifayətdir;

• yadda saxlanılacaq informasiyanın həcmi praktiki olaraq məhdud deyil;

• strukturun çevikliyi (yaddaş gah ayrılır, gah boşaldılır).

Bununla yanaşı, əlaqəli təsvirlər çatışmazlıqlardan xali deyil və onlar aşağıdakılardır:

• əlaqə sahələrinin yadda saxlanması üçün əlavə yaddaş tələb olunur;

• əlaqəli strukturlarla işləmək üsulu nisbətən çətindir;• əlaqəli strukturun elementlərinə müraciət vaxta görə

daha az səmərəli ola bilər.Sonuncu çatışmazlıq daha ciddidir və verilənlərin

əlaqəli təsvirinin tətbiq edilməsini məhz o məhdudlaşdırır. Verilənlərin statik təsvirində istənilən elementin ünvanını hesablamaq üçün elementin nömrəsi və strukturun deskriptorunda olan informasiya kifayət etdiyi halda, əlaqəli təsvirdə elementin ünvanı ilkin verilənlərdən hesablana bilmir. Əlaqəli strukturun deskriptoru struktura daxil olmağa imkan verən bir və ya bir neçə göstəricini özündə saxlayır, sonra tələb edilən elementin axtarışı göstəricilər zənciri üzrə elementdən elementə keçməklə yerinə yetirilir. Buna görə də verilənlərin məntiqi strukturu elementin nömrəsi ilə girişə imkan verən vektorun və ya massivin olduğu məsələlərdə praktik olaraq heç vaxt tətbiq edilmir, amma məntiqi strukturun giriş üçün digər ilkin informasiya (cədvəllər, siyahılar, ağaclar və s.) tələb etdiyi başqa məsələlərdə tez-tez tətbiq edilir.

Verilənlərin dinamik strukturlarını belə təsnif etmək olar:

• bir istiqamətli siyahılar;• iki istiqamətli (iki əlaqəli) siyahılar;• halqavari (dövrü) siyahılar;

38 Məhərrəmov Z. T., Vəliyev H.P.

• stek;• dek;• növbə;• ikili ağaclar.Qeyd edək ki, bəzi mənbələrdə sadaladığımız bu tipləri

verilənlərin mücərrəd tiplərinə də aid edirlər.Onu da qeyd edək ki, təsnifat həmişə subyektiv

xarakterli olur, ona görə xatırlamaq lazımdır ki, istənilən təsnifat kifayət qədər şərtidir və bütün hallarda reallığı əks etdirə bilmir.

2.2. Verilənlərin strukturları üzərində yerinə yetirilən əməliyyatlar

Verilənlərin istənilən strukturları üzərində aşağıdakı dörd ümumi əməliyyat yerinə yetirilə bilər:

- yaradılma,- məhv edilmə,- seçmə (əldə etmə və ya giriş),- yeniləmə.Yaradılma əməliyyatı verilənlərin strukturu üçün

yaddaşın ayrılmasından ibarətdir. Yaddaş proqramın icrası prosesində və ya kompilyasiya mərhələsində ayrıla bilər. Proqramçı tərəfindən konstruksiya edilən strukturlaşdırılmış verilənlər üçün bir sıra dillərdə (məsələn, C və C#) yaradılma əməliyyatına həmçinin ilkin qiymətlərin təyin edilməsi də daxil olur.

Verilənlərin strukturlarının məhv edilməsi əməliyyatı yaradılma əməliyyatının əksidir. Pascal, C, C# dillərində blokun daxilində olan verilənlərin strukturu proqramın icrası prosesində blokdan çıxdıqda məhv edilir. Məhvetmə əməliyyatı yaddaşdan effektiv istifadə etməyə kömək edir.

Seçmə əməliyyatı strukturun özünün daxilində verilənləri əldə etmək (giriş) üçün proqramçılar tərəfindən

İkinci fəsil. Verilənlərin statik və dinamik strukturları 39

istifadə olunur. Giriş əməliyyatının forması müraciət edilən verilənlərin strukturunun tipindən asılı olaraq həyata keçirilir. Giriş metodu o vaxt əhəmiyyətli olur ki, o verilənlərin konkret strukturunun seçilməsi ilə bilavasitə əlaqəli olsun.

Yeniləmə əməliyyatı verilənlərin strukturunda verilən­lərin qiymətlərini dəyişdirməyə imkan verir. Yeniləmə əməliyyatına mənimsətmə əməliyyatını və ya daha mürəkkəb forma olan parametrlərin ötürülməsini misal göstərmək olar.

Yuxarıda göstərilən dörd əməliyyat verilənlərin bütün strukturları və tipləri üçün məcburidir. Bu ümumi əməliy­yatlardan başqa, verilənlərin hər strukturu üçün yalnız bu tip (bu struktur) ilə işləyən spesifik əməliyyatlar müəyyən edilə bilər. Belə spesifik əməliyyatları verilənlərin hər konkret strukturunu öyrəndikdə müzakirə edəcəyik.

2.3. Verilənlərin baza tipləri

Müxtəlif növ informasiyanı, məsələn, tam və həqiqi ədədləri, məntiqi qiymətləri və simvollar ardıcıllıqlarını emal etmək üçün proqramlaşdırma dillərində verilənlərin tipi anlayışından istifadə edirlər. Verilənlərin tipi - proqramda rast gəlinən istənilən qiymətin ayrılmaz atributudur. Verilənlərin hər bir tipi onların iki xarakteristikasını müəyyən edir:

• bu tipə aid olan verilənlərin ala biləcəyi mümkün qiymətlər çoxluğu;

• verilənlər üzərində yerinə yetirilə biləcək əməliyyatlar yığımı.

Bütün tipləşdirilmiş proqramlaşdırma dilləri (C, C++, C#. Go, Java, Python, PHP və başqaları) verilənlərin baza (primitiv) tipləri yığımını dəstəkləyir. Məsələn, tam ədədlər tipi (int), həqiqi ədədlər tipi (real, float), məntiqi tip (boolean), simvolik tip (char). Bu baza tipləri bütün proqramlaşdırma dillərində eyni mahiyyət daşıyır və yalnız

40 Məhərrəmov Z. T., Vəliyev H.P.

təsvir formasına görə (məsələn, tam tip bir dildə integer yazıldığı halda, digər dildə int kimi yazıla bilər) və qiymətlərin dəyişmə diapazonuna görə fərqlənə bilər.

Proqramlaşdırma dilinin tiplər sistemi proqramda hesablanmış hər bir qiyməti müəyyən tipə aid edir və onların üzərində əməliyyatların icra edilməsinin düzgünlüyünə nəzarət edir. Məsələn, proqramın kompilyasiyası və ya onun icrası mərhələsində sətir qiymətlərinin tam ədədə bölünməsi və s. kimi səhvlər aşkar edilə bilər.

Baza tiplərindən başqa, proqramlaşdırma dili verilənlərin tərkibli tiplərini (aqreqat, struktur, birləşmə tipləri) də dəstəkləyə bilər. Bu tiplər baza tipləri əsasında formalaşdırılır. Məsələn, C, C++ və C# dillərində massivlər, strukturlar və siniflər tərkibli verilənlər tiplərinə aid edilir.

2,4. Göstəricilər

Bütün proqram obyektləri və verilənlərin strukturu özlərinin kompüterin yaddaşında yerləşdikləri ünvanlarla xarakterizə olunur. Bu ünvanlar hər hansı formada proqramda istifadə edilə bilər, bunun üçün isə onlar haradasa yadda saxlanmalıdır. Ünvanları yadda saxlamaq üçün göstərici­lərdən istifadə edilir.

Göstəricilər - digər dəyişənlərin və ya funksiyaların, o cümlədən, siniflərin (hər hansı proqram obyektlərinin, məsələn, dəyişənlərin, massivlərin, yazıların) ünvanlarından ibarət dəyişənlərdir.

Göstəricilər öz təyinatlarına görə, yəni, digər dəyişənlərin ünvanlarını yadda saxladıqlarına görə qeyri-adi, özlərinin bəzi xassələrinə, məsələn, yerinə yetirilən əməliyyatlara görə isə adi dəyişənlərdir. Ünvanlar işarəsiz tam (uzun) ədədlər olduğundan göstəriciləri verilənlərin sadə (tamədədli) tiplərinə aid edirlər.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 41

2.4.1. Dəyişənlərə göstəricilər

C# dilində göstəricilər çox az hallarda istifadə olunur, ancaq bəzi hallarda əlavələri optimallaşdırmaq üçün onlardan istifadə etmək lazım gəlir. Göstəriciləri tətbiq edən kodları təhlükəli kodlar adlandırırlar. Ancaq bu o demək deyil ki. bu kod hansı isə bir təhlükə yaradacaq. Sadəcə olaraq göstəricilərlə işlədikdə yaddaşdan istifadə üzrə bütün əməliyyatlar, o cümlədən, yaddaşın təmizlənməsi qayğısı CLR (Commom Language Runtime) mühitinin yox, tamamilə proqramçının üzərinə düşür. CLR mühitinin nöqteyi-nəzərindən belə kod təhlükəsiz deyil, çünki mühit bu kodu yoxlaya bilmir, buna görə də müxtəlif növ səhvlərin baş verməsi ehtimalı artır.

C# dilində təhlükəli koddan istifadə etmək üçün, birinci növbədə layihəyə göstərmək lazımdır ki, o təhlükəli kodla işləyəcək. Bunun üçün layihənin kökləmək lazımdır, yəni. Solution Explorer (OöospeBaTejib pemeHMM) pəncərəsində layihənin adı üzərində kontekst menyunun Properties (CBofıcTBa) əmrini icra edib, açılan pəncərənin Build (Cöopıca) səhifəsində (və ya Project/ Properties/Build (npoeKT/CBOücTBa/CöopKa) əmri ilə açılan səhifədə) Allow unsafe code (PaspeııiMTb HedesonacHbiM koa) dəyişdiricisini qoşmaq lazımdır (şəkil 2.1).

İndi isə göstəricilərin tətbiqi ilə məşğul olaq.Göstəricidən istifadə edən kod bloku, metod və ya

struktur unsafe sözü ilə başlamalıdır. Belə kodların ümumiləşmiş strukturu müvafiq olaraq aşağıdakı kimi olacaqdır:

static void Main(string[] args)

// göstəricidən istifadə edən kod bloku

Məhərrəmov Z.T., Vəliyev H.P.

Ukaz-Microsoft Visua...LJ Zp | Ebicrpbiü sanycK (Ctrl+QJ «p| _ □ X

©aw/ı ripacxa Bh/j ("Igoeıcr £6opıca Or/ıa^tca 3a*np Mareppawoa ~

KoMaHAa Cpe/jcTBa Teçr Anann3 Okho Cnpaaxa

O - O I ö ’ İl W b? I ■?’<?’ I İDebug - İAnyCPU “| 2

Şəkil 2.1. Təhlükəli koddan istifadənin köklənməsi

unsafe( kodlar

}

// göstəricidən istifadə edən metod unsafe private static void Yad() {kodlar

}

// göstəricidən istifadə edən struktur// tipiunsafe struct Person {kodlar

1

İkinci fəsil. Verilənlərin statik və dinamik strukturları 43

Göstəricilərlə işlədikdə əsas əməliyyat * unar əməliyyatıdır. Bu əməliyyat göstərici ilə göstərilən dəyişənin ünvanına görə onun qiymətini almağa və ya təyin etməyə imkan verir. Dəyişənin ünvanını almaq üçün & unar əməliyyatı tətbiq edilir. Aşağıdakı kodda bu əməliyyatlardan istifadə edilmişdir:

using System;namespace Ukaz{class Program (static void Main(string[] args){unsafe{

int* x; // x göstərici kimi// təyin edilir

int y = 10; // adi y dəyişəninə// qiymət veririk

x = &y; // İndi x göstəricisi y// dəyişəninin ünvanını //göstərir

Console.WriteLine("Gostericinin baslangic qiymeti = " + *x) ; // iq

y = y + 20;Console.WriteLine("Gostericinin

yeni qiymeti = "+*x); // 30

* x = 50;Console.WriteLine("Gösteriçinin yeni qiymetinden sonra y= " + *x); // y=50

x = &y; // İndi x göstəricisi y//dəyişəninin ünvanını //göstərir

44 Məhərrəmov Z.T., Vəliyev H.P.

ulong ünvan = (ulong)x;//y dəyişəninin //ünvanı

Console.WriteLine("\ny deyişeninin ünvani= {0}", ünvan);

}Console.ReadLine();} } }

Proqramın nəticəsi şəkil 2.2-də göstərilmişdir.

F3 F\ZÄIflR\VSA\lJkaAUVaAhin\nehııg\lll<

lostericinin başlan gic qiymeti = 10iostericinin yeni qiymeti = 30lostericinin yeni qiymetinden sonra y= 50

deyiseninin unuani- 3273620

m

Şəkil 2.2. * və & unar əməliyyatlarının nəticələri

Göstəricini elan etdikdə int* x tipini göstəririk, yəni, tam ədədə göstərici elan edilir. Amma int tipindən başqa sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal və ya bool tiplərini də istifadə etmək olar. Göstəriciləri, həmçinin, enum tipinə, struktur tiplərinə və digər göstəricilərə elan etmək olar.

x=&y; operatoru bizə y dəyişəninin ünvanım almağa və ona x göstəricisini təyin etməyə imkan verir. Bu operatora qədər x göstəricisi heç nə göstərmirdi. Bundan sonra y ilə aparılan bütün əməliyyatlar x göstəricisi vasitəsilə alınan qiymətə və əksinə təsir edəcək, çünki, onlar yaddaşda eyni sahəni göstərir, x göstəricisi ilə göstərilən yaddaşda saxlanılan qiymətin alınması üçün *x ifadəsi istifadə edilir.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 45

Göstəricini tam tipə çevirməklə göstərici ilə göstərilən yaddaşın ünvanını ala bilirik. Bu əməliyyat ulong unvan= (ulong) x; kodu ilə yerinə yetirilir. Belə ki, ünvanın qiyməti tam ədəddir, 32-mərtəbəli sistemlərdə ünvanlar 0 - 4000000000 diapazonunda dəyişir, ona görə də ünvanın alınması üçün uint, long və ya ulong tipindən istifadə olunur. 64-mərtəbəli sistemlərdə isə ünvanların dəyişmə diapazonu daha geniş olduğundan dolub-daşma halının qarşısını almaq üçün ulong tipindən istifadə etmək daha yaxşıdır.

2.4.2. Göstəricilərə göstəricilər

Yuxarıda qeyd etdik ki, göstəricilər digər göstəriciləri də göstərə bilər. Bu halı aşağıdakı proqramla nümayiş etdirə bilərik:

static void Main(string[] args) { unsafe{int* x; // x göstərici kimi

// təyin edilirint y = 100; // adi y dəyişəninə

// qiymət veririk

x • &y; // x göstəricisi y dəyişə- // ninin ünvanını göstərir

int z = &x; // indi z göstəricisi x //göstəricisinin göstər- // diyi ünvanı göstərir

z - 2 + 900; // z göstəricisinin//dəyişməsi y-in dəyişmə- //sinə səbəb olur

Console.WriteLine("\n y = "+y);//y=1000 alınır

46 Məhərrəmov Z. T., Vəliyev H.P.

Console.WriteLine("**z = "+**z); // **z=1000 alınır

}Console.ReadLine();}

Proqramın nəticəsi şəkil 2.3-də göstərilmişdir.

Şəkil 2.3. Göstəricilərə göstərici əməliyyatının nəticəsi

2.4.3. Massivlərə göstəricilər

Massivlərə göstəriciləri tətbiq etmək üçün stackalloc operatorundan istifadə edilir. Bu operator vasitəsi ilə stekdə massivin elementləri üçün yaddaş ayrılır. Stekdə yaddaşın ayrılması kodun sürətini artırır. Faktorialın hesablanmasında massivə göstəricidən istifadə edək:

static void Main(string[] args) {unsafe{const int n = 7;mt* f = stackalloc int[n]; // Stekdə

//int tipli 7 obyekt üçün // yaddaş ayrılır

int* k = f;

(k++) =1; // Birinci xanaya 1

İkinci fəsil. Verilənlərin statik və dinamik strukturları 47

//qiyməti mənimsədirik və// göstəricini 1 vahid artırırıq

for (int i = 2; i <= n; i++, k++) {//7 ədədinin faktorialını hesablayırıq

*k = k[-l] * i;}for (int i = 1; i <= n; ++i){Console.WriteLine("{0}! = {l}",i,

f [ i - 1 ] ) ;}Console.ReadKey();}

Proqramın nəticəsi şəkil 2.4-də göstərilmişdir.

Şəkil 2.4. Göstərici ilə faktorialın hesablanması

stackalloc operatoru özündən sonra göstəricinin göstərdiyi massivi qəbul edir: int* f = stackalloc int[n];. Massivlə əməliyyatlar aparmaq üçün k göstəricisini yaradırıq: int* k=f; O. 7 elementdən ibarət massivin birinci elementini göstərir. Sonra göstəricinin özü ilə əməliyyat aparılır və faktorial hesablanır. 1 faktorial 1-ə bərabər olduğundan k göstəricisinin göstərdiyi birinci

48 Məhərrəmov Z.T., Vəliyev H.P.

elementə 1 qiyməti mənimsədirik: *(k++)=l;. Biz bu operatoru belə də yaza bilərik:

*k=l; k + +;Faktorial * k=k[-1]* i; operatoru ilə hesablanır.

2.5. Massivlər

Massivlər proqramlaşdırmada ən çox istifadə edilən tiplərdir. Massiv eyni tipli indeksli verilənlər yığımına deyilir. Massivin elementləri yaddaşda bir-birinin yanında ardıcıl yerləşir. Massivin elementlərinə onların indeksi (nömrəsi) vasitəsi ilə müraciət edilir. Elementlər ixtiyari tipli (lakin eyni) ola bilər. Massivlər bir ölçülü, iki ölçülü, uç ölçülü və s. olur. Massivlərin ölçüsü massivlərin indekslərinin sayı ilə müəyyən olunur. Bir ölçülü massivlərə, adətən, vektor deyirlər. İki ölçülü massivlər məntiqi səviyyədə qiymətlər matrisindən ibarət olur. Böyük ölçülü massivlər paralele- pipeddən (və ya matrislər yığımından), hiper paralelepiped- dən (və ya matrislər yığımı yığımından) ibarətdir. Bununla əlaqədar olaraq belə strukturları düzbucaqlı strukturlar adlandırırlar. Kompüterin yaddaşı unikal nömrəli xanaların xətti (faktiki olaraq birölçülü) ardıcıllığından ibarət olduğu üçün fiziki səviyyədə bir ölçüdən yuxarı massivlərin təsviri çətinlik yaradır. Belə massivlər birölçülü massivlər massivi kimi, faktiki olaraq, birölçülü massivlərə göstəricilər massivi kimi təsvir edilir.

İkiölçülü massiv, yəni matrislər halında, belə massivlərə göstəricilər massivlərinin hər birölçülü massivində matrisin sütunlarının və ya sətirlərinin elementləri saxlanılır. Sütunların və ya sətirlərin seçilməsi proqramlaşdırma dili ilə (C ailəsi dillərində - sətirlər) müəyyən edilir. Üçölçülü massiv üçün paralelepiped qatlardan ibarət olur, bu qatların hər biri bir matrisdir. Real olaraq qat matrisə göstəricidir,

İkinci fəsil. Verilənlərin statik və dinamik strukturları 49

bütün qatlar isə matrislərə göstəricilər massividir. Öz növbəsində, matris - vektorlara göstəricilər massividir. Beləliklə, çoxölçülü (və birölçülü) massivlərin elementlərinə müraciət etmək üçün göstəricilər istifadə oluna bilər.

İkiölçülü massivin elementləri sətirlər üzrə saxlanır, yəni əgər yaddaşda onların yerləşmə ardıcıllığına baxsaq, onda görərik ki, ən sağdakı indeks daha sürətlə dəyişir. Bu, böyük ölçülü massivlər üçün də doğrudur.

C# dilində massivlər aşağıdakı strukturla təsvir edilir: tip[] massivin adı =

new tip[elementlərin sayı];Burada: tip - baza tiplərindən biri, kvadrat

mötərizələr - massiv əlaməti, elementlərin sayı isə massivdə elementlərin sayını bildirir.

Massivin ölçüsünü kvadrat mötərizələr daxilində yazılmış vergüllərin sayının üzərinə 1 əlavə etməklə tapmaq olar. Əgər vergül yoxdursa, 0-ın üzərinə 1 əlavə edirik, deməli, vergül yoxdursa, massiv bir ölçülü olur. Massivlər ixtiyari ölçülü ola bilər. Uç ölçülü massiv belə elan edilir:

int [,,] y =new int [2, 2, 3];Massivin elementlərinə onların indeksləri vasitəsi ilə

müraciət edirlər. Yadda saxlamaq lazımdır ki, indekslər sıfırdan başlayır, yəni, birinci elementin sıra nömrəsi - 0, n- ci elementin sıra nömrəsi (n-1) olur.

Yuxarıda qeyd etdik ki, massivin elementləri ardıcıl yaddaş xanalarında yerləşir. Belə ardıcıl yerləşdirmə sabit 0(1) vaxtı ərzində elementin nömrəsinə görə onun yaddaşda yerləşdiyi ünvanını tapmağa imkan verir. Tutaq ki, k - birölçülü massivin birinci elementinin ünvanı, r isə massivin elementlərinin baza tipinin baytlarla ölçüsüdür. Onda i = 0,1,2,... indeksli elementin ünvanını aşağıdakı düsturla hesablamaq olar:

ünvan = k + ri.C# dilində dörd elementdən ibarət birölçülü massivə

baxaq:

50 Maharramov Z.T., Vəliyev H.P.

int[] a = { 6, 12, 8, 45 } ;Cədvəl 2.1-də, məsələn, 10 0-cü ünvandan başlayaraq

yaddaşda a massivinin elementlərinin ardıcıl yerləşdirilməsi göstərilmişdir. Massivin elementləri int tiplidir ki, bu baza tipli dəyişənlər yaddaşda 4 bayt yer tutur. 0 indeksli elementin ünvanı 100 olduğundan. 1 indeksli elementin ünvanı - 104, 2 indeksli elementin ünvanı 108 və s. olacaqdır, i indeksli elementin ünvanının almaq üçün 10 0 + 4 i ifadəsini hesablamaq kifayətdir. Bu ifadənin hesablanması cəmi iki əməliyyatın icra edilməsini tələb edir ki, bununla da indeksinə görə massivin elementinə müraciət sabit vaxt tələb edir.

Cədvəl 2.1. Massivin elementlərinin yaddaşda yerləşdirilməsi

İndeks 0 1 2 3Element 6 12 8 45Ünvan 100 104 108 112

Praktikada massivin elementlərinə müraciət etmək üçün proqramçıya aşkar formada yaddaş ünvanını hesablamaq tələb olunmur. Proqramlaşdırma dilinin kompilyatoru və ya interpretatoru bu məsələni öz üzərinə götürür. Belə ki, o indeksə görə massivin elementlərinə müraciəti müxtəlif üsullarla, indeks mötərizələri vasitəsi ilə (məsələn, a [i]) yerinə yetirir.

Massivlər üzərində yerinə yetirilən əsas əməliyyatlara baxaq. Ümumiliyə xələl gətirməmək üçün birölçülü massivlərə baxaq:

• massivə elementlərin yazılması və elementlərin oxunması (elementlərə müraciət), artıq qeyd etdiyimiz kimi, sabit 0(1) vaxt tələb edir.

• massivin elementlərinin axtarışının mürəkkəbliyi massivin nizamlanmasından asılıdır: əgər elementlər nizamlı

İkinci fəsil. Verilənlərin statik və dinamik strukturları 51

şəkildə (artma və ya azalma sırasında - bu yaxşı hala uyğundur) yerləşərsə, onda elementlərin axtarışı 0(J.ogn), əks halda isə (yəni pis halda) 0(n) əməliyyata həyata keçirilə bilər.

• massivin elementlərinin əlavə edilməsi/silinməsi əməliyyatı pis halda 0(n) əməliyyat tələb edir. Çünki, massivin strukturunun dəyişdirilməsi elementlərin yerlərinin dəyişdirilməsini tələb edir. Əgər əlavə edilmə/silinmə əməliyyatı massivin başlanğıcında və ya sonunda yerinə yetirilirsə (yaxşı hal), onda məsələnin mürəkkəbliyi 0(1) təşkil edir.

Massivə yeni elementin əlavə edilməsi proqramını tərtib edək. Massivə yeni elementin əlavə edilməsi onun ölçüsünü artırır, elementi sildikdə isə onun ölçüsü kiçilir. Massiv isə statik olduğu üçün onun strukturunun dəyişdirilməsi mümkün deyildir. Ona görə də bu əməliyyatları yerinə yetirdikdə ikinci, yeni elementlərdən ibarət massiv yaradılır.

Massivə yeni elementin əlavə edilməsi proqramı aşağıda verilmişdir:

static void Main(string[] args) {int index = 2; int elem = 500;int[] a = new int[] { 1, 2, 3, 4 }; Console.Write("ilkin massiv: ");for (int i = 0; i < a.Length; i++) {Console.Write(" " + a[i]);

1int size = a.Length + 1;int[] b = new int[size];if (index > 0)

for (int i = 0; i < index; i++) {b [ i ] = a [ i ] ;

52 Məhərrəmov Z.T., Vəliyev H.P.

}b[index] = elem;for(int i=index+l; i<=a.Length; i++) {

b[i] = a[i-l];} }Console.Write("\nElement elave edilnmiş

massiv: ") ;for (int i = 0; i < size; i++) Console.Write(" " + b[i]);

Console.ReadLine();}

Bu proqramda a massivinin index mövqeyinə elem yeni elementi əlavə edilir. Alqoritmin mahiyyəti belədir. Əlavə edildikdən sonra massivin elementlərinin sayı a massivinin elementlərinin sayından 1 vahid çox olacaq. Ona görə də elementlərin yeni sayına uyğun b massivi yaradırıq. Əlavə ediləcək mövqeyə qədər hər iki massivin elementləri eyni olur, ona görə də index indeksinə qədər dövr yaradılıb a-nın elementləri b-yə mənimsədilir, b-nin index indeksli elementi isə əlavə ediləcək elementə, yəni, elem deyişəninə bərabər edilir: b [index] =elem;. Bundan sonra index+1 mövqeyindən sonrakı elementlər dəyişməz qalmalıdır, ona görə yeni dövr təşkil edilərək b[i]=a[i-1] ; mənimsət­məsin! icra edirik.

Proqramın nəticəsi şəkil 2.5-də göstərilmişdir.

> F:\ZAKIR\VSA\ELWE ET1\ELAVE ETl\bin\Debuq\EUWE E.J

Şəkil 2.5. Massivə yeni elementin əlavə edilməsi

İkinci fəsil. Verilənlərin statik və dinamik strukturları 53

Massivdən elementin silinməsi alqoritmi isə belədir:

static void Main(string[] args) { int index = 2;int[] a = new int[] { 1, 2, 3, 4 }; int size = a.Length - 1;Console.Write("ilkin massiv: "); for (int i = 0; i < a.Length; i++)

Console.Write(" " + a [i]);} int[] b = new int[size]; if (index > 0) { for (int i = 0; i < index; i++) {b [ i ] = a [ i ] ;

} for (int i = index; i < size; i++) {b [ i ] = a [ i + 1 ] ;

11

Console.Write("\nElementi silinmiş massiv: ") ;

for (int i = 0; i < size; i++)Console.Write(" " + b[i]) ;

Console.ReadLine(); }

Burada index indeksli element massivdən silinir. Yeni, elementlərinin sayı 1 vahid az olan massiv yaradılır. Silinəcək mövqeyə qədər hər iki massivin elementləri eyni olur, ona görə də index indeksinə qədər dövr yaradılıb a- nın elementləri b-yə mənimsədilir. index indeksindən başlayaraq a-nın elementləri bir vahid sola sürüşdürülməlidir,

54 Məhərrəmov Z.T., Vəliyev H.P.

ona görə dövr daxilində b [ i ] =a [ i +1 ] ; mənimsətməsini icra edirik.

Proqramın nəticəsi şəkil 2.6-da göstərilmişdir.

<> \ FAZAKIP.\VSA\SILME\SILME\bin\Debug\S(LME.exe

ilkin nassiv: 12 3 4Elementi s ilinmiş nassiv: 12 4

Şəkil 2.6. Massivdən elementin silinməsi

Qeyd edək ki. C# dilində massivlərlə işləmək üçün xüsusi Array sinfi mövcuddur. Bu sinifdə aşağıdakı statik metodlar mövcuddur:

» > Clear () metodu - massivdən müəyyən sayda simvolları silir (sıfra çevirir);

❖ Sort() metodu - massivin elementlərini onların qiymətlərinin artma sırası ilə düzür;

♦ ♦♦ Clone () metodu - massivin surətini yaradır;♦ >IndexOf() metodu - massivin göstərilən

elementinin indeksini tapır;♦ >Copy() metodu - massivin elementlərini digər

massivə köçürür;• >Reverse() metodu - massivin elementlərini

tərsinə (əks istiqamətdə) çevirir.Sonda qeyd edək ki. pilləli (“cırıq’’) massiv anlayışı da

mövcuddur. Pilləli massiv - massivlər massividir. Belə massivlərdə hər bir massivin elementlərinin sayı müxtəlif ola bilər (şəkil 2.7).

Massivlərin iki çox böyük üstün cəhəti istənilən elementə sabit vaxt ərzində müraciətin mümkünlüyündə və yaddaşdan yalnız elementlərin yerləşdirilməsi üçün istifadə edilməsindədir. Geniş tətbiq edilməsinə baxmayaraq, onların

İkinci fəsil. Verilənlərin statik və dinamik strukturları 55

çox böyük çatışmaz cəhətləri də vardır. Bunlardan biz iksini əyani olaraq müşahidə etdik: massivə yeni elementin əlavə edilməsi və elementin silinməsi. Yuxarıda gördük ki, massivə yeni elementi əlavə etmək və onu silmək mümkün deyil. Belə ki, biz bu əməliyyatları yeni massiv yaratmaqla icra etdik. Çünki massivlər statik, dəyişməz struktura malikdir. Bundan başqa, bu əməliyyatlar ən pis halda 0(n) əməliyyat tələb edir.

Şəkil 2.7. Pilləli massiv

aoo 3 31

a10 Ən 312 313

a2C a2:

a2 33: a33

2.6. Dinamik massivlər

Yuxarıda göstərildiyi kimi, öz təşkilinə görə massivlər, prinsipcə, statik strukturlu verilənlərdir. Onların ölçüləri proqramın bütün işi prosesində və ya yaradıldığı andan məhv edilənə kimi dəyişməz olaraq qalır. Bu halda “dinamik" termini massivin yaradılması üsuluna aid edilir. Dinamik massivlərin elementlərini istənilən zaman pozmaq, onların tutduğu yaddaşı boşaltmaq, zərurət yarandıqda isə massivi yenidən yaratmaq olar.

Əsas proqramlaşdırma dilləri özlərinin standart kitabxanalarında dinamik massivləri dəstəkləyir. C++ dilində bu - vector, Java dilində - ArrayList, C# dilində isə List adlanır.

Dinamik massivlər üzərində aşağıdakı əməliyyatlar yerinə yetirilə bilər:

• massiv üçün yaddaşın ayrılması;• massivin elementlərinə müraciət;• yaddaşın boşaldılması.

56 Məhərrəmov Z.T.^ Vəliyev H.P.

Aşağıdakı proqram kodu ilə C# dilində siyahılar əsasında dinamik massivlərin yaradılması və proqramın işi prosesində elementlərin əlavə edilməsi, silinməsi və s. əməliyyatlar icra edilmişdir:

static void Main(string[] args) {List<char> İst = new List<char> ();Console.WriteLine("Elementlerin ilkin

sayi: " + İst.Count);Console.WriteLine();Console.WriteLine("6 elementin elave

edilmesi");

// Dinamik massivə elementlərin// əlavə edilməsi:İst.Add('C');İst.Add(1 A');İst.Add('E');İst.Add('B' ) ;İst.Add('D');İst.Add( ’ F ’ ) ;

Console.WriteLine("Elementlerin sayi: " + İst.Count);

// Massivi indeksləşdirməklə dinamik// massivin elementlərinin göstərilməsi Console.Write("Mezmunu: ");for (int ı=0; i < İst.Count; i++) Console.Write(İst[i] + " ");

Console.WriteLine("\n") ;Console.WriteLine("2 elementin

silinmesi ");

// dinamik massivdən// elementlərin silinməsi:İst.Remove( ' F ' ) ;İst.Remove('A');

ikinci fəsil. Verilənlərin statik və dinamik strukturları 57

Console.WriteLine("Elementlerin sayı: ' + İst.Count);

// foreach dövrü ilə dinamik massivin // elementlərinin göstərilməsi Console.Write("Mezmunu: ");foreach (char c in İst)Console.Write(c + " ");

Console.WriteLine("\n");Console.WriteLine("Yeni 20 elementin

əlavə edilməsi");// Massivi böyütmək üçün //20 elementin əlavə edilməsi:

for (int i = 0; i < 20; i++) İst.Add((char)('a' + i));

Console.WriteLine("Cari hecm: " + İst.Capacity);

Console.WriteLine("Yeni 20 elementin elave edilmesinden sonra

elementlerin sayi: " + İst.Count);Console.Write("Mezmunu: ");foreach (char c in İst)Console.Write(c + " ");

Console.WriteLine("\n");

// İndeksləşdirməklə dinamik massivin // məzmunun dəyişdirilməsi:

Console.WriteLine("Birinci 3 elementin deyişdirilmesi");

1 s t [ 0 ] = ' X' ;lst[l] = 'Y';1s t [ 2] = 'Z';Console.Write("Mezmunu: ");foreach (char c in İst)Console.Write(c + " ");

Console.WriteLine();Console.ReadLine();

58 Məhərrəmov Z.T., Vəliyev H.P.

Proqramın nəticəsi şəkil 2.8-də göstərilmişdir.

F:\ZAK1R\VSA\D1NAM1K MASSIV\DINAMIK MASSV\bin\Debug\DlNAMIK MA...

enentlerin m sayı:

I

elementin elaue edilmes lementlerin sayi: 6 lezmunu: C A E B D F

elementin silinmesi lenentlerin say?: 4 lezmunu: C E B D

'eni 20 elementin elaue edilmesilari hecm: 32feni 20 elementin elaue edilmesinden lezmunu: CEBDabcdef g Jı i j

lirinci 3 elementin deyisdirilmesi leznunu: XYZDabcdefghij

sonra kim

eleraentlerin sayi: 24

kin n o p q r s t

Şəkil 2.8. Dinamik massivlər üzərində müxtəlif əməliyyatların yerinə yetirilməsi

Bu proqramla C# dilinin List sinfi əsasında elementləri simvollardan ibarət olan İst dinamik massivi yaradılmışdır. Massiv üzərində əməliyyatlar List sinfinin aşağıdakı metodları ilə icra edilmişdir:

• Add () metodu - massivə elementlərin əlavə edil­məsi;

• Remove () metodu - massivdən elementin silinməsi;• Count xassəsi - massivin elementlərinin sayı;• Capacity xassəsi — dinamik yaddaşın cari ölçüsü.Proqram kodunda yazılmış şərhlər və alınmış nəticələr

proqramı anlamağa imkan verir.

2.7. Sətirlər

Sətirlər C# dilində verilənlərin tərkibli strukturuna aiddir, string tipi ilə müəyyənləşdirilmişdir və Unicode simvollar yığımından ibarətdir. Ona .NET kitabxanasının

İkinci fəsil. Verilənlərin statik va dinamik strukturları 59

System. String baza sinfi uyğun gəlir. Sətirlər cədvəl 2.2-də göstərilmiş üsullarla yaradıla bilər.

Cədvəl 2.2. Sətirlərin yaradılması üsullarıSətrin yaradılması üsulu Mahiyyəti

s L r i n g s ; s dəyişəni sətir tipli elan edilirstring s="Biri vardı, biri yox"; s dəyişəni literal ilə inisiallaşdırılir

string s=@"Daglıq QarabağAzerbaycanın tarixi torpağıdır:!!"

3 simvolu string konstruktoruna bil­dirir ki, sətir bir neçə sətirdə yerləşsə də, onu olduğu kimi qəbul etmək lazımdır

string s=new string J'd’,20);

Konstruktor 2 0 ədəd d simvolundan ibarət sətir yaradır

int x = 12344556; string s =x.ToSt rina();

Tam tipli x dəyişənini inisiallaşdırılır və o, string tipinə çevrilir

char['a={’N’,’i',’z’ , ’ a ' f ’ m' , ' i ’ } ;string s=

new string (a);Simvollar ınassivi yaradılır

char [ 1a={ 1 a 1, 'B1 , 'a', ' k' , ' i ' , ' 8 ' , ' r' ) ; string s= new

string(a , 1, 4 ) ;

Simvollar massivinin bir hissəsindən sətrin yaradılması; burada: 1-inisializa- siya üçün neçənci simvoldan başlanma­sını, 4 isə neçə simvolun istifadə edil­məsini bildirir.

Sətirlər ikiqat dırnaq işarələri daxilində yazılır, məsələn:

string s="Sirler xezinesi";string d="a";char f='a'; //bu simvol tipidir.Sətir tipli dəyişən istənilən sayda simvollar

ardıcıllığından ibarət qiymət ala bilər. Onlar üzərində aşağıdakı əməliyyatları yerinə yetirmək olar:

• mənimsətmə (=);• bərabərliyin yoxlanması (==);• bərabər olmamağın yoxlanması (I =);

60 Məhərrəmov Z. T., Vəliyev H.P.

• indeksə görə simvola müraciət [ ];• sətirlərin birləşdirilməsi və ya konkatenasiya (+).

Misal. Sətirlər üzərində əməliyyatlar.

static void Main(string[] args) (string dil ="JAVA";string c = "J";c = c +"AVA";Console.WriteLine(c == dil);char k = dil[2];Console.WriteLine("k = "+k);Console.ReadLine();}

Proqramın icrasından sonra TrueK = V

alınacaqdır. Biz bu proqramda k simvol tipli dəyişəni vasitəsi ilə sətir tipli dil dəyişəninin simvollarına massivin elementi kimi müraciət etdik (konkret olaraq 2-ci simvoluna, yəni V simvoluna). Halbuki, bu yol ilə sətir simvollarını dəyişdirə bilmərik, məsələn, dil [2] ="R"; kodu yolverilməzdir. Bu onunla əlaqədardır ki, string tipli sətirlər verilənlərin dəyişdirilə bilməyən tiplərinə aiddir.

String sinfində sətirlər üzərində ixtiyari əməliyyat­ları yerinə yetirməyə imkan verən çoxlu statik və nüsxə metodları mövcuddur. Bu metodlar cədvəl 2.3-də göstəril­mişdir.

Xatırladaq ki, statik metodlara onların adlarına müraciətlə, məsələn, String.Concat(a,b); kimi, qalan hallarda isə sinfin nüsxəsinə müraciət etməklə, məsələn, metn . Length; kimi müraciət edilir.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 61

Cədvəl 2.3. String sinfinin metodları

Metodun adı Metodun növü Təyinatı

Compare Statik metod

İki sətrin əlifba sırası ilə müqayisəsi

CompareTo Nüsxə metodu

Cari sətrin nüsxəsinin digər sətirlə müqayisəsi

Concat Statik metod

İxtiyari sayda sətirlərin birləşdirilməsi

Copy Statik metod

Sətrin surətinin yaradılması

Empty Statik metod

Boş sətirdən ibarət açıq statik sahə

Format Statik metod

Sətrin verilmiş formata uyğun formatlaşdırılması

IndexOf, IndexOfAny, LastlndexOf, LastlndexOfAny

Nüsxə metodları

Sətrə daxil olan alt sətrin və ya verilmiş yığımdan istənilən simvolun birinci və sonuncu indekslərinin tapılması

Insert Nüsxə metodu

Alt sətrin göstərilən mövqeyə yerləşdirilməsi

Joir. Statik metod

Massivlər sətrinin bir sətirdə birləşdirilməsi. Massivin elementləri arasına ayrıcılar əlavə edilir

Lengtn Xassə Sətrin uzunluğunu qaytarır

PadLeft, PadRigth

Nüsxə metodları

Sətrin başlanğıcına və ya sonuna lazım olan sayda boşluqlar əlavə etməklə onu sol və ya sağ tərəfə düzləndirir

Remove Nüsxə metodu

Göstərilən mövqedən alt sətrin pozulması

Replace Nüsxə metodu

Sətrə daxil olan alt sətir və ya simvolların yeni alt sətir və ya simvollarla əvəz edilməsi

Spl i t Nüsxə metodu

Müxtəlif ayrımlardan istifadə etməklə sətri elementlərə ayırır. Nəticələr massivlər sətrinə yerləşdirilir.

StartWith, EndWith

Nüsxə metodları

Sətrin verilmiş alt sətirlə başlaması və ya qurtarmasından

62 Məhərrəmov Z.T., Vəliyev H.P.

asılı olaraq true və ya false qiyməti qaytarır

Substring Nüsxə metodu

Göstərilən mövqedən başlayaraq alt sətrin seçilməsi

ToCharArray Nüsxə metodu Sətri simvollar massivinə çevirir

ToLower, Toüpper

Nüsxə metodları

Sətrin aşağı və ya yuxarı registrə çevrilməsi

Tr im, TrimStart, TrimEnd

Nüsxə metodları

Sətrin başlanğıcından və sonundan və ya yalnız bir tərəfindən boşluqların pozulması

Bu funksiyaların bir neçəsini proqramla izah edək.

Misal. Sətirlərin emalı.

static void Main(string[] args) (

String metn ="Microsoft Excel-2015";

Console.WriteLine("Metnde simvolların sayı: " +metn.Length);

Console.WriteLine("Metnin yuxarı registrde tesviri: " +metn.Toüpper());

Console.WriteLine("Metnin aşağı registrde tesviri: " +metn.ToLower());Console.WriteLine("Metnde Excel sözü varmı?(True - var, False - yoxdur) "

+metn.Contains("Excel"));Console.WriteLine("Excel sözünün setirdə

mövqeyi: " +metn.IndexOf{"Excel"));

Console.WriteLine("Excel sözünün Word sözü ile evez edilmesi:\n"+

metn.Replace("Excel", "Word"));

Console.ReadLine();}

ikinci fəsil. Verilənlərin statik və dinamik strukturları 63

Proqramın nəticəsi şəkil 2.9-da göstərilmişdir.

I ’ C:\Usera\Usei\Desktop\CCC\ConsolsApp29\ConsoleApp29\bin\Debug\C.J D I —

letnde simvolların sayı: 20letnin yuxarı registrde tesviri: MICROSOFT EXCEL-2015letnin aşağı registrde tesviri : nicrosoft excel-2015letnde Excel sözü varm? <Irue - var, False - yoxdur) TrueExcel sözünün setirde mövqeyi: 10Excel sözünün Uord sözü ile evez edilmesi:ücrosoft Uord-2015

Şəkil 2.9. Sətirlərin emalı

Daha bir misala baxaq.

Misal. Sətirlərin emalı.

static void Main(string[] args) { string a ="Microsoft";string b =" Excel"; string c ="-2015";

string setir = String.Concat(a, b, c); Console.WriteLine("Yaradılan setir: "

+ setir);string d = String.Copy(b);Console.WriteLine("Excel sözünün

suretinin yaradılması: " + d) ; string f = setir.Remove(15, 5);Console.WriteLine("-2015 alt metni

pozulduqdan sonra qalan setir: " + f ) ;

string g = c.Insert(0, "Windows"); Console.WriteLine("c deyişenine Windows

alt setrinin elave edilmesi: " + g) ;

Console.ReadLine();}

64 Məhərrəmov Z.T., Vəliyev H.P.

Proqramın nəticəsi şəkil 2.10-da göstərilmişdir.

1' C:\U>eK\User\DMİrfGp\CCnC.nnvdpApp2q\fnn«MgApp2Q\hin\n»hLig\Cn-l a I |ı—

laradılan setir: Microsoft Excel-2015Excel sözünün suretinin yaradılnası: Excel-2015 alt netni pozulduqdan sonra qalan setir: Microsoft Excel c deyişenine Uindows alt setrinin elave edilnesi: Uindows-2015

Şəkil 2.10. Sətirlərin Concat, Copy, Remove və Insert metodları ilə emalı

Bu misalda, əvvəlcə, sətir tipli üç a, b və c dəyişənləri inisiallaşdırılır, sonra isə Concat statik metodu vasitəsi ilə onlar birləşdirilərək setir adlı yeni dəyişən yaradılır, string d=String.Copy(b); kodu ilə b dəyişəninin surəti yaradılmışdır. Remove metodu ilə setir dəyişəninin 15-ci mövqeyindən 5 ardıcıl simvol pozulur (-2015 alt sətri). C dəyişəninin isə əvvəlinə Windows alt sətri əlavə edilmişdir (string g=c . Insert (0, "Windows");).

2.8. Yazılar

Hər şeydən əvvəl qeyd edək ki, C ailəsi dillərində yazılara strukturlar deyirlər. Biz də bu termindən istifadə edəcəyik.

Struktur - müxtəlif tipli, bir proqram obyektində birləşdirilmiş məntiqi əlaqəli informasiya yığımıdır. Siniflər kimi strukturlar da sahələrdən və metodlardan ibarətdir. Strukturun sahələri müxtəlif tipli ola bilər. Strukturun adı struct sözü ilə başlamalıdır. Aşağıdakı proqramla Adam adlı struktur yaradılmış və onun string tipli AD, string tipli cinsi və int tipli boyu adlı üç sahəsi müəyyən edilmişdir. Main metodunda bu sahələrə qiymətlər verilmiş

ikinci fəsil. Verilənlərin statik və dinamik strukturları 65

və ekrana çıxarılmışdır. Diqqət yetirin ki. strukturun sahələrinə strukturun adı vasitəsi ilə müraciət edilir, yəni, sahəyə müraciət etmək üçün strukturun adından sonra nöqtə simvolu qoyub sahənin adını yazmaq lazımdır.

namespace Struct { class Program {

struct Adam {

public string Ad; public int boyu; public string cinsi;

}

static void Main(string[] args) {

Adam Rauf;Rauf.Ad = "Rauf";Rauf.boyu = 17 6;Rauf.cinsi = "kishi";

Console.WriteLine($"Adi: {Rauf.Ad}\nCinsi: {Rauf.boyu}\nBoyu:

{Rauf.cinsi}");

Console.ReadKey(); } } 1

Proqramın nəticəsi şəkil 2.11-də göstərilmişdir.Qeyd edək ki, strukturlara da göstəricilər yaratmaq olar.

Strukturun sahələrinə göstərici vasitəsi ilə müraciət etmək üçün -> əməliyyatı tətbiq edilir. İki int tipli sahəsi olan Adam adlı struktura göstərici yaradaq:

66 Məhərrəmov Z. T., Vəliyev H.P.

Şəkil 2.11. Strukturun yaradılması

class Program

struct Adam{

public int yashi;public int boyu;

}

static void Main(string[] args){unsafe{Adam Rauf;Rauf.yashi = 35;Adam* p= &Rauf; // Struktura göstərici p->boyu = 180; // Strukturun sahəsinəgöstəriciConsole.WriteLine(p->boyu) ;

// Strukturun sahəsinə göstərici// belə də yaradıla bilər:(*p).boyu = 17 0;Console.WriteLine((*p).boyu);

Console.Read(); }1}p->boyu=180; göstəricisi ilə biz göstərici ilə

göstərilən strukturun sahəsinin qiymətini ya ala ya da ona

İkinci fəsil. Verilənlərin statik və dinanük strukturları 67

qiymət verə bilərik. Diqqət yetirin ki, biz p.boyu yaza bilmərik, çünki, p Adam strukturu deyil, struktura göstəricidir. Strukturun sahəsinə göstərici ilə müraciət üçün alternativ variant kimi ( *p) . boy'j=170; yaza bilərik.

2.9. Çoxluqlar

Massiv və yazılarla yanaşı verilənlərin daha bir strukturundan - çoxluqlardan istifadə edilir. Bu tip çox da geniş istifadə edilmir, ancaq bəzi hallarda onu tətbiq etmək lazım gəlir. Proqramlaşdırmada “çoxluq” tipi riyaziyyatdakı çoxluq anlayışına uyğun olaraq istifadə olunur. Çoxluq əvvəlcədən müəyyən edilmiş qiymətlərdən seçilmiş eyni tipli, lakin nizamlanmamış elementlər yığımıdır. Ona görə də çoxluqları təsvir etdikdə elementlərin tipi göstərilməlidir.

Çoxluqlar üzərində əməliyyatlar çoxluqlar nəzəriyyəsinin riyazi qaydalarına görə aparılır. Bu əməliyyatlar aşağıdakılardır:

• Çoxluqların birləşməsi;• Çoxluqların kəsişməsi;• Çoxluqların fərqi;• Alt çoxluğun yoxlanması və s.Proqramlaşdırma nöqteyi-nəzərindən çoxluqlar

üzərində bu əməliyyatlarla yanaşı çoxluğa elementin əlavə edilməsi, çoxluqdan mövcud elementin silinməsi, çoxluğa mənsub olmanın yoxlanması və s. əməliyyatlar yerinə yetirilə bilər.

C# dilində çoxluqlarla işləmək üçün iki sinif müəyyən edilmişdir:

• HashSet<T>;• Sor tedSet<T>.Bu siniflər System.Collections.Generic ad­

lar fəzasına daxildir və onların fərqi ondadır ki,

68 Məhərrəmov Z.T., Vəliyev H.P.

SortedSet<T> sinfi nizamlanmış çoxluq təqdim edir. Çoxluqlarla işləmək üçün metodlar cədvəl 2.4-də göstəril­mişdir.

Cədvəl 2.4. Çoxluqlarla işləmək üçün metodlarMetodun adı Metodun funksiyası

AddÇoxluğa elementin əlavə edilməsi; əgər çox­luqda belə element olarsa, o əlavə edilmə­yəcək

Remove Çoxluqdan elementin silinməsi

UnionWithÇoxluqların birləşməsi, yəni, ilkin çoxluq­ların bütün elementlərindən ibarət çoxluğun alınması; element hər iki çoxluqda mövcud olduqda o bir dəfə əlavə edilir

ExceptWi th Çoxluqların fərqi; bir çoxluqdan yalnız digər çoxluğa daxil olmayan elementləri seçir

IntersectWith İki çoxluğun kəsişməsi; hər iki çoxluqda olan eyni elementləri seçir

SubsetAlt çoxluğun yoxlanması; əgər A çoxluğu B çoxluğunun bütün elementlərini özündə saxlayırsa, onda A çoxluğu B çoxluğunun alt çoxluğu olur və metod true qiyməti qaytarır

SymmetricExce ptWith

Simmetrik fərq; eyni zamanda hər iki çoxluğa daxil olan elementləri seçir

C# dilində çoxluqlarla işlədikdə diqqət yetirmək lazımdır ki, çoxluqlarla yerinə yetirilən əməliyyatın nəticəsi müvafiq metodun çağırıldığı dəyişəndə yadda saxlanır. Başqa sözlə, dəyişənə əməliyyat tətbiq edildikdən sonra, həmin dəyişəndə ilkin çoxluq yox, əməliyyatın nəticəsi yadda saxlanacaq.

İndi isə C# dilində çoxluqların yaradılması və onlar üzərində icra ediləcək əməliyyatları kodlaşdıraq:

using System;using System.Collections.Generic; namespace CHOXLUQ i

İkinci fəsil. Verilənlərin statik və dinamik strukturları 69

class Program{static void Main(){// A və B çoxluqlarının yaradılması SortedSet<char> A=new SortedSet<char>(); SortedSet<char> B=new SortedSet<char>();

A.Add( ' A' ) ;A.Add('B');A.Add(' C ') ;A.Add( ' Z ' ) ;ChoxjGOSTER(A, "A choxlugu: ");

B.Add( ' X' ) ;B.Add('Y');B.Add( ' Z ' ) ;Chox_GOSTER(B, "Bi choxlugu:");

A.SymmetricExceptWith(B);Chox_GOSTER(A, "Her iki choxluga daxil

olan elementler: ");

A.UnionWith(B);Chox_GOSTER(A, "Choxluqlarin

birleshdirilmesi: ");

A.ExceptWith(B) ;Chox_GOSTER(A, "Choxluqlarin

chixilmasi:");

A.Add('G') ;Chox_GOSTER(A, "Choxluga G elementinin

elave edilmesi:");

A.Remove('A');Chox_GOSTER(A, "Choxluqdan A elementinin

silinmesi:");

70 Məhərrəmov Z.T., Vəliyev H.P.

Console.ReadLine(); }

static void Chox_GOSTER(SortedSet<char> ss, string s)

{Console.WriteLine(s) ;foreach (char ch in ss)

Console.Write(ch + " ");Console.WriteLine("\n") ;

} } )

Proqramın nəticəsi şəkil 2.12-də göstərilmişdir.

F:\ZAKIR\VSA\CHOXLI 1 Q\CHOXU JQ\b...

cboxlugu: B C Z

i choxluguV Z

er iki choxluga daxil olan elementler: B C X Y |

:hoxluqlarin birleshdirilmesi: B C X Y Z

Ihoxluqlarin chixilmasi: B C

lıoxluga G elementinin elaue edilmesi: B C G

ihoxluqdan A elementinin silinmesi: I C G

rrr r

Şəkil 2.12. Çoxluqlar üzərində əməliyyatlar

Bu proqramda SortedSet sinfinin A və B nüsxələri, yəni elementləri char (simvol) tip olan boş çoxluqlar yaradılır. Sonra Add metodu ilə hər iki çoxluğa elementlər

İkinci fəsil. Verilənlərin statik və dinamik strukturları 71

əlavə edilir. Çoxluqların məzmununu ekranda təsvir etdirmək üçün Chox_GOSTER metodu yaradılmışdır. Çoxluqlar üzərində əməliyyatlar yerinə yetirildikdən sonra bu metodla çoxluqlar ekranda təsvir edilir. Proqram kodundakı şərhlər və onlara uyğun nəticələr çoxluqlara tətbiq edilmiş metodların mahiyyətini başa düşməyə imkan verir.

2.10. Siyahılar

Verilənlərin strukturunun ən universal formalarından biri əlaqəli siyahılardır. Siyahı - dəyişən sayda elementlərdən ibarət nizamlanmış çoxluqdur. Elementlər arasında qonşuluq münasibətlərini təsvir edən siyahı xətti siyahı adlanır. Siyahının uzunluğu siyahının ibarət olduğu elementlərin sayına bərabərdir, sıfır uzunluqlu siyahı boş siyahı adlanır. Xətti əlaqəli siyahılar verilənlərin sadə dinamik strukturlarıdır.

Siyahılarda əlaqələri qrafik olaraq oxla göstərmək daha rahatdır. Əgər komponent heç bir digər komponentlə əlaqəli deyilsə, onda sahədə heç bir elementi göstərməyən qiymət yazılır. Eielə istinad null (nil) ilə və ya sadəcə olaraq 0 ilə işarə edilir.

Şəkil 2.13. Bir əlaqəli siyahıların strukturu

Əlaqəli siyahının elementi öz-özünü ünvanlaşdırmaq qabiliyyətinə malikdir, ona görə də o iki hissədən ibarətdir: informasiya (və ya verilən) və ünvan. Beləliklə, əlaqəli siyahılar əlaqəli qovşaqlar yığımından ibarətdir ki. onların hər biri məxsusi verilənlərdən və növbəti qovşağa istinaddan ibarətdir (şəkil 2.13). Həmin şəkildə Verilən - verilənlərin qiymətlərinin saxlandığı sahə. Ünvan isə siyahının növbəti

72 Məhərrəmov Z. T., Vəliyev H.P.

elementinə göstəricidir. Real həyatda əlaqəli siyahını qatar kimi təsəvvür etmək olar. Belə ki, hər bir vaqon yükdən və ya sərnişinlərdən ibarətdir və vaqonlar bir-biri ilə əlaqəlidir.

Təsəvvür edək ki, artma ardıcıllığı ilə nizamlanmış tam ədədlər verilmişdir: 10, 20, 30, 40, 50, 60. Bu verilənlər yığımı ilə əməliyyat apara bilən sistemin yaradılması məsələsi qoyulur. Əlbəttə, ilk baxışda ən sadə variant onları massiv kimi təsvir etməkdən ibarətdir:

int[] m = new int[6]{10,20,30,40,50,60};Lakin yuxarıda biz massivlərin emalında nə qədər

problemlərlə qarşılaşdığımızı müşahidə etdik. Ona görə də bu verilənləri xətti əlaqəli siyahı kimi təsvir etmək daha səmərəli olur (şəkil 2.14, a)), gələcək proqramlaşdırma məqsədi ilə verilənlər əks ardıcıllıqla göstərilmişdir). Siyahıdan elementin silinməsi və ya elementin əlavə edilməsi heç bir problem yaratmır (şəkil 2.14, ^).

Şəkil 2.14. Siyahının strukturu: a) - bir əlaqəli siyahı, b) - 30 elementinin silinməsi və 55 elementinin əlavə edilməsi

Massivlərdə elementin vəziyyəti indekslərlə müəyyən edildiyi və elementlərin sayı əvvəlcədən müəyyən olduğu halda, əlaqəli siyahılarda elementlərin sayı məlum olmur və onların yerləşmə qaydası göstərici ilə müəyyən edilir, yəni vacib deyil ki, bu elementlər ardıcıl qonşu xanalarda yerləşsin. Baxmayaraq ki, elementlər yaddaşın ən müxtəlif xanalarında yerləşir, göstərici onları əlaqələndirərək vahid bir strukturda birləşdirir. Siyahılarda elementlər eyni tipli olur. Hər bir siyahı siyahının başlanğıcı (yz ya başı) adlandırılan

İkinci fəsil. Verilənlərin statik və dinamik strukturları 73

elementə malik olmalıdır ki, o öz formatına görə digər elementlərdən fərqlənir. Sonuncu elementin istinad (göstə­rici) sahəsində siyahının sonunu bildirən null əlaməti yerlə­şir.

Siyahıdan elementin silinməsini ətraflı araşdıraq. Tutaq ki, şəkil 2.15 ü)-da göstərilmiş 4 elementdən ibarət siyahı verilmişdir və bu siyahıdan qiyməti 3 olan elementi silmək lazımdır. Bunun üçün siyahıda silinəcək element axtarılır və ona uyğun qovşaq silinir. Bu zaman əvvəlki elementin istinadı silinmiş elementdən sonrakı elementi göstərməlidir, yəni 2 qiymətli qovşaq silindikdən sonra, qovşağın istinad sahəsi 4 qiymətli qovşağı göstərəcək (şəkil 2.15, b)).

Şəkil 2.15. 3 elementinin siyahıdan silinməsi

Silmə əməliyyatında aşağıdakı hallar ola bilər ki, onları nəzərə alınaq lazımdır:

• siyahı boş ola bilər və ya silmək istədiyimiz element (hansıni ki metoda veririk) siyahıda olmaya bilər. Bu halda siyahı dəyişməyəcək;

• siyahı yalnız silmək istədiyimiz bir elementdən ibarət ola bilər. Bu halda siyahının baş və son əlamətlərinə null qiyməti veriləcək;

• silmək istədiyimiz element siyahının başlanğıcında ola bilər. Bu halda siyahının baş əlamətinə növbəti düyünə istinad yazılacaq;

• silmək istədiyimiz element siyahının ortasında ola bilər;

74 Məhərrəmov Z.T., Vəliyev H.P.

• silmək istədiyimiz element siyahının sonunda ola bilər. Bu halda siyahının sonu əlamətinə sonuncudan əvvəlki qovşağa istinad yazılır, onun özünün göstərici sahəsinə isə null yazılır.

Siyahının hər bir elementi bu elementi tanıyan açardan ibarətdir. Açar, adətən, ya tam ədəd, ya da sətir olmaqla siyahının hər bir elementində saxlanılan verilənin bir hissəsi olur. Siyahılarla iş prosesində verilənlərin müxtəlif hissələri açar rolunu oynaya bilər. Məsələn, sahələri soyad, təvəllüd, iş stajı və s. olan yazıdan siyahı yaradılırsa, onda yazının istənilən hissəsi açar kimi istifadə edilə bilər: siyahını əlifba sırası ilə nizamladıqda açar kimi soyad, axtarışda, məsələn, əmək veteranlarını axtardıqda isə iş stajı açar kimi istifadə edilə bilər. Siyahının müxtəlif elementlərinin açarları eyni ola bilər.

Siyahılar üzərində aşağıdakı əməliyyatlar yerinə yetirilə bilər:

• siyahının sonuna yeni elementin əlavə edilməsi;• açara uyğun elementin oxunması;• siyahının göstərilən yerinə elementin yerləşdirilməsi;• açarla göstərilən elementin silinməsi;• açara görə siyahının nizamlanması.

Siyahının elementlərinə sərbəst müdaxilə mümkün deyil. Ona görə də elementin oxunması, yerləşdirilməsi və silinməsi əməliyyatlarında verilmiş açara uyğun element tapılana qədər bütün elementlər ardıcıl olaraq araşdırılma­lıdır. Böyük həcmli siyahılarda elementlərin araşdırılması çox vaxt tələb edə bilər, çünki, elementin orta axtarış vaxtı siyahıda elementlərin sayına mütənasibdir.

Əlaqəli siyahının ən böyük üstünlüyü obyektlərin siyahıya əlavə edilməsi və siyahıdan silinməsi imkanının olmasından ibarətdir. Siyahının ortalarında dəyişikliklərin edilməsi çox sürətlə yerinə yetirilir. Xatırlayaq ki, dinamik massivlərin ortalarında hər hansı dəyişikliyin edilməsi

İkinci fəsil. Verilənlərin statik və dinamik strukturları 75

massivin bütün yerdə qalan elementlərinin yerdəyişməsini tələb edirdi. Siyahılarda isə yeni obyektin əlavə edilməsi və mövcud obyektin siyahıdan silinməsi digər elementlərin yerdəyişməsini tələb etmir, hər obyekt öz yerində qalır.

Yuxarıda şərh etdiyimiz üstünlüklərinə baxmayaraq, siyahıların da çatışmaz cəhətləri vardır. Massivləri bir daha xatırlayaq. Orada elementlər ardıcıl yaddaş xanalarında yerləşir. Massivin 500-cü elementinə müraciət etmək üçün sadəcə olaraq “500 yer’ qabağa baxmaq lazımdır. Əlaqəli siyahıda yaddaş zəncirvari əlaqələnmişdir. Əgər bizə 500-cü element lazımdırsa, onda zəncirin ucundan başlayaraq onun göstəricisi vasitəsi ilə növbəti elementə, sonra yenidən növbəti elementə və s. keçməklə bu əməliyyatı 500 dəfə təkrar etmək lazım gələcəkdir. Əlaqəli siyahının ixtiyari elementinə müraciət ləng yerinə yetirilir.

Siyahının digər ciddi çatışmazlığı aşkar şəkildə özünü büruzə vermir. Hər qovşağın yadda saxlanması üçün böyük olmayan əlavə yaddaş tələb olunur. Bəs bu yaddaş nə qədər olmalıdır? Fikirləşmək olar ki. onun üçün yalnız göstəricinin ölçüsü kifayətdir, lakin bu belə deyildir. Obyektin dinamik yaradılması prosesində həmişə kiçik həcmli yaddaş ehtiyatı mövcud olur. Bəzi proqramlaşdırma dilləri, məsələn, C++ dili yaddaş səhifələri ilə işləyir. Adətən, səhifə 4 kilobaytdan ibarət olur. Əlavəetmə və silmə operatorlarını istifadə etdikdə bütöv bir səhifə yaddaş yerləşir, baxmayaraq ki, bizə bir bayt kifayət edə bilər.

Java və C# dillərində bu bir az fərqlidir, belə ki, bu dillərdə böyük obyektlərlə işləmək üçün xüsusi qaydalar mövcuddur. Bu dillər üçün bütöv 4 kilobaytlıq səhifə lazım deyil, lakin hər halda, yenə də onların çox da böyük olmayan ehtiyatı vardır. Standart kitabxanalardan istifadə etdikdə ikinci çatışmazlıq barədə narahat olmağa dəyməz, çünki, onlar elə yazılmışdır ki, boş-boşuna tutulan yerlər min imallaşdırı I ır.

76 Məhərrəmov Z.T., Vəliyev H.P.

2.10.1. Bir əlaqəli siyahılar və onların kompüterdə reallaşdırılması

Əgər element yalnız növbəti elementlə əlaqəlidirsə, belə siyahı bir əlaqəli və ya bir istiqamətli, əgər element həm növbəti, həm də əvvəlki elementlə əlaqəlidirsə, belə siyahı iki əlaqəli və ya iki istiqamətli adlanır (şəkil 2.16).

Şəkil 2.16. İki əlaqəli və ya iki istiqamətli siyahı

İndi isə əlaqəli siyahının proqramlaşdırılması ilə məşğul olaq. C# dilində siyahılarla işləmək üçün xüsusi siniflər mövcuddur. Siyahının yaradılmasında biz, hələlik, belə siniflərdən istifadə etməyəcəyik. Aşağıdakı kodla siyahının elementləri SİYAHI adlandırılmış siniflə müəyyən edilir. Siyahının elementləri dinamik olaraq yaradılacaq (klaviaturadan daxil etməklə). Sıfrıncı ünvan siyahının sonu əlamətini bildirəcəkdir. Verilənlər sinfin info sahəsinə yazılacaq, link isə növbəti ünvanlara istinaddır. Proqramın kodu belədir:

using System;namespace ELAQE_SIYAHI1class SİYAHI{static SİYAHI top = null;int info;SİYAHI link;public SİYAHI(int i){info = i;if (top == null) link = null;

İkinci fəsil. Verilənlərin statik və dinamik strukturları ~~

else link = top;top = this;

}static public void Type () {SİYAHI p;for (p = top; p != null; p = p.link) Console.Write("{0} ",p.info);

} 1 static void Main {string s;int i;for (; ; )

s = Console.ReadLine();i = Convert.Tolnt32(s);if (i != 0) new SİYAHI(i); else break;

}SİYAHI.Type();Console.ReadLine();

} } }

Proqramın nəticəsi şəkil 2.17-də göstərilmişdir.

Şəkil 2.17. Elementləri klaviaturadan daxil etməklə siyahının yaradılması

78 Məhərrəmov Z.T., Vəliyev H.P,

Qeyd edək ki, parametrləri olmayan for dövrü təşkil edilmişdir. Ona görə də proqramın işini yekunlaşdırmaq üçün siyahının elementlərini daxil etdikdən sonra 0 rəqəmi daxil edilməlidir.

Qeyd etdiyimiz kimi, C# dilində siyahılarla işləmək üçün xüsusi siniflər mövcuddur ki, onların içərisində ən geniş yayılmışı List<T> sinfidir, burada, T-elementlərin tipidir. List<T> sinfinin əsas metodları cədvəl 2.5-də göstəril­mişdir.

List<T> sinfinin köməyi ilə siyahı yaradaq:

Cədvə 2.5. List<T> sinfinin metodlarıMetodun adı Metodun funksiyası

Add Siyahının sonuna yeni element əlavə edir

Insert Göstərilmiş elementi (qiyməti) göstərilən indeks­dən sonra siyahıya əlavə edir

Remove Qiyməti ilə göstərilən elementi silirRemoveAt İndeksi ilə göstərilən elementi silirClear Siyahının bütün elementlərini silirCopyTo Siyahının elementlərini massivə köçürürSort Siyahının elementlərini nizamlayır

using System;using System.Collections.Generic;namespace ELAQE1LIST{class Program {static void Main(string[] args){List<int> siyahi = new List<int>()

{ 1, 5, -90, -40, 42, -69 };

// Elementlər əlavə edirik siyahi.Add(5000);siyahi.Insert(4, 6000) ;

İkinci fəsil. Verilənlərin statik və dinamik strukturları 79

// Siyahının elementlərini //ekrana çıxarırıqConsole.WriteLine("Siyahinin

elementleri:");foreach (int item in siyahi){Console.WriteLine(item);

)Console.WriteLine();

//Siyahının elementlərini massivə //köçürürük və ekrana çıxarırıq

int[] a = new int[siyahi.Count];siyahi.CopyTo (a);Console.WriteLine("\nMassivin

elementleri:");foreach (int item in a) {Console.Write(item+" \t");

]

//Siyahının mənfi elementlərini// silirikfor (int i=siyahi.Count-1; i>=0; i--) {

if (siyahi[i] < 0) siyahi.Remove(siyahi[ i ] ) ;

}Console.WriteLine();

// Elementi silirik siyahi.Remove(5000) ;

// Elementləri dəyişdirilmiş //siyahını ekrana çıxarırıq Console.WriteLine("\nElementleri

deyişdirilmiş siyahi:");foreach (var item in siyahi)

80 Məhərrəmov Z.T., Vəliyev H.P.

Console.WriteLine(item);}Console.ReadLine();

} } }

Bu proqramda tam ədədlərdən ibarət siyahi adlı siyahı yaradılmış və dərhal inisiallaşdırılmışdır:

List<int> siyahi = new List<int>(){ 1, 5, -90, -40, 42, -69 };

Sonra siyahının sonuna - 5000, 5-ci mövqeyə isə 6000 ədədləri əlavə edilmişdir:

siyahi.Add(5 000) ;siyahi.Insert(4,6000);Proqramda CopyTo metodu ilə siyahıdan massivin

yaradılması qaydası da nümayiş etdirilmişdir.Siyahının elementlərinin sayını Count xassəsi

müəyyən edir. Siyahıdan mənfi elementləri pozmaq üçün elementlərin sayının azalması istiqamətində dövr qurulmuş və Remove metodu ilə elementlər silinmişdir. Göründüyü kimi, siyahının hər bir elementinə onun indeksi vasitəsi ilə müraciət etmək olar (siyahi . Remove ( siyahi [i ] ) ;).

Proqramın nəticəsi şəkil 2.18-də göstərilmişdir.

Şəkil 2.18. Siyahının elementləri üzərində əməliyyatlar

İkinci fəsil. Verilənlərin statik və dinamik strukturları 81

Qeyd edək ki, indiyədək baxdığımız tiplər içərisində massiv, dinamik massiv və əlaqəli siyahı tipləri verilənlərin strukturunun əsasını təşkil edir. Proqramlaşdırmada bu strukturlar fundamental hesab olunur. Hansı proqramlaşdırma dilinin istifadə edilməsindən asılı olmayaraq, bu strukturları bilmək lazımdır.

2.10.2. İki əlaqəli siyahılar və onların kompüterdə reallaşdırılması

İki əlaqəli siyahı hər bir elementdə iki göstəricinin olması ilə xarakterizə olunur. Onlardan biri əvvəlki, digəri isə növbəti elementə istinadı göstərir. Belə siyahılarda iki istiqamət üzrə keçid mümkündür: irəli və geri. İki əlaqəli siyahını qrafik təsvirini yuxarıda göstərmişik (şəkil 2.16), ona analoji sxem isə şəkil 2.19-da göstərilmişdir.

Şəkil 2.19. İki əlaqəli siyahı

Siyahıya yeni element əlavə etdikdə və ya siyahıdan elementi sildikdə elementdə yalnız istinad dəyişir. Şəkil 2.20-də yeni elementin əlavə edilməsi sxemi göstərilmişdir.

Şəkil 2.20. İki əlaqəli siyahıya yeni 5 elementinin əlavə edilməsi

82 Məhərrəmov Z. T., Vəliyev H.P.

C# dilində iki əlaqəli siyahdarla işləmək üçün xüsusi LinkedList<T> sinfi nəzərdə tutulmuşdur, burada T - elementin tipidir. Bu sinif siyahılar elementlərin yerini dəyişdirmədən yeni elementin əlavə edilməsinə və ya siyahıdan istənilən elementin silinməsinə imkan verir. LinkedList<T> sinfi ICollection və ICollection<T> interfeyslərini reallaşdırır. İki əlaqəli siyahının hər elementi LinkedListNode<T> obyekti ilə təsvir edilmişdir. LinkedList<T> sinfinin aşağıdakı xassələri var:

• Value - elementin T tipi ilə təsvir edilmiş qiymətidir;

• Next - siyahının növbəti elementinə istinaddır; əgər element yoxdursa, onun qiyməti null olur;

• Previous - siyahının əvvəlki elementinə istinaddır; əgər element yoxdursa, onun qiyməti null olur.

LinkedList<T> sinfinin siyahının elementləri üzərində əməliyyatlar aparmağa imkan verən bəzi metodları və onların funksiyaları cədvəl 2.6-da göstərilmişdir. Bu metodların hər birinin bir neçə yenidən yüklənmə metodları vardır.

C# dilində iki əlaqəli siyahının yaradılması ilə məşğul olaq. Əvvəlcə yuxarıda verilmiş massiv əsasında siyahının yaradılmasını öyrənək. Belə siyahı aşağıdakı kodla yaradılır:

using System;using System.Collections.Generic;

namespace ElSIMas {class Program1

İkinci fəsil. Verilənlərin statik və dinamik strukturları 83

Cədvəl 2.6. LinkedList<T> sinfinin metodlarıMetodun adı Metodun funksiyası

First LinkedListcO siyahısının birinci elementini müəyyən edir

Last LınkedList<T> siyahısının sonuncu elementini müəyyən edir

AddAfterLinkedList<T> siyahısının göstərilmiş mövcud qovşağından sonra göstərilən yeni qovşağı əlavə edir

AddBeforeLinkedList<T> siyahısının göstərilmiş mövcud qovşağından əvvələ göstərilən yeni qovşağı əlavə edir

AddFirstLinkedList<T> siyahısının başlanğıcına yeni qiymətdən ibarət qovşaq əlavə edir

AddLastLinkedList<T> siyahısının sonuna yeni qiymətdən ibarət qovşaq əlavə edir

RemoveFirstLinkedList<T> siyahısının başlanğıcından qovşağı silir. Bundan sonra növbəti qovşaq birinci olur

RemoveLas tLinkedList<T> siyahısının sonundan qovşağı silir

RemoveLinkedI.ist<T> siyahısından cari qovşağı silir

static void Main(string[] args)

int[] m=new int[6] (10,20,30,40,50,60);LinkedList<int> SIYAHI2 = new

LinkedList<int>(m);LinkedListNode<int> indeks;

SIYAHI2.AddAfter(SIYAHI2.First, 5);Console.WriteLine("AddAfter

emeliyyatindan sonra:");for (indeks = SIYAHI2.First; indeks !=

null; indeks = indeks.Next)Console.Write(indeks.Value + "\t");

SIYAHI2.AddBefore(SIYAHI2.Last, 5);

84 Məhərrəmov Z. T., Vəliyev H.P.

Console.WriteLine("\n\nAddBefore emeliyyatindan sonra:");

for (indeks = SIYAHI2.First; indeks != null; indeks = indeks.Next)

Console.Write(indeks.Value + "\t");

SIYAHI2.AddFirst(5);Console.WriteLine("\n\nAddFirst

emeliyyatindan sonra:");for (indeks = SIYAHI2.First; indeks !=

null; indeks = indeks.Next) Console.Write(indeks.Value + ”\t");

SİYAH 12 .AddLast (,5) ;Console.WriteLine("\n\nAddLast

emeliyyatindan sonra:");for (indeks = SIYAHI2.First; indeks !=

null; indeks = indeks.Next) Console.Write(indeks.Value + "\t");

SIYAHI2.RemoveFirst() ;Console.WriteLine("\n\nRemoveFirst

emeliyyatindan sonra:");for (indeks = SIYAHI2.First; indeks !=

null; indeks = indeks.Next) Console.Write(indeks.Value + "\t");

SIYAHI2.RemoveLast() ;Console.WriteLine("\n\nRemoveLast

emeliyyatindan sonra:");for (indeks = SIYAHI2.First; indeks !=

null; indeks = indeks.Next) Console.Write(indeks.Value + "\t");

Console.ReadLine() ;} 1 )

Koddan göründüyü kimi, əvvəlcə massiv yaradılmış və inisializasiya edilmişdir. Sonra həmin massiv əsasında

ikinci fəsil. Verilənlərin statik və dinamik strukturları 85

SIYAHI2 adlı iki əlaqəli siyahı yaradılmışdır. LinkedListNode<int> indeks; kodu ilə indeks adlı istinad təyin edilmişdir. Sonrakı kodla siyahının elementlərinə cədvəl 2.6-da göstərilmiş əməliyyatlar tətbiq edilmiş və həmin əməliyyatların hər birindən sonra siyahıda edilmiş dəyişiklikləri müşahidə etmək üçün onlar ekranda təsvir edilmişdir. Proqramın nəticəsi şəkil 2.21-də göstəril­mişdir.

Şəkil 2.21. İki əlaqəli siyahının elementləri üzərində əməliyyatların nəticələri

Massivlər əsasında siyahı daha tez yaradılır. Lakin siyahını birbaşa siyahı kimi yaratmaq daha maraqlıdır, bu halda siyahı əsil dinamiklik əldə edir. İkinci misal kimi, universitetlərin adlarından ibarət iki əlaqəli siyahı yaradıb, onun elementləri üzərində əməliyyatlar aparaq. Aşağıda müvafiq kod yazılmışdır (proqram mətnində yazılmış şərhlər və proqramın nəticəsi kodu tam başa düşməyə imkan verir):

using System;using System.Collections.Generic;

namespace ELAQE_SIYAHI2(class Program {

86 Məhərrəmov Z.T.^ Vəliyev H.P.

static void Main(string [ ] args) {// Əlaqəli siyahı yaradırıq:LinkedList<string> S2Elaqe = new

LinkedList<string>();

// Bir neçə element əlavə edirik:S2Elaqe.AddFirst("AzTU"); // siyahının // əvvəlinə AzTU elementini əlavə edir

S2Elaqe.AddFirst("BDU"); // siyahının// əvvəlinə BDU elementini əlavə edir

S2Elaqe.AddFirst("ADNSU");// siyahının // əvvəlinə ADNSU elementini əlavə edir

S2Elaqe.AddFirst("ADPU"); // siyahının // əvvəlinə ADPU elementini əlavə edir

LinkedListNode<string> node; // node // adlı göstərici

// elementləri düz istiqamətdə// ekranda təsvir edirikfor (node = S2Elaqe.First; node !=

null; node = node.Next) Console.Write(node.Value + "\t");

// elementləri əks istiqamətdə// ekranda təsvir edirikConsole.WriteLine("\n\nEks istiqametde

elementler: ");for (node = S2Elaqe.Last; node !=

null; node = node.Previous) Console.Write(node.Value + "\t");

// elementləri dəyişdiririkS2Elaqe.Remove("ADNSU"); // ADNSU

// elementini silir

İkinci fəsil. Verilənlərin statik və dinamik strukturları 87

S2Elaqe.AddFirst("ATU"); // siyahının// əvvəlinə ATU elementini əlavə edir

S2Elaqe.AddLast("ADPU"); // siyahının// sonuna ADPU elementini əlavə edir

S2Elaqe.AddLast("AzMİU"); // siyahının // sonuna AzMİU elementini əlavə edir

Console.WriteLine("\n\nElementler deyişdikden sonra:");

for (node = S2Elaqe.First; node != null; node = node.Next)

Console.Write(node.Value + "\t");

// siyahının başlanğıcına və// sonuna yeni elementlər əlavə edirikS2Elaqe.AddAfter(S2Elaqe.Last, "TEHSIL

NAZİRLİYİ");S2Elaqe.AddBefore(S2Elaqe.First, "TEHSIL

NAZİRLİYİ");Console.WriteLine("\n\nSiyahinin evveline ve sonuna TEHSIL NAZİRLİYİ

elave edilir:");for (node = S2Elaqe.First; node !=

null; node = node.Next) Console.WriteLine(node.Value);

S2Elaqe.Clear();S2Elaqe.AddFirst("AzTU"); // siyahının // əvvəlinə AzTU elementini əlavə edir

Console.WriteLine("\n\nElementler silindikden sonra:");

for (node = S2Elaqe.First; node != null; node = node.Next)

Console.Write(node.Value + "\t");Console.ReadLine() ;} } }

88 Məhərrəmov Z.T.y Vəliyev H.P.

Proqramda siyahı üzərində müxtəlif əməliyyatlar aparıldıqdan sonra onun elementləri Clear () metodu ilə silinmişdir. Clear () metodu siyahının baş və son istinad­larını null qiymətinə bərabərləşdirir. C# dili yaddaşı avtomatik idarə etdiyi üçün bütün qovşaqları aşkar şəkildə silməyə ehtiyac yoxdur. Elementlər silindikdən sonra siyahıya yalnız bir element (AzTU) daxil edilmişdir. Bax, bütün bunlar siyahının strukturunun çevikliyi hesabına mümkün ola bilir!

Proqramın nəticəsi şəkil 2.22-də göstərilmişdir.

'■] F:\ZAiaPAVSA\F.LAQF_SJVAh4I2\FI AQFJTYAWT7\hin\r>Phug\n AQF SIY...

RVrD ÄWW WU AzTU

Eks İstiqanetde elenentler:IzTU BDU ADNSU ADPU

jlenentler deyisdikden sonra:ITU ADPU BDU AzTU ADPU AzMIU

iuahinin evueline ve sonuna TEHSIL NAZİRLİYİ elave edilir: IHSIL NAZİRLİYİ U

IPU>U:TUIPUUIU■sil nazirliyi

Elenentler sllindikden sonra: AzTU

eaŞəkil 2.22. Elementləri sətirlərdən ibarət olan iki əlaqəli

siyahı üzərində əməliyyatların nəticələri

Elementləri tam ədədlər olan yeni iki əlaqəli siyahı yaradaq və bu ədədlərin ədədi orta qiymətini hesablayaq. Bu proqramın mətni belədir:

using System;

İkinci fəsil. Verilənlərin statik və dinamik strukturları 89

using System.Collections.Generic;namespace EDEDI_SIYAHI <class Program{static void Main(string[] args){// Əlaqəli siyahı yaradırıq:LinkedList<int> Eded = new

LinkedList<int>(); LinkedListNode<int> node;

// siyahını elementlərlə doldururuq:for (int i=10; i<=60; i+=10)Eded.AddFirst(i);// i-nin qiymətlərini

// siyahının əvvəlinə əlavə edir

// elementləri ekranda təsvir edirik: for (node = Eded.First; node !=

null; node = node.Next)Console.Write(node.Value + "\t");

// siyahının elementlərini cəmləyib,// orta qiyməti hesablayırıq:int sum = 0;for (node = Eded.First; node !=

null; node = node.Next) sum += node.Value;

int orta=sum/Eded.Count;Console.WriteLine("\nEdedi orta = "

+ orta);

// siyahının cari elementini// təyin edirik:LinkedListNode<int> cari =

Eded.FindLast(40);Eded.AddBefore(cari, 200); // 40// qiymətindən əvvələ 200 qiyməti// əlavə edirik

22___________________ Məhərrəmov Z. T., Vəliyev H. P.

Eded.AddAfter(cari, 400); // 40// qiymətindən sonraya 400 qiyməti// əlavə edirik

Console.WriteLine("\nYeni elave edilmiş qiymetlerden sonra alinmiş

yeni siyahi: ") ;for (node = Eded.First; node !=

null; node = node.Next) Console.Write(node.Value + "\t");

// siyahıdan 400 qiymətinin silinməsi:if (Eded.Contains(400))

Eded.Remove(400);Console.WriteLine("\n\nSiyahidan 400

qiymeti pozulduqdan sonra alinmiş yeni siyahi:");

for (node = Eded.First; node != null; node = node.Next)

Console.Write(node.Value + "\t");Console.ReadLine();) ) )

Proqramdakı bəzi kodları izah edək. LinkedList<int>Eded=new inkedList<int>() ; kodu ilə Eded adlı tamədədli siyahı yaradılır, sonra isə dövr təşkil edilərək 10,20,..., 60 ədədləri daxil edilir. Ədədlər hər dəfə siyahının əvvəlinə əlavə edildiyinə görə, onlar siyahıda azalma sırası ilə yerləşir (bu prinsipial əhəmiyyət kəsb etmir, dövrdə indeksin dəyişmə ardıcıllığını dəyişməklə bu ədədləri artma sırası ilə daxil edə bilərik). Ədədi orta qiyməti hesabladıqda siyahının elementlərinin sayım Eded . Count metodu ilə alırıq.

Əslində bizim məqsədimiz burada başa çatır. Lakin siyahının cari mövqeyini tapmaq, həmin elementdən əvvələ və sona yeni qiymət əlavə etmək və ya siyahıdan mövcud elementi silmək kimi əməliyyatların icra edilməsi qaydalarını

İkinci fəsil. Verilənlərin statik və dinamik strukturları 91

öyrənmək üçün əlavə kod yazılmışdır. Göstərilən mövqedən əvvələ və sona yeni qiymət əlavə etmək üçün bizə məhz həmin mövqeni göstərmək lazımdır. Bu məqsədlə cari adlı yeni dəyişən yaradılmış və ona siyahının konkret qiyməti mənimsədilmişdir: LinkedListNode<int> cari = Eded. FindLast ( 4 0 ) ; Sonra isə AddBefore və AddAfter metodları ilə həmin təyin edilmiş mövqenin, müvafiq olaraq, əvvəlinə və sonuna yeni qiymətlər (konkret olaraq 2 00 və 4 00) əlavə edilmişdir. Siyahıdan 400 qiymətini silmək üçün Contains metodu tətbiq edilmişdir. Bu metod siyahının hər bir elementinə baxır və arqumentində göstərilən qiyməti tapdıqda true qiyməti qaytarır. Remove metodu isə həmin qiyməti siyahıdan silir.

Proqramın nəticəsi şəkil 2.23-də göstərilmişdir.

F:\ZAKIR\VSA\SIYAHI_EDED\SIYAHI_EDED\bin\Debug\SIYAHl_EDED.exe

050403020İDidedi orta= 35'eni elaue edilmiş qiynetlerden sonra alinmis yeni siyahi:D 50 200 40 400 - ^30 20 10liyahidan 400 qiymeti pozulduqdan sonra alinmis yeni siyahi: .0 50 200 40 30 20 10

Şəkil 2.23. Elementləri tam ədədlər olan iki əlaqəli siyahı üzərində əməliyyatların nəticələri

LinkedList<T> sinfinə yekun vuraraq sonda qeyd edək ki, belə siyahıda istənilən obyekti, o cümlədən, null və təkrarlanan obyektləri saxlamaq olar. 0(1) sabit vaxtı ərzində siyahının başlanğıcından və sonundan elementi silmək və ya əlavə etmək olar. Siyahıda elementin axtarılması isə 0(?ı) qədər vaxt tələb edir.

92 Məhərrəmov Z.T., Vəliyev H.P.

2.10.3. Halqavari siyahılar və onların kompüterdə reallaşdırılması

Xətti siyahıların digər növü dövrü və ya halqavari siyahılardır. Əgər sonuncu element göstərici vasitəsi ilə birinci elementlə əlaqələndirilərsə, belə siyahıya dövrü və ya halqavari siyahı deyilir. Belə siyahılar həm bir istiqamətli, həm də iki istiqamətli siyahılardan təşkil edilə bilər. Siyahıda elementlərin sayı proqramın iş prosesində dəyişə bilər.

Şəkil 2.24-də halqavari bir istiqamətli siyahının sxemi göstərilmişdir, şəkil 2.25-də isə belə siyahıya yeni elementin əlavə edilməsi nümayiş etdirilmişdir. Halqavari bir istiqamətli siyahının fərqli cəhəti ondan ibarətdir ki, sonuncu elementdə siyahının birinci elementinə istinad edilir.

Şəkil 2.24. Halqavari bir istiqamətli siyahı

Şəkil 2.25. Halqavari bir istiqamətli siyahıya yeni 5 elementinin əlavə edilməsi

Halqavari iki istiqamətli siyahılarda isə göstəricilər yenidən müəyyən edilir, belə ki, sonuncu elementdə siyahının birinci elementinə, birinci elementdə isə siyahının sonuncu elementinə istinad edilir (şəkil 2.26).

İkinci fəsiL Verilənlərin statik vg dinamik strukturları 93

Şəkil 2.26. Halqavari iki istiqamətli siyahılarda göstəri­cilərin müəyyən edilməsi (prev - əvvəlki, next isə

növbəti elementə istinaddır)

Halqavari siyahılarla işlədikdə bir sıra prosedurlar sadələşir Bununla yanaşı, belə siyahılarda sonsuz dövretmə təhlükəsi mümkündür, bunun qarşısını almaq üçün müəyyən tədbirlər görülməlidir.

Aşağıdakı proqram kodu ilə halqavari bir istiqamətli siyahı yaradılmışdır:

using System;namespace Circular Item {class Program {class ListElem // siyahı elementi sinfi {public int Value; // verilənlər sahəsi public ListElem Next; // növbəti

// elementə keçici sahəsi

// sinfin konstruktoru: public ListElem(ListElem next,

int value){Next next; // sahənin doldurulmasıValue = value; // sahənin doldurulması

class List // siyahılar sinfi

94 Mthtrrzmov £!., Vəliyev H.P.

{ int value, count = 0;

// siyahının başı:Public ListElem head = null;

// siyahının cari elementi:Public ListElem current = null;Public List() { } // boş konstruktor

// siyahının başlanğıcına// elementin yerləşdirilməsi:Public void Menu() {Console.Clear();Console.WriteLine("ESAS NENYUConsole.WriteLine(" 1. Siyahini

doldurmaq.");Console.WriteLine(" 2. Siyahiya

baxmaq.");Console.WriteLine (" 3. Elementi

silmek,");Console.WriteLine(" 4. Siyahini

temizlemek.");Console.WriteLine(" 5. Çixiş.\n");Console.WriteLine("LAZİM OLAN MENYU

BENDİNİ SEÇİN! \n"); }

// Siyahının başlanğıcına elementin // yerləşdirilməsi:Public void FirstElem() {//Console.Clear();

int n = 10;Console.WriteLine(n + " element

daxil edin:");for (int i = 0; i < n; i++)

-kincıfasil. Verilənlərin statik və dinamik strukturları 95

{ value = int.Parse(

Console.ReadLine() ) ;

//siyahının yeni elementinin yaradılması //və onun qiymətlərlə doldurulması: ListElem temp = new LıstElem(null,

value);if (head == null) // əgər siyahı

// boşdursahead = temp; // yeni element birinci

// element olurelse

{// yeni elementə birinci //elementə istinadın əlavə edilməsi temp.Next = head;head = temp; // birinci elementin

// yenidən yazılması head = temp; // birinci elementin

// yenidən yazılması}

) current = head; while (current.Next != null)

current = current.Next;current.Next = head; count += 10;}

// Siyahıya baxış metodu: public void Show() ( //Console.Clear() ;Console.Write("Halqa şekilli bir

ıstiqametlı siyahi:\n");if (count == 0) // əgər siyahı boşdursaConsole.WriteLine("Siyahi boşdur!") ;

else

96 Məhərrəmov Z.T., Vəliyev H.P.

{int counterl = 0;// yeni elementin yaradılması və//ona birinci elementin yazılması

ListElem temp = head;while (counterl < count) // siyahının

//sonuna kimi dövr(

// cari qiymətin ekrana çıxarılması Console.Write(temp.Value + " "); temp = temp.Next; // növbəti

// elementə keçid counterl++;

}Console.WriteLine("");} }

// cari elementdən sağa yerləşdirmə: public void Right_Element() {// Console.Clear();if (head == null){Console.WriteLine("Siyahini

doldurun!");)else(int m = count;current = head;for (int i = 1; i < m; i++) current = current.Next; // növbəti

// elementə keçidConsole.WriteLine("Ededi daxil

edin: " ) ;value = int.Parse(Console.ReadLine()) ;ListElem temp = new ListElem(null,

value);temp.Next = current.Next;

İkinci fssil. Verilənlərin statik və dinamik strukturları 97

current.Next = temp;current = temp;count++;}

}

// elementin silinməsi:public void Delete_Elements() {// Console.Clear();if (head != null){Show();ListElem temp = head;ListElem prev = head;int i = 1;Console.WriteLine("Siyahida mövqeni

daxil edin:\n ");int pos = int.Parse

(Console.ReadLine());whıle (pos != i){prev = temp;temp = temp.Next;i + + ;

}if (head == temp)

head = head.Next;elseprev.Next = temp.Next;

count--;

elseConsole.WriteLine("Siyahi onsuz da

boşdur! Neyi sileceksiniz?");

// siyahını təmizləmə metodu: public void Clear_list()

98 Məhərrəmov Z.T., Vəliyev H.P.

{ListElem while (i /

temp; int i = 0; < count)

ıtemp = head =

head.Next; temp;

count — ) )

static void Main(string[] args) {List List = new List();List.Menu();int c = int.Parse(Console.ReadLine()); while (c != 5) { switch (c) {//siyahını doldurmaq:

case 1: List.FirstElem(); break;//siyahıya baxmaq:

case 2: List.Show(); break;//elementi silmək:case 3: List.Delete_Elements(); break; //siyahını təmizləmək:case 4: List.Clear_list(); break;//çıxış :case 5: break;default: Console.Write("Bele nomreli

menyu bendi yoxdur!"); break; )do Console.Write("\nDavam etmek uçun

ENTER klavişini basin...");while (Console.ReadKey().Key !=

ConsoleKey.Enter) ;List.Menu();c = int. Parse (Console.ReadLine()) ;> } } }

ikinci fəsil. Verilənlərin statik və dinamik strukturları 99

Proqram icra olunduqda ekranda 5 bənddən ibarət menyu peyda olur (şəkil 2.27). 1 rəqəmini daxil etdikdə siyahıya 10 ixtiyari tam ədədin daxil edilməsinə icazə verilir. 2 rəqəmini daxil etməklə siyahının məzmununa baxmaq olar. Siyahıdan hər hansı elementi silmək üçün 3 rəqəmi daxil edilməlidir. Bu zaman hansı elementin silinməsinin daxil edilməsi tələb olunacaq. Silinəcək elementin sıra nömrəsini (nömrə 1-dən başlayır) daxil etmək lazımdır. Elementin silinməsinə əmin olmaq üçün 2 rəqəmini daxil edərək siyahıya yenidən baxmaq olar. 4 rəqəmini daxil etdikdə siyahının bütün elementləri silinir.

F:\7A KTR\VSA\Circı Jİa rXC'ino ıla r\hin\Debug\C.„

BSAS NZNYU:1. Siyahini2. Siyahiya3. Elementi4. Siyahini 5. Cixis.

doIdurmaq. baxmaq. silmek. temizlemek.

LAZIM OLAN MENYU BENDINI SEGIN?

2Halqa sekilli bir istiqametli siyahi: tOO 90 80 70 60 50 40 30 20 10

auam etmek ucun ENTER klavisini basin..._

Şəkil 2.27. Halqavari bir istiqamətli siyahının elementləri üzərində əməliyyatların nəticələri

Daha bir siyahı növünü xatırlatmaqla siyahı bölməsinə yekun vuraq.

Bəzən elə vəziyyət yaranır ki, bir neçə müxtəlif siyahı mövcud olur və onların tərkibinə eyni elementlər daxil olur. Bu halda, ənənəvi siyahılardan istifadə etdikdə, dinamik dəyişənlərin dəfələrlə təkrarlanması və yaddaşın irrasional

100 Məhərrəmov Z. T., Vəliyev H.P.

istifadəsi baş verir. Siyahılar faktiki olaraq verilənlər elementlərinin saxlanılması üçün yox, onların müxtəlif strukturlarda təşkili üçün istifadə olunur. Multi (çox əlaqəli) siyahılardan istifadə etdikdə bu məsələ asanlaşır.

Multi siyahı o qədər göstəricilərdən ibarət olur ki, bu göstəricilər onları eyni zamanda bir neçə müxtəlif siyahılar şəklində təşkil etməyə imkan verir. Verilənlərin təkrarlanması hesabına yaddaş daha səmərəli istifadə olunur.

Yaddaşa qənaət multi siyahıları tətbiq edilməsinin yeganə səbəbi deyil. Verilənlərin bir sıra real strukturları tipik strukturlara gətirilə bilmir, onların bəzi kombinasiyasından ibarət olur. Həm də multi siyahılarda ən müxtəlif siyahılar - xətti və halqavari, bir əlaqəli və iki əlaqəli - birləşir.

Multi siyahılara verilənlərin strukturunun daha bir növü olan lüğəti də aid etmək olar.

2.11. Stek və onun kompüterdə reallaşdırılması

Stek elə dəyişən uzunluqlu ardıcıl siyahıdır ki, buraya elementlərin daxil edilməsi və ya çıxarılması yalnız siyahının başi (təpəsi) adlanan bir tərəfindən mümkün olur. Stekin başqa adları da mövcuddur: maqazin və LIFO prinsipi ilə fəaliyyət göstərən növbə. LIFO abreviaturasmın açılışı belədir: Last-In-First Out - "sonuncu gələn birinci çıxır". Stekin iş mexanizmini əyani izah etmək üçün Niderlyandiyalı alim Deykstra tərəfindən dəmir yolu yolayrıcısı ilə analogiya təklif edilmişdi (şəkil 2.28). Belə dəmir yolu yolayrıcısının bir tərəfi dalandan ibarət olur, digər tərəfindən isə vaqonlar daxil olur və çıxır. Stekə başqa misallar da göstərmək olar: odlu silahın patron darağı - patronlar yuxarıdan aşağı yerləşdirilir, ancaq yalnız yuxarıda dayanan istifadə edilir, kitab qalaqları və s. Beləliklə, stekdə həqiqətən də "sonuncu gələn birinci çıxır" prinsipi reallaşır.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 101

Stekdətı çıxış Stek.? giriş

Şəkil 2.28. Stekin Deykstra təsviri

İndi, stekin iş prinsipini başa düşdükdən sonra, onunla işləyə bilməyimiz üçün əsas anlayışlarla tanış olaq.

Stek üzərində aparılan əsas əməliyyatlar yeni elementin əlavə edilməsi və çıxarılmasıdır. Elementin əlavə edilməsi Push (ingiliscədən - itələyib salmaq), elementin çıxarılması isə Pop (ingiliscədən - sıçrayıb çıxmaq) adlanır. Sonuncu əlavə edilmiş element stekin başı (təpəsi) adlanır.

Stek üzərində stekin təmizlənməsi və onun cari elementinin tapılması kimi əməliyyatlar da yerinə yetirilə bilər. Stekin ortalarına elementin əlavə edilməsi/çıxarılması əməliyyatları stekin tərifinə uyğun olmadığı üçün yerinə yetirilə bilmir.

Stekə elementin əlavə edilməsi/çıxarılması əməliyyat­larını əyani başa düşmək üçün kiçik bir misala baxaq. Şəkil 2.29-da stekin aşağıdakı vəziyyətləri təsvir edilmişdir:

• 1) boş;• 2)- 4) A, B, C adlı elementlər ona ardıcıl əlavə

edildikdən sonra;• 5), 6) ardıcıl olaraq C və B elementləri stekdən

çıxarıldıqdan sonra;• 7) D elementi stekə əlavə edildikdən sonra.

102 Məhərrəmov Z.T., Vəliyev H.P.

Şəkil 2.29. Stekə elementlərin əlavə edilməsi/çıxarılması əməliyyatları

Şəkil 2.29-dan göründüyü kimi, steki masanın üzərindəki kitab qalaqları (elementləri) kimi təsəvvür etmək olar. Kitabların hər birinə ad, məsələn, A, B. C, D... adları verək. Onda, masa üzərində kitablar olmadıqda, masaya analoji olaraq, stek haqqında demək olar ki, o boşdur, yəni, heç bir elementi yoxdur. Əgər biz ardıcıl olaraq, masa üzərinə bir-bir kitabları qoysaq, onda masada kitab qalaqları (məsələn n sayda) və ya n sayda elementdən ibarət stek alacağıq, həm də bu stekin başı n+7-ci element olacaq. Stekdən elementlərin çıxarılması (silinməsi) analoji qaydada yerinə yetirilir, yəni, stekin başından başlayaraq ardıcıl olaraq bir-bir element və ya qalaqdan bir-bir kitab çıxarılır.

İndi isə stekin kompüterdə reallaşdırılmasına baxaq. Bunun üçün C++ dilində stack, Java və C# dillərində isə Stack adlanan siniflər (bəli, yeganə fərq baş hərfdən ibarətdir) mövcuddur.

C# dilində mövcud olan Stack<T> sinfinin iş prinsipi List<T> sinfinin iş prinsipi ilə eynidir. Stack<T> sinfinin əsas metodları cədvəl 2.7-də göstərilmişdir.

İndi isə stek üzərində əməliyyatları proqramlaşdıraq.Əvvəlcə massivdən stek yaradaq:

using System;using System.Collections.Generic;

İkinci fəsil. Verilənlərin statik və dinamik strukturları 103

Cədvəl 2.7. Stack<T> sinfinin əsas metodlarıMetodun adı Metodun funksiyasıPush Stekin sonuna yeni element əlavə edir

Pop Stekdən sonuncu elementi silir və onun qiymətini qaytarır

Pee k Stekin yuxarısından elementi qaytarır, lakin onu pozmur

Count Stekdə elementlərin sayını qaytarır

Cor.ta.nsArqument ilə göstərilmiş elementin stekdə olub- olmamasını yoxlayır; element mövcud olduqda true qiyməti qaytarır

C1 ear Steki təmizləyir (onun bütün elementlərini silir)

namespace Stekl {class Program {static void Main(string[] args) (mt[] b = { 3, 2, 1 );

Stack<int> stekl = new Stack<int>(b);

Console.WriteLine("İlkin siyahi:"); foreach (int k in stekl) {Console.Write(k+" ");

)

int elerc = stekl.Peek(); // elem = 1, // lakin element silinmir

Console.WriteLine();Console.WriteLine("\nPeek="telem);Console.WriteLine() ;Console.WriteLine("\nPeek()

emeliyyatindan sonra:");foreach (int k in stekl){Console.Write(k + " ");

104 Məhərrəmov Z.T., Vəliyev H.P.

}

int pop=stekl.Pop(); // stekl={2,3) Console.WriteLine();Console.WriteLine("\nPop=" + pop);Console.WriteLine();Console.WriteLine("\nPop()

emeliyyatindan sonra:");foreach (int k in stekl) {Console.Write(k + " ");

)

stekl.Push(5); // stekin əvvəlinə // 5 yerləşdirir

Console.WriteLine("\n");Console.WriteLine("Yekun siyahi: ") ; foreach (int k in stekl) (Console.Write(k+" ");

Console.WriteLine("\n");if (stekl.Contains (100) )Console.WriteLine("Stekde 100 elementi

var"); elseConsole.WriteLine("Stekde 100 elementi

yoxdur");

Console.WriteLine("\n\nStekin olçusu=" + stekl.Count);

Console.ReadKey() ; } ) 1

Proqramın mətnindəki şərhlər və şəkil 2.30-da göstərilmiş nəticələr steklə əməliyyatı tam aydın qavramağa imkan verir.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 105

Şəkil 2.30. Stekin elementləri üzərində əməliyyatların nəticələri

Növbəti misalda biz tam ədədlər üzərində hesab əməllərini yerinə yetirən kalkulyator proqramlaşdıracağıq. Burada biz polyak yazı üslubunu tətbiq edəcəyik. Bu üslubda operator öz operandlarından sonra yazılır. Yəni, adi halda biz ənənəvi olaraq

<operand> <operator> <operand> yazdığımız halda, polyak yazı üslubunda bu əməliyyat belə yazılır:

<operand> <operand> <operator>Başqa sözlə, 4 + 2 ifadəsinin yerinə biz 42 + yazacağıq.42 + əməliyyatı stekdə belə icra ediləcək:

106 Məhərrəmov Z.T., Vəliyev H.P.

push(4)push(2)push(pop() + pop())

Sonda stekdə yalnız bir qiymət qalacaqdır: 6.Həmin proqramın mətni belədir:

using System;using System.Collections.Generic;

namespace Stek2 {class Program {static void Main(string[] args) {Console.Write("> simvolunun qarşisindan

operandlari daxil edin:\n");while (true) {Console.Write("> ");string operandlar =

Console.ReadLine();if (operandlar == "quit") fbreak;

}// stekin yaradılması:Stack<int> stek2 = new Stack<int>();

// operandlari ayırırıq foreach (string simvol in operandlar.Split(new char[] { ' ' })) {

// Əgər qiymət tamdırsa...int value;if (int.TryParse(simvol, out value)) {

// ... onu stekə yerləşdiririk

İkinci fəsil. Verilənlərin statik və dinamik strukturları 107

stek2.Push(value); ) else {

// əks halda aşağıdakı əməliyyatları // aparırıq:

int opl = stek2.Pop();int op2 = stek2.Pop();

switch (simvol) { case :stek2.Push(op2 + opl); break;case stek2.Push(op2 - opl); break;case stek2.Push(op2 * opl); break;case "/":stek2.Push(op2 / opl); break;case "% " :stek2.Push(op2 % opl); break;default:// Əgər əməl işarələri +, *// və ya / olarsa:throw new ArgumentException( string.Format("Unrecognized

token: , simvol));> } }

// Stekdə sonuncu element elə// nəticə olur:Console,WriteLine(stek2.Pop());} } } )

108 Məhərrəmov Z.T., Vəliyev H.P.

Proqramın nəticəsi şəkil 2.31-də göstərilmişdir.

IJ F:\ZAKIR\VSA\Stek2\Stek2\bin\De bug\Stek2.exe

simvolunun 4 2 +

qarsisindan operandlari daxil edin:6> 45 20 - 25> 16 4 « 64> 99 3 / 33> 13 3 V.1> quit

'■-i,:

rrr

Şəkil 2.31. Stekin köməyi ilə yaradılmış kalkulyator

Proqram icra edildikdə verilənlər, yuxarıda qeyd etdiyimiz kimi, aralarında boşluq simvolu qoymaqla polyak üslubunda daxil edilməlidir (şəkil 2.31-də göstərildiyi kimi). Klaviaturadan ilkin verilənlər sətir kimi daxil edildikdən sonra. həmin sətir foreach dövrü daxilində Split metodu ilə alt sətirlər massivinə (operandlara) ayrılır. Sonra ədədlərin tam olması yoxlanır və tam olduqda Push metodu ilə onlar stekə əlavə edilir. Sonra daxil edilən əməl işarəsinə uyğun hesablama aparılır və stekdə nəticə olan yeganə qiymət qalır. Proqramdan çıxmaq üçün quit daxil edilməlidir.

2.12. Növbə və onun kompüterdə reallaşdırılması

Təsəvvür edin ki. Siz nəyinsə növbəsinə durursunuz. Bu növbədə birinci adama xidmət edirlər, sonra o gedir. Sonra növbədə dayanmış ikinci adama qulluq edilir və gedir. Digər insanlar növbəyə yaxınlaşır və onun sonunda dururlar. Məişətdə olan bu növbə prinsipi verilənlərin ‘‘növbə” adlı strukturunun ideyasını təşkil edir.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 109

Növbə (ingiliscə queue) — FIFO (First In First Out, “birinci gələn birinci çıxır”) strukturudur. Növbə elə dəyişən uzunluqlu ardıcıl siyahıdır ki, buraya elementlərin daxil edilməsi siyahının yalnız bir tərəfindən (bu tərəfi, adətən, növbənin somu və ya quyruğu adlandırırlar), çıxarılması isə digər tərəfindən (növbənin başlanğıcı və ya başi adlanan) mümkün olur. Növbəyə yeni element əlavə etdikdə və ya sildikdə birinci əlavə edilən birinci çixarılan element olur.

Növbələr steklərə çox oxşayır. Növbələr də həmçinin ixtiyarı elementə müraciət etməyə imkan vermir, amma, stekdən fərqli olaraq, elementlər müxtəlif uclardan (tərəflərdən) yerləşdirilir (enqueue') və çıxarılır (dequeue). Belə metod “birinci gələn birinci çıxır (First-ln-First-Out və ya FIFO) adlanır. Yəni növbədən elementləri qoyduğumuz qaydada da götürəcəyik (real növbələrdə olduğu kimi).

Növbə üzərində əsas əməliyyatlar steklər üzərində aparılan əməliyyatlarla eynidir: əlavəetmə, çıxarma (silmə), ölçünün təyin edilməsi, təmizləmə.

C# dilində növbələrlə işləmək üçün xüsusi Queue<T> sinfi mövcuddur ki, bu sinfin iş prinsipi adi siyahılarla işləmək üçün nəzərdə tutulmuş List<T> sinfinin iş prinsipi ilə eynidir. Queue<T> sinfinin əsas metodları cədvəl 2.8-də göstərilmişdir.

Aşağıdakı proqramla təsadüfi ədədlərdən ibarət növbə yaradılır və onun elementləri üzərində müxtəlif əməliyyatlar icra edilir.

using System;

namespace Novbel {class Program

static void Main(string[] args) {// Növbə yaradırıq

110 Məhərrəmov Z. T., Vəliyev H. P.

Cədvəl 2.8. Queue<T> sinfinin əsas metodlarıMetodun adı Metodun funksiyası

Dequeue Növbədən birinci elementi silir və onun qiymətini qaytarır

Enqueue Növbənin sonuna yeni element əlavə edir

Peek Növbənin başlanğıcından elementi qaytarır, lakin onu pozmur

Count Növbədə elementlərin sayını qaytarır

ContainsArqument ilə göstərilmiş elementin növbədə olub- olmamasını yoxlayır; element mövcud olduqda :rue qiyməti qaytarır

Clear Növbəni təmizləyir (onun bütün elementlərini silir)

Queue<int> nov = new Queue<int>(); Random ted = new Random();

// Növbəni təsadüfi ədədlərlə doldururuq for (int i = 0; i < 10; i++)nov.Enqueue(ted.Next(20, 40));

// Növbənin elementlərini ekranda// göstəıririkConsole.WriteLine("Novbedeki tesadufi

elementler:");foreach (int i in nov) Console.Write(i+ " ");

Console.WriteLine("\n\nNovbedeki elementlerin sayi= " +nov.Count);

int elem;if(nov.Contains(35))(Console.WriteLine("Novbede 35 elementi

var");elem = nov.Dequeue();Console.WriteLine("Dequeue()= "

+ elem);

İkinci fəsil. Verilənlərin statik və dinamik strukturları 111

}elseConsole.WriteLine("Novbede 35 elementi

yoxdur");Console.ReadLine();} } }

Proqramın nəticəsi şəkil 2.32-də göstərilmişdir.

F:\ZAIGR\VSA\NovbelXNovbel\...

Noubedeki tesadufi elementler: 38 39 36 35 22 31 37 22 31 37

Noubedeki elementlerin sayi= 10 Moubede 35 elementi varVequeueO= 38

Şəkil 2.32. Növbə üzərində əməliyyatlar

Bu misalda elementlərin hansı ardicılhqla daxil edilməsini tam müşahidə edə bilmədik. Bunu anlamaq üçün yeni proqram yazaq:

using System;

namespace Novbe2 {class Program {static void Main(string[] args)

// Növbə yaradırıqQueue<string> novbe = new

Queue<string> () ;

// Növbəni doldururuq:novbe.Enqueue("Kompüter");

112__________________________ Məhərrəmov Z. T., Vəliyev H.P.

novbe.Enqueue("Televizor") ;novbe.Enqueue("Maqnitafon");novbe.Enqueue("Tozsoran");novbe.Enqueue("Paltaryuyan");

// Növbənin elementlərini ekranda// göstəririkforeach (string cihaz in novbe)Console.WriteLine(cihaz);

// syahıdan silmədən elementləri alırıq: object cihazl = novbe.Peek(); // cihazl

// = "Kompüter"object cihaz2 = novbe.Peek(); // cihaz2

// = "Kompüter"Console.WriteLine("\nPeek= " + cihaz2);

// syahıdan silməklə elementləri alırıq: object Cihazl = novbe.Dequeue();// Cihazl = "Kompüter" alınır

object Cihaz2 = novbe.Dequeue();// Cihaz2 = "Televizor" alınır

object Cihaz3 = novbe.Dequeue();// Cihaz3 = "Maqnitafon" alınır

// Növbənin elementlərini ekranda// göstəririk:Console.WriteLine("\nNovbenin qalan

elementleri:") ;foreach (string cihaz in novbe)Console.WriteLine(cihaz);

novbe.Clear(); // növbə təmizləndiConsole.WriteLine("\n\nNovbedeki elementlerin sayi= " + novbe.Count);

Console.ReadLine();

İkinci fəsil. Verilənlərin statik və dinamik strukturları 113

Proqram şərhlərindən və şəkil 2.33-də göstərilən nəticədən növbənin necə yaradılması tam aydın başa düşülür.

Peek= Kompüter

Novbedeki elementlerin sayi" 0

Novbenin qalan elementleri: Tozsoran Paltaryuyan

F:\ZAKIRWSA\Novbe2\Novbe2\...

Kompüter Televizor Naqnitafon Tozsoran

^Paltaryuyan

b

Şəkil 2.33. Növbənin yaradılması və onun üzərində əməliyyatların nəticələri

Növbələr buferin reallaşdırılması üçün proqramlarda tez-tez istifadə olunur, bu zaman daxilolma qaydasına əməl etməklə, sonrakı emal üçün buferə növbəti element qoymaq olar. Məsələn, əgər verilənlər bazası yalnız bir birləşməni dəstəkləyirsə, axınlar növbəsindən istifadə etmək olar ki, o, qəribə olsa da, VB-ə müraciət üçün öz növbəsini gözləyəcəkdir.

2.13. Dek

Proqramçılara çox tez-tez növbənin hər iki uclarından elementləri əlavə etmək və ya silmək lazım gəlir. Belə struktur dek və ya ikitərəfli növbə (ingiliscə deque - double

114 Maharramov Z.T., Valiyev H.P.

ended queue) adlanır. Dek elə dəyişən uzunluqlu ardıcıl siyahıdır ki. buraya elementlərin həm daxil edilməsi, həm də çıxarılması siyahının istənilən ucundan mümkün olur. Dekin xüsusi halı - məhdud girişli dek və məhdud çıxışlı dekdir. Dekin məntiqi və fiziki strukturu halqavari FIFO növbəyə analojidir. Ancaq dekdə başlanğıc və son yox, sol və sağ uclar anlayışları daha məqsədəuyğundur.

Növbənin digər növü proritetli (üstünlüklü) növbədir. Proritetli növbə adi növbəyə çox oxşayır. Proqram elementi sondan əlavə edir, başlanğıcdan isə çıxarır. Fərq ondadır ki, növbənin müəyyən elementlərinə prioritetlər vermək olar. Bütün vacib elementlər FIFO qaydası ilə emal edilir. Sonra FIFO qaydası ilə daha aşağı prioritetli elementlər emal edilir. Və bu, bütün aşağı prioritetli elementlər FIFO qaydası ilə emal edilənə kimi təkrarlanır.

Dek əsas dillərin əksəriyyətinə daxil edilmişdir. C++ dilində bu queue və deque sinfidir. Java dili növbə və ikitərəfli növbə üçün interfeyslər müəyyən edir, amma sonra onları LinkedList vasitəsilə reallaşdırır. C# dilində Queue sinfi var. amma Deque sinfi yoxdur.

Növbə və ikitərəfli növbənin daxili strukturu kifayət qədər mürəkkəb ola bilər. Belə ki, obyektlər istənilən uclardan daxil ola və çıxarıla bilər, ona görə daxili struktur növbəni həm başlanğıcdan, həm də sondan qısalda və ya böyüdə bilməlidir.

Dek üzərində aşağıdakı əməliyyatlar yerinə yetirilə bilər:

• elementin sağdan daxil edilməsi;• elementin soldan daxil edilməsi;• elementin sağdan silinməsi;• elementin soldan silinməsi;• ölçüsünün müəyyən edilməsi;• təmizlənmə.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 115

Statik yaddaşda dekin fiziki strukturu halqavari növbənin strukturuna analojidir. Onun dinamik reallaşdırılması stek və növbənin aşkar birləşməsidir.

Dek strukturunu tələb edən məsələlər hesablama texnikasında stek və növbə strukturlarını tələb edən məsələlərə nisbətən daha az rast gəlinir. Bir qayda olaraq, dekin təşkili sistem tərəfindən dəstəklənən xüsusi vasitələr olmadan proqramçının özü tərəfindən yerinə yetirilir.

Dekə misal olaraq hər hansı terminalı göstərmək olar ki, oraya əmrlər daxil edilir və onların hər biri müəyyən vaxtda yerinə yetirilir. Hər hansı bir əmrin icrası başa çatmamış növbəti əmr daxil edildikdə, o növbəyə dayanır və terminal azad olan kimi icra edilməyə başlayır. Bu FIFO növbədir. Əgər əlavə olaraq sonuncu daxil edilmiş əmrin icrasını ləğv etmək əmri daxil edilərsə, onda dek alınır.

Yekun olaraq qeyd edək ki, steklər, növbələr, iki istiqamətli növbələr və prioritetli növbələri verilənlərin digər strukturları əsasında reallaşdırmaq olar. Bunlar fundamental strukturlar deyil, lakin tez-tez istifadə edilir. Yalnız uclardakı elementlərlə işləmək lazım gəldikdə, ortalardakı elementlər isə vacib olmadıqda bu strukturlar xüsusən çox səmərəli olur.

2.14. Fayllar

Məlumdur ki, proqramın tələb etdiyi ilkin verilənlər klaviaturadan daxil edilir və alınmış nəticələr ekranda təsvir edilir. Bu zaman əlavəni bağladıqda görülən bütün işlər itir. Real iş prosesində isə belə olmur: tələb olunur ki, verilənlər hər hansı fayllardan daxil edilsin və onlar müxtəlif fayllarda yadda saxlanılsın. Verilənləri fayllardan daxil etməyi və fayllarda yadda saxlamağı bacarmaq lazımdır. Bütün informasiya xarici yaddaş qurğularında fayl şəklində yadda saxlanır. Fayllar kataloqda, kataloqlar isə bir-birinin daxilində yerləşir.

116 Məhərrəmov Z, T., Vəliyev H.P.

Kompüter proqramlarının əksəriyyəti fayllarla işləyir və ona görə də fayllarla iş dedikdə aşağıdakı əməliyyatlar başa düşülür:

• faylları yaratmaq;• faylları pozmaq;• faylları açmaq;• verilənləri oxumaq;• verilənləri yazmaq;• faylın parametrlərini (adını, genişlənmiş hissəsini və

s.) dəyişdirmək;• digər əməliyyatlar.Bəs fayl nədir? Fayl - hər hansı xarici yaddaş

qurğusunda saxlanılan və unikal ada malik olan verilənlər yığımıdır məsələn, Nizami . txt. Faylda müxtəlif tipli veri­lənlər yerləşə bilər. Bir kataloqda (qovluqda) eyniadlı bir neçə fayl yerləşə bilməz. Faylın adı dedikdə yalnız faylın öz adı deyil, həm də onun genişlənmiş hissəsi başa düşülür, məsələn, Nizami . txt və Nizami . dat — müxtəlif fayl- iardır, baxmayaraq ki, onların adları eynidir. “Faylların tam adı” kimi anlayış da mövcuddur - bu faylın adını da göstər­məklə faylın yerləşdiyi qovluğun tam ünvandır, məsələn, F:\KAFEDRA\Nizami.txt. Belə mühüm anlayışları bilmək əhəmiyyətlidir, əks halda fayllarla işlədikdə çətinliklər yaranacaqdır. Biz fayllarla işlədikdə mətn və ikilik fayllarla rastlaşırğıq. Mətn faylları hamının başa düşə biləcəyi simvollar yığımından ibarət olduğu halda, ikilik fayllar ikilik kodlardan ibarət olur və bu faylları adi mətn redaktorları ilə açmağa cəhd etdikdə anlaşılmaz simvollarla təsvir olunur. Belə faylları yalnız proqramlaşdırma yolu ilə oxumaq olar.

C# dilində fayllarla işin əsasını axınlar təşkil edir. Faylı oxunmaq və ya fayla yazılmaq üçün açdıqda biz axınlarla (stream) işləməli oluruq. Axınlar faylla müqayisədə daha çox funksional imkanlara malik olur. Axınlar verilənlərin

İkinci fəsil. Verilənlərin statik və dinamik strukturları 117

strukturunu, massivləri və digər axınları oxumağa və yazmağa imkan verir.

Ümumiyyətlə, fayllarla işlədikdə C# dilində System. 10 adlar fəzasından (kitabxanasından) istifadə edilir. Burada fayllarla işləmək üçün zəruri olan bütün siniflər yerləşir. Bu adlar fəzasını qoşmaq və axınlarla işləmək üçün proqramın başlanğıcına aşağıdakı sətri əlavə etmək lazımdır:

using System.10;Cədvəl 2.9-da System. 10 adlar fəzasına daxil olan

siniflərin qısa təsviri verilmişdir.

Cədvəl 2.9. System. 10 adlar fəzasına daxil olan siniflər

Sinfin adı Təyinatı

BinaryReader BinaryWriter

Daxili təsvir formasında sadə təməl tiplərinin (tam, məntiqi, sətir və s.) qiymətlərinin oxunması və yazılması

BufferedStreamBaytlar axınının müvəqqəti saxlanması (məsələn, daimi saxlanc yerinə ötürmək üçün)

Directory, Directorylnfc, File, Filelnfo

Kataloqlarla və ya fiziki fayllarla iş: onların yaradılması, pozulması, xassələri haqqında məlumat almaq və s. File və Directory siniflərinin imkanları əsasən statik metodlar şəklində reallaşdırılmışdır.Directorylnfo və Filelnfo sinifləri adi metodlardan istifadə edir

FıleStre am Baytlar axını kimi təsvir edilmiş fayla sərbəst (birbaşa) müdaxilə

MemoryStream Operativ yaddaşda baytlar axınına sərbəst müdaxilə

StreamWriterStreamReader

Mətn informasiyasının fayldan oxunması və fayla yazılması (sərbəst müdaxilə dəstəklən­mir)

StringWriterStringReader Operativ yaddaşda mətn informasiyası ilə iş

118 Məhərrəmov Z. T„ Vəliyev H.P.

Cədvəldən göründüyü kimi, xarici qurğularla mübadilə aşağıdakı səviyyələrdə aparıla bilər:

• verilənlərin ikilik təsviri ilə (BinaryReader, BinaryWriter);

• baytlarla (FileStream);• mətnlərlə, yəni simvolla (StringWriter,

StringReader).Mətn fayllarında verilənlərə yalnız ardıcıl, ikilik və

bayt axınlarında isə verilənlərə həm ardıcıl, həm də birbaşa müdaxilə etmək olar

2.14.1. Mətn faylları

Mətn faylları ilə işləmək üçün StreamWriter və StreamReader siniflərinin axınlarından istifadə etmək daha asandır.

Əvvəlcə verilənlərin mətn faylına necə yazılmasını öyrənək, sonra isə verilənlərin mətn faylından oxunmasını araşdırarıq.

Verilənlərin mətn faylına yazılması. Mətn tipli fayl yaratmaq üçün File sinfində CreateText!) metodu mövcuddur. Bu metoda yalnız bir arqument - fayla yol - vermək lazımdır, məsələn:

CreateText("F:WKAFEDRAWNizami.txt").

Fayla verilənləri yazmaq üçün əvvəlcə faylı yaratmaq, sonra isə onunla işləmək üçün axını açmaq lazımdır, yəni:

StreamWriter mf=File.CreateText( "F: WKAFEDRAWNizami . txt") ;

Biz burada mf axınını, sonra isə, File.CreateText ("F: WKAFEDRAWNizami .txt"

İkinci fəsil. Verilənlərin statik və dinamik strukturları 119

) metodunun köməyi ilə, F: diskinin KAFEDRA qovluğunda Nizami . txt adında fayl yaratdıq.

Axını açdıqdan sonra isə biz, Write və WriteLine metodlarının köməyi ilə fayla istənilən mətn sətirlərini yaza bilərik:

mf.WriteLine("Nizami Gencevi dahi Azerbaycan şairidir");

Lakin, biz proqramı işə saldıqdan sonra faylın məzmununa baxsaq görəcəyik ki, həmin fayl boşdur. Bu normal haldır, çünki, faylda verilənlər yalnız mf axınını bağladıqdan sonra peyda olacaqdır. Bu Close () metodu ilə yerinə yetirilir:

m f . C1 o s e () ;İndi faylın məzmununa baxsaq (məsələn, Notepad,

WordPad və s. redaktorları ilə), daxil etdiyimiz sətri müşahidə edəcəyik.

Biz burada yeni fayl yaradıb oraya mətn daxil etdik. Elə hal ola bilər ki, mövcud fayla yeni sətir əlavə etmək lazım gəlsin. Bu halda AppendText () metodundan istifadə edilir, başqa sözlə, CreateText() metodunun yerinə bu metodu yazmaq lazımdır:

StreamWriter mf = File.AppendText("F: WKAFEDRAWNizami . txt" ) ;

mf.WriteLine("O, dünyaya "Xemse" kimi bir xezine bağışlamışdır1');

mf .Close ();

Bu proqramın tam mətni belə olacaqdır:

using System;using System.10;namespace Nizami {class Program {static void Main(string[] args)

120 Məhərrəmov Z. T., Vəliyev H.P.

{StreamWriter mf =File.CreateText("F: \\KAFEDRA\\

Nizami.txt");mf .WriteLine("Nizami Gencevi dahi

Azerbaycan şairidir");mf .WriteLine("O, dünyaya "Xemse" kimi

bir xezine bağışlamışdır");mf.Close (); )})

Proqramı F5 klavişini basmaqla işə saldıqdan sonra, proqramın nəticəsi kimi F: diskinin KAFEDRA qovluğunda Nizami.txt adlı fayl yaradılacaqdır və onun məzmunu yuxarıdakı iki sətirdən ibarət olacaqdır.

İndi isə verilənlərin fayldan oxunmasını araşdıraq.Mətn verilənlərinin fayldan oxunması. Verilənləri

fayldan oxumaq üçün ilk növbədə onu açmaq lazımdır. Bunun üçün StreamReader sinfinin axınını faylla əlaqələndirərək onu açmaq lazımdır. Bu Fil e .OpenText () ; metodunun köməyi ilə yerinə yetiri­lir, yəni:

StreamReader mf = File.OpenText( "F: WKAFEDRAWNizami. txt") ;

Əgər bizə faylın yalnız birinci sətrini oxumaq lazımdırsa, onda sadəcə olaraq mf. ReadLine () konstruksiyasını yazmaq kifayətdir. Fərz edək ki, biz faylın birinci sətrini ekranda təsvir etmək istəyirik. Bunun üçün proqramda

Console.WriteLine(mf.ReadLine()); kodunu yazmaq lazımdır.

Əgər faylın bütün məzmununu oxumaq tələb olunarsa, onda məsələ bir az çətinləşir. Çünki, biz faylın neçə sətirdən ibarət olduğunu əvvəlcədən bilməyə bilərik. Fayldan verilənlər sətirbəsətir oxunur. Faylın isə məzmununu bütün

ikinci fəsil. Verilənlərin statik və dinamik strukturları 121

sətirlər oxunana kimi davam etdirmək lazımdır. Bu isə yalnız dövr təşkil etməklə mümkündür:

StreamReader sr =File.OpenText("F:\\KAFEDRA\\

Nizami.txt");While (true) { string st = sr.ReadLine(); if (st==null) break;Console.WriteLine (st) ; }

Göründüyü kimi, dövrdən çıxış əlaməti sətir tipli st dəyişəninin null qiymətinə bərabər olmasıdır.

Həm fayla yazdıqda, həm də fayldan oxuduqda axını Close metodu ilə bağlamağı unutmaq olmaz, yəni hər iki halda proqrama mf . Close () ; kodunu yazmaq lazımdır.

İndi isə yuxarıda yazdığımız proqrama faylın məzmununu ekrana çıxaran proqram kodunu əlavə etməklə tam proqramı yazaq:

using System.10; using System; namespace Nizami { class Program {

static void Main(string[] args) {

StreamWriter mf =File.CreateText("F:\\KAFEDRA\\

Nizami.txt");mf .WriteLine("Nizami Gencevi dahi

122___________________________Məhərrəmov Z. T., Vəliyev H.P.

Azerbaycan şairidir");mf.WriteLine("0, dünyaya "Xemse" kimi

bir xezine bağışlamışdır");mf.Close () ;

// Fayldan verilənlərin oxunmasıStreamReader sr =File.OpenText("F:\\KAFEDRA\\

Nizami.txt");

while (true){string st = sr.ReadLine();if (st == null)

break;System.Console.WriteLine(st) ;

}mf .Close();

Console.ReadLine() ; } } }

Proqramın nəticəsi şəkil 2.34-də göstərilmişdir.

Nizami Genceui dahi Azerbaycan şairidir D. diinuaua "Xemse" kimi bir xezine haaıslamısdır

a ' C:\Users\Usei\Desktop\CCC\Nizami\Nizami\bin\Deb... I 1=1 I ImS—ı

Şəkil 2.34. Faylın məzmununun ekrana çıxarılması

Mətn fayllarına nəinki, yalnız qrammatikada başa düşülən mənada mətnlər, yəni hərf-simvollardan ibarət sətirlər, həm də riyazi hesablamanın nəticələrini də yazmaq mümkündür. Aşağıdakı misalda hesablamanın nəticələrinin mətn tipli fayllara yazılması nümayiş etdirilmişdir.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 123

Misal.y=x/(l+x) funksiyasının cədvəlləşdirilməsi.

using System;using System.10;namespace ConsoleApplication48 ( class Prcgram ( stacic double f(double x) { double y;y - x / (1.0 + x) ; return y;}static void Main(string[] args) ( double x = 0.0;StreamWrıter mf = File.CreateText(

"F:table.dat");mf.WriteLine("y=x/(1+x) funksiyasının");mf .WriteLine(" cədvəl qiymətləri");mf .WriteLine() ;mf.WriteLine ( " x y");mf.WriteLine();for (int k = 0; k <=50; k++) (double y = f(x);y = Math.Round(y, 4);mf.WriteLine( " { 0,3 : F) {1,15:F5)",

x, y) ;x = x + 0.1;if (k % 10 == 9) mf.WriteLine();

Proqramın nəticəsi şəkil 2.35-də göstərilmişdir (proqram kodunda boş sətir buraxmaq üçün yazılmış

124 Məhərrəmov Z.T., Valiyev H.P.

mf.WriteLine (); kodu əvəzinə mf.Write(mf . NewLine) ; kodunu da yazmaq olar).

table.dat — G._2L

©a fin npaaıca ©opijaı 8hä Çn pasxa y=x/(l+x) funksiyasının

cədvəl qiymət "Ur i

X y0,00 0,000000.10 0.090900,20 0,166700.30 0.230800,40 0,285700.50 0.333300,60 0,375000,70 0,411800,80 0,444400,90 0,47370

1,00 0,500001,10 0,523801,20 0,545501,30 (J, 565201,40 0,583301,50 0,600001,60 0,615401,70 0,629601,80 0,642901,90 0,65520

2,00 0,666702,10 0,67740

r<

Şəkil 2.35. y=x/(l+x) funksiyasının cədvəlləşdirilməsi

Mətn fayllan ilə işlədikdə WriteAllText() və AppendAllText () metodlarından istifadə etmək olar.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 125

WriteAlIText () metodu yeni fayl yaradır (əgər belə fayl yoxdursa) və ya mövcud faylı açır və bu faylın bütün məzmununu dəyişməklə yeni mətn yazır:

static void Main(string[j args) {File.WriteAllText ( "F: \\KAFEDRA\\

Nizami.txt", "XX əsrin dahi şairi S.VURĞUN");

)

AppendAllText () metodu da WriteAllText () metodu kimi işləyir, fərq ondan ibarətdir ki, faylın məzmununu pozmadan onun sonuna yeni mətn əlavə edir:

static void Main(string[] args) (File.AppendAllText("F:\\KAFEDRA\\ Nizami.txt", "O, "Fərhad və Sirin"

poemasını yazmışdır");

Hər iki metod axından deyil, File sinfinə müraciət etməklə çağrı İm işdir.

2.14.2. İkilik fayllar

Fayl axınları ilə işləmək üçün sadə üsullara baxaq. Yuxarıdakı izahlardan da gördük ki, proqramlarda fayl axınları siniflərinin istifadə edilməsi aşağıdakı əməliyyatların yerinə yetirilməsini tələb edir:

• axının yaradılması və onun fiziki faylla əlaqələndirilməsi;

• verilənlərin mübadiləsi (fayla verilənləri yazmaq və ya onları oxumaq);

126 Məhərrəmov Z. T., Vəliyev H.P.

• faylın bağlanması.FileStream axının açılması. Bu Stream

sinfindən törəmə sinifdir. O, bir baytla və ya baytlar massivləri ilə işləyə bilər. İkilik verilənlərlə işləmək üçün əvvəlcə FileStream sinfinin axınını yaratmaq lazımdır:

FileStream dəyişən=new FileStreamf fayla yol, axını açmaq rejimi);

Burada, dəyişən - ixtiyari ad, fayla yol-ikilik faylın ünvanıdır, axını açmaq rejimi-faylı açmaq rejimini müəyyənləşdirir, məsələn, faylı yalnız oxumaq, yalnız yazmaq və ya həm oxumaq, həm də yazmaq üçün açmaq olar. Bu müdaxilə rejimləri FileAccess sinfinin statik sabitləri ilə təyin olunur və onlar aşağıdakılardır:

• Read - yalnız oxumaq üçün;• ReadWrite - həm oxumaq, həm də yazmaq üçün;• Write - yalnız yazmaq üçün.

Axınların açılması rejimləri isə FileMode sinfi ilə müəyyənləşdirilir.

Bu rejimlər cədvəl 2.10-da göstərilmişdir.

Misal. Faylın sonuna verilənlərin əlavə edilməsi.

FileStream kf=newFileStream(@"F:\Kafedra\funk.dat", FileMode.Append, FileAccess.Write);

Bu kod Kafedra qovluğunda yerləşən funk.dat faylını, onun sonuna verilənlər əlavə etmək üçün, açır (biz burada fayla yolu tam göstərmək üçün @ literalından istifadə etdik; bu halda əksinə maili xətt simvolunu təkrarlamamaq olar). Yeri gəlmişkən qeyd edək ki, FileMode. Append rejimini yalnız Fi leAccess. Write tipli müdaxilə ilə birgə, yəni yalnız yazmaq üçün açmaq rejimində istifadə etmək olar.

İkinci fəsil. Verilənlərin statik və dinamik strukturları 127

Cədvəl 2.10. FileMode sinfinin axınları açma rejimləri

Rejimlər Təyinatı

Apper.d

Əgər fayl mövcuddursa, onda o, açılacaqdır. Faylın sonu cari mövqe kimi müəyyənləşdiri­lir. Əgər fayl mövcud deyilsə, onda o, yaradı­lacaqdır. Yalnız Write müdaxilə rejimində işləyir

CreateYeni fayl yaradır. Əgər kataloqda belə fayl mövcud olarsa, onda onun məzmunu yenisi ilə əvəz olunacaqdır

CreateNewYeni fayl yaradır. Əgər kataloqda belə fayl mövcud olarsa, onda müstəsna hal baş verə­cəkdir

OpenMövcud faylı açır. Əgər kataloqda belə fayl mövcud olmazsa, onda müstəsna hal baş verə­cəkdir

OpenOrCreateƏgər kataloqda fayl mövcud olarsa, onda o, açılacaq, əks halda fayl yaradılacaq və açıla­caqdır

Truncate Mövcud faylı açır. Fayl açıldıqdan sonra o. sıfır uzunluğa qədər qısaldılmalıdır.

FileStream axını ilə işlədikdə sətir verilənlərini baytlar massivinə çevirmək işi xeyli asanlaşdırır, əks halda verilənlər massivini hər bir simvol üzrə daxil etmək tələb olunur, bu isə çox yorucudur. Bu məqsədlə System. Text adlar fəzasının Encoding xüsusi sinfindən istifadə etmək olar ki, o, sətirləri baytlar massivinə kodlaşdırmağa və, əksinə, dekodlaşdırmağa imkan verir, kodlaşdırılmış massiv FileStream.Write() metodu vasitəsi ilə fayla yazılır. Həmin baytları yaddaşa oxumaq üçün isə faylın başlanğıc mövqeyinə keçmək və onu ReadByte () metodu ilə oxumaq lazımdır. Faylın başlanğıc mövqeyinə keçmək üçün isə Position xassəsinə 0 qiyməti vermək lazımdır.

Misal. FileStream sinfinin öyrənilməsi.

using System;

128 Məhərrəmov Z.T., Vəliyev H.P.

using System.10;namespace ConsoleApplication54 {class Program {static void Main(string[] args) {Console.WriteLine();Console.WriteLine("FileStream sinfinin

öyrenilmesi");Console.WriteLine() ;// Faylm yaradılması və yazılıb- //oxunması üçün açılmasıFileStream f = newFileStream(@"F:\Kafedra\Metn.txt", FileMode.Create, FileAccess.ReadWrite);

// Sətrin massiv baytları// kimi kodlaşdırılması:string msg = "FileStream sinfi ile iş " byte[] Arr =

Encoding.Default.GetBytes(msg); // Default xassəsi əməliyyat sisteminin //cari ANSI kod səhifəsi üçün //kodlaşdırmanı alır

// Massivin fayla yazılması:f.Write(Arr, 0, Arr.Length); /* burada ə — axının bayt nömrəsidir, bu nömrədən başlayaraq fayla verilənlər yazılır */

// axının başlanğıc mövqeyinin// bərpa edilməsif•Position = 0;

// Axının oxunmasıConsole.Write("Faylda olan baytlar

massivi " + "(kodlaşdırılmış setir):\n");

ikinci fəsil. Verilənlərin statik və dinamik strukturları 129

byte[] b = new byte[Arr.Length];for (int i = 0; i < Arr.Length; i + +) {b[i] = (byte)f.ReadByte();

/* ReadByte() metodu Int32 tipinə çevrilmiş baytı qaytarır, ona görə də yenidən byte tipinə qayıtmaq üçün əksinə çevirmə etmək lazımdır */

Console.Write(b[i]); }

Console.WriteLine();

// Kodu açılmış nəticənin// ekrana çıxarılması:Console.Write("\nKodu açılmış netice " +

"(bu setir kodlaşdırılmışdı):\n");Console.WriteLine(Encoding.Default.

GetString(b));f.Close();Console.Read();} } }

Proqramın nəticəsi şəkil 2.36-da göstərilmişdir.

■C:\Users\User\Desktop\CCC\ConsoleApplication54\ConsoleApplication54\bin\... I ° I LJ

PileStrean sinfinin öyrenilnesi

todu açılmış netice (bu setir kodlaşdırılmadı): FileStream sinfi ile i

Faylda olan baytlar massivi (kodlaşdırılmış setir):70105108101831161141019710932115105110102185321051881813210525432

Şəkil 2.36. FileStream sinfi ilə işin nəticəsi

130 Məhərrəmov Z. T., Vəliyev H.P.

İkilik verilənlərdən ibarət fayllarla əlaqədar axın yaratmaq üçün BinaryWriter və BinaryReader kimi iki sinifdən də istifadə edilir.

BinaryWriter və BinaryReader axınlarının açılması. Bu axınlar aşağıdakı kimi açılır:

BinaryWriter bf = new BinaryWriter(kf);BinaryReader bf= new BinaryReader(kf);Burada, bf ixtiyari dəyişənin adı. kf isə FileStre-

am tipli axınıdır.BinaryWriter axınına verilənləri yazmaq üçün

Write metodunun bir neçə yenidən yükləmə metodları nəzərdə tutulmuşdur.

Misal. BinaryWriter axınına verilənlərin yazılma­sı.

FileStream kf =new FileStream("first.dat", FileMode.CreateNew);BinaryWriter bf = new

BinaryWriter(kf);bf.Write("text");bf.Write((uint)i);b f . c 1 o s e () ;kf.close ();

BinaryReader axınından verilənləri oxumaq üçün bir neçə metod nəzərdə tutulmuşdur.

Misal. BinaryReader axınından verilənlərin oxun­ması.

FileStream kf =new FileStreamf "funk.dat", FileMode.Open,

FileAccess.Read);BinaryReader bf =new BinaryReader(kf);String s=bf.ReadString();b f . c 1 o s e () ;kf.close ();

ikinci fəsil. Verilənlərin statik və dinamik strukturları 131

Axınların bağlanması. Proqram axınlarla işini başa çatdırdıqdan sonra onları bağlamaq lazımdır. Axınları bağlamaq üçün Close() metodundan istifadə edilir. Axınları onların açılmasının tərsinə olaraq (sonuncu açılanı birinci) bağlamaq lazımdır. Sonuncu iki misalda məhz bu hal nümayiş etdirilmişdir.

Misal. Mətn tipli fayl bölməsində cədvəlləşdirdiyimiz funksiyanın nəticələrini ikilik fayla yazaq və nəticələri oxuyub ekranda təsvir etdirək.

using System;using System.10; namespace ikilik {class Program

static double f(double x) {

double y;y = x / (1.0 + x); return y;

} static void Main(string[] args) { double x = 0.0;// Nəticəni yazmaq üçün faylın // yaradılması və onun açılması Filelnfo kf = new Filelnfo(

@"F:\Kafedra\funk.dat") ;BinaryWriter bf = new BinaryWriter(

kf.OpenWrite());for (int k = 0; k <= 50; k++) {double y = f(x);y = Math.Round(y, 4);bf.Write(y);x = x + 0.1; 1

132 Məhərrəmov Z.T,, Vəliyev H.P.

bf.Close(); x = -0.1;// Nəticələrdən ibarət yaradılmış // faylın oxumaq üçün açılması BinaryReader br = new BinaryReader(

kf.OpenRead());double[] yl = new double [ 51 ]; for (int k = 0; k <= 50; k++)

x = x + 0.1;yl[k] = br.ReadDouble();Console.WriteLine("x= {0} y={1}",

x, yl[k]);} br.Close();Console.WriteLine("Proqram uğurla başa

çatdı");Console.ReadLine(); } } )

Proqramın nəticəsi şəkil 2.37-də göstərilmişdir.

Şəkil 2.37. Faylın məzmununun ekrana çıxarılması

İkinci fəsil. Verilənlərin statik və dinamik strukturları 133

Bu misalın həllində Filelnfo sinfinin Open() metodundan istifadə edilmişdir. Çünki, BinaryWriter axınının özünün Open () metodu yoxdur. Qeyd edək ki, yalnız y dəyişəninin qiymətləri fayldan oxunmuşdur (çünki, yaradılmış funk. dat faylına yalnız y dəyişəninin qiymət­lərini yazmışıq), x dəyişəninin qiymətləri isə for dövrü ilə adi qaydada ekrana çıxarılmışdır.

Ümumiyyətlə, fayl mövzusu çox genişdir və onların dərindən öyrənilməsi üçün digər mənbələrə müraciət edil­məsini məsləhət görürük.

VERİLƏNLƏRİN İYERARXİK QEYRİ- XƏTTİ DİNAMİK STRUKTURLARI

3.1. Qraf və ağacların təsviri

Əlaqəli siyahılar, steklər və növbələr verilənlərin xətti strukturlarına aiddir. Ağac isə verilənlərin digər növü olan qeyri-xətti iki ölçülü struktura aiddir. Ağac özündə iki və daha çox istinad saxlayır. Ağacın mahiyyətini yaxşı qavramaq üçün çox səthi formada qraflar nəzəriyyəsinin bəzi anlayışlarını öyrənək.

Qraflar nəzəriyyəsi hesablama riyaziyyatının mühüm hissəsidir. Bu nəzəriyyənin köməyi ilə müxtəlif sahələrdən çoxlu məsələlər həll edilir. Qraf - öz aralarında bir-biri ilə birləşdirilmiş zirvələrdən (təpələrdən) və tillərdən ibarətdir. Qraflar nəzəriyyəsi nöqteyi-nəzərindən zirvə və tillərin hansı məna kəsb etməsinin heç bir əhəmiyyəti yoxdur. Zirvələr yaşayış məntəqələri, tillər isə onları birləşdirən yollar ola bilər və ya zirvələr alt proqramlara, tillər isə alt proqramların qarşılıqlı təsirinə uyğun ola bilər. Adətən, qrafda qövsün

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 135

istiqamətləri məna kəsb edir. Əgər til istiqamətə malikdirsə, o qövs adlanır, istiqamətlənmiş tilli qraf isə orqraf adlanır.

İndi qraflar nəzəriyyəsinin daha formal əsas tərifini verək. G qrafı nizamlanmış (V, E) cütlüyüdür, burada V - boş olmayan zirvələr, E isə V çoxluğunun elementlər cütlüyü çoxluğudur. V çoxluğunun elementlər cütlüyü til adlanır. V çoxluğunun nizamlanmış element cütlüyü qövs adlanır. Əgər E-də bütün cütlüklər nizamlanmışdırsa, onda qraf istiqamətlənmiş adlanır.

Yol - orqrafın zirvələrinin istənilən elə ardıcıllığıdır ki, bu ardıcıllıqda h zirvəsi a zirvəsindən sonra gələ bilər, ancaq gərək <7-dan Z>-yə gedən qövs mövcud olsun. Analoji qayda ilə qövslərdən ibarət olan yola tərif vermək olar. Bir zirvədən başlanan və həmin zirvədə qurtaran yol dövr adlanır. Hansı qrafda ki, dövrlər yoxdur, o qraf asiklik adlanır.

Qrafın ən vacib xüsusi halından biri ağacdir. Aşağıdakı şərtləri ödəyən orqraf ağac adlanır:

I. Elə düyün (node) mövcuddur ki, ona heç bir qövs daxil olmur. Bu düyün A:öÄ:(root) adlanır.

2. Kökdən başqa, hər zirvəyə bir qövs daxil olur.Qeyri-xətti strukturların ən vacib növlərindən biri

ağaclardır. Ağacvari strukturlar əcdad, nəsil (varis), qardaş (bacı) və s. kimi əlaqələri müəyyən etməyə imkan verir.

Verilənlər ağacları bir çox hallarda çox vacib əhəmiyyət kəsb edir. Video oyunların hazırlanmasında ağacların strukturu istehsalçıya oyun dünyasında hər obyekti yoxlamadan yanaşı yerləşən obyekti tez tapmağa imkan verən sahəni bölmək üçün istifadə olunur.

Bəs ağac nədir? Ağac... elə ağacdır. Əsl ağacın kökü, budaqları var. budaqların sonlarında isə yarpaqları var.

Verilənlərin strukturu ağacların kök düyünündən başlayır. Hər düyün törəmə düyünlərinə ayrıla bilər. Əgər düyündə törəmə element yoxdursa, onda o yarpaq düyünü adlanır. Bir neçə ağac meşə adlanır. Şəkil 3.1-də ağac nümunəsi göstərilmişdir. Əsl ağaclardan fərqli olaraq onlar

136 Məhərrəmov Z.T., Vəliyev H.P.

yuxarıdan aşağıya böyüyür: kök düyünü adətən yuxarıda, yarpaqlar isə aşağıda çəkilir.

Şəkil 3.1. 9 elementdən ibarət kök ağacı (ağacın hündürlüyü - 3)

Kök ağacı (rooted tree) - əlaqəli düyünlər (nodes) yığımından ibarət strukturudur və onlardan biri ağacın köküdür (root).

Til (edges) ağacın düyünlərini əlaqələndirir və onların arasında “valideyn-törəmə" (parent-child) münasibətini müəyyən edir. Şəkil 3.1-də kök ağacının nümunəsi təsvir edilmişdir.

Hansı düyünün ki, törəmə zirvələri yoxdur, xarici düyün (external node) və ya yarpaq (leaf node) adlanır. Şəkil 3.1-də 4, 8, 9, 6 və 7 belə düyünlərdir. Analoji olaraq, törəmə zirvələri olan ağacın düyünü daxili düyün (internal node) adlanır.

Öz törəmə zirvələrinə (child nodes) nisbətdə istənilən daxili düyün valideyn (parent node-u) adlanır. Ümumi valideynləri olan düyünlər qohum və ya bacı düyünlər (sibling nodes) adlanır. Hər hansı zirvənin alt ağacında istənilən düyün onun varisi (descendant), bu düyünlərin zirvələri isə əcdad (ancestor) adlanır.

Törəmə düyünlərin sayına düyünün dərəcəsi (node degree) deyilir.

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 137

Düyünün hündürlüyü (node height) - düyündən yarpağa qədər olan uzun yolda tillərin sayıdır.

Ağacın hündürlüyü (tree height)- kökdən yarpağa qədər olan uzun yolda tillərin sayıdır.

Düyünün dərinliyi (node depth) və ya düyünün səviyyəsi (node level)- düyündən kökə qədər olan yolda tillərin sayıdır.

Sadaladığımız anlayışları ağacın sxemində əyani aydınlaşdıraq. Şəkil 3.1-də 9 düyündən (1, 2,....9) ibarət ağac göstərilmişdir. 2 zirvəsi 4 və 5 zirvələri üçün valideyndir, 4, 5, 8 və 9 düyünləri üçün isə əcdaddır. 4 və 5 düyünləri bacıdır. 4, 6, 7, 8, 9 yarpaqlardır. Ağacın hündürlüyü 3, səviyyələrin sayı isə 4-ə bərabərdir. 5 düyününün dərəcəsi 2- yə hündürlüyü isə 1-ə bərabərdir.

Düyünləri olmayan ağac boş ağac adlanır.Ümumi növ ağacın əsas xassələri bunlardır:• kökün əcdadları olmur;• kök müstəsna olmaqla, hər bir düyünün yalnız bir

əcdadı olur;• hər bir düyün köklə yalnız bir yol ilə əlaqələndirilə

bilər, başqa sözlə, ağaclarda qapalı dövr olmur.Əgər ağacın təyinində alt ağacların nisbi sırası

əhəmiyyət kəsb edirsə, onda belə ağac nizamlanmış adlanır. Buna görə şəkil 3.2-də göstərilmiş iki nizamlanmış ağac bir- birindən fərqli, müxtəlif obyektlərdir.

Şəkil 3.2. İki nizamlanmış müxtəlif ağac

Ağaclar çox alqoritmlərdə istifadə olunur. Ağac tipli oyunlarda geniş yayılmış dörd törəmə düyünlü ağaca rast

138 Məhərrəmov Z. T., Vəliyev H.P.

gəlmək mümkündür. Toru örtmək üçün istifadə edilən kvadrantlar (quadtree) ağacında törəmə düyünləri, adətən, onlar tərəfindən örtülən istiqamətlərə görə adlandırırlar: Northwest (şimal-qərb) və ya NW, NorthEast (şimal-şərq) və ya NE, SouthWest (cənub-qərb) və ya SW və SouthEast (cənub-şərq) və ya SE.

Tarazlaşdırılmış (balanslaşdırılmış) vətarazlaşdırılmamış (balanslaşdırılmamış) ağaclar mövcuddur. Qırmızı-qara ağaclar, ABJl-ağaclar (ABJI - ağacı yaradan müəlliflərin soyadlarının baş hərfləridir) və digər ağaclar mövcuddur. Budaqlarının sayı 2-dən çox olan ağacları multivarianrlı ağaclar və ya K-ağac (K-ölçülü) adlandırırlar. Belə ağaclara B-ağaclarını (müxtəlif variantlı, məsələn, 2-3- ağac. 2-3-4-ağac, müxtəlif Bayer-MakKreyt ağacları) və s. misal göstərmək olar. K-ağacların növləri çoxdur (çoxölçüiü informasiyanı təsvir etmək üçün 40-dan çox müxtəlif ağacvari strukturlar mövcuddur: R-Tree, R+-Tree, Hilbert R- Tree, hB-Tree, hBII-Tree, BV-Tree, BD-Tree, GBD-Tree, G- Tree, SKD-Tree, kd-Tree, kd2B-Tree, BSP-Tree, LSD-Tree, P-Tree. TR-Tree, Cell-Tree, Quadtree, Grid File, Z-Hashing, SS-Tree).

Ağac o vaxt tarazlaşdırılmış adlanır ki, onun sağ və sol alt ağaclarında hər zirvə üçün düyünlərin sayının fərqi birdən çox olmasın, n düyündən ibarət tarazlaşdırılmış ağac bütün binar ağaclar içərisində ən kiçik hündürlüyə malik olur.

3.2. Binar ağaclar

Dərhal belə sual yaranır: hər düyün neçə törəmə elementlərə (budaqlara) malik ola bilər?

Əksər ağacların ikidən çox (0, 1 və ya 2) törəmə zirvələri olmur. Belə ağaclara binar (ikilik, binary tree) ağaclar deyilir. Yuxarıdakı şəkillərdə binar ağac

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 139

göstərilmişdir. Adətən, törəmə elementləri sol və sağ törəmə düyünlər adlandırırlar.

Binar ağac rekursiv strukturludur, belə ki, onun hər bir alt ağacının özü binar ağacdır və aydındır ki, onun düyünü öz növbəsində ağacın kökü olur.

Binar ağac - elə köklü ağacdır ki, onun hər düyünündə ikidən çox törəmə zirvələri olmur.

Tamam binar ağac (full binary tree) - elə binar ağacdır ki, onun hər düyünündə 0 və ya 2 törəmə düyün olur. Belə ağaca nümunə şəkil 3.1 -də göstərilmişdir.

Tamamlanmış binar ağac (complete binary tree) - elə binar ağacdır ki, onun hər səviyyəsi (sonuncu istisna ola bilər) düyünlərlə doludur, sonuncu səviyyənin doldurulması isə soldan sağa yerinə yetirilir (şəkil 3.3).

Şəkil 3.3. 10 elementdən ibarət tamamlanmış binar ağac

Mükəmməl binar ağac (perfect binary tree) - elə binar ağacdır ki. onun bütün yarpaqları eyni dərinliyə malikdir (şəkil 3.4).

Ümumi halda, ağacda saxlanılan verilənlər hər hansı bir üsulla nizamlanmaya da bilər. Amma, adətən, hər hansı

140 Mahərramov Z. T., Valiyev H. P.

prinsip üzrə nizamlama tələb olunur. Məhz bu prinsipə görə “piramidalar” və “ağaclar” bir-birindən fərqlənir:

Şəkil 3.5. Ağacların nizamlanması: a)- binar piramida, b)- binar axtarış ağacı

• piramida (heap-yığım) - verilənlərin ağacvari strukturudur və burada bir səviyyədə yerləşən bütün düyünlərin qiymətləri yuxarı səviyyədə yerləşən düyünlərin qiymətlərindən böyükdür (və ya kiçikdir, şəkil 3.5, o>);

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 141

• ağac - verilənlərin ağacvari strukturudur və burada hər hansı düyündən sağ tərəfdə yerləşən bütün düyünlərin qiymətləri sol tərəfdə yerləşən düyünlərin qiymətlərindən böyükdür, həm də bu, bütün ağac və ya onun istənilən hissəsi üçün doğrudur (şəkil 3.5, b)). Burada çox vacib dəqiqləşdir­mə etmək lazımdır: göstərilən prinsipə görə ‘‘‘'binar axtarış ağacı" (Binary Search Tree, BST) adlandırılan ağac qurulur. Bu elə ağacdır ki, burada verilənlər çox rahatlıqla, həm də yüksək səmərə ilə axtarılır.

Ağaclar bir çox sahələrdə, məsələn, informasiyanın saxlanmasında, massivlərdə elementlərin axtarılması və nizamlanması, disk daşıyıcılarında faylların saxlanılması, informasiyanın sıxılması üçün effektiv kodların (Şennon- Fano və Haffmen kodları) qurulması və s. kimi əməliyyat­ların proqramlaşdırılmasında geniş tətbiq edilir.

3.3. Ağacların yaddaşda təsviri

3.3.1. Massiv və siyahılar əsasında ağacların təsviri

Ağaclar massivlər və siyahılar şəklində çox asanlıqla təsvir edilir. Belə təsvir ağacın düyünlərindəki müvafiq elementlərə əsaslanır. Belə ki. ağacın düyünləri üçün dinamik yaddaş ayrılır və onlar ixtiyari ünvanlarda yerləşir. Hər düyün aşağıdakı sahələrdən ibarət olur:

• parent - valideyn düyününə göstərici;• lef t - sol törəmə düyünə göstərici;• right - sağ törəmə düyünə göstərici.parent valideyn düyününə göstərici vacib deyil. Bu

göstərici ağac üzrə törəmə düyünlərdən valideyn düyününə irəliləmək tələb olunduqda lazımdır. Əgər ağacın x düyünü yarpaqdırsa, onda bu sahə x.left=null və x.h=rıght olur, yəni, yarpaqlarda əcdadlara göstərici boş olur. Ağacın

142 Məhərrəmov Z.T., Vəliyev H.P.

belə təsvirində ağacın kökü olan düyünə göstərici saxlanmalıdır.

3.3.1.1. Massivlər əsasında təsvir

N düyündən ibarət tamamlanmış ağacı uzunluğu n olan A[n] massivində yerləşdirmək olar.

İzahatların aydın olması üçün fərz edək ki, massivdə elementlərin indeksləşməsi 1-dən başlanır (xatırladırıq ki, bir çox dillərdə, o cümlədən C# dilində massivin indeksi O-dan başlayır). Ağacın bütün düyünləri onların eninə dolanmaqla (dövrə vurmaqla) massivin xanalarında yerləşir. Ağacın kökü massivin birinci xanasında saxlanılır. ı xanasında yerləşdirilmiş istənilən zirvə üçün sol törəmə düyün 2i mövqeyində, sağ törəmə düyün isə 2i~ 1 mövqeyində yerləşdirilir, i zirvəsinin valideyn düyünü [ı’/2J xanasında yerləşir ([i/2] - bölmə əməlinin tam hissəsi deməkdir). Əgər 2i və ya 2i + 1 qiymətləri w-dən böyük olarsa, onda i zirvəsində müvafiq törəmə düyün yoxdur. Şəkil 3.6-da şəkil 3.3-də göstərdiyimiz ağacın massiv şəklində təsviri təqdim edilmişdir.

Şəkil 3.6. Şəkil 3.3-də göstərilmiş tamamlanmış binar ağacın A[10] massivi şəklində təsviri

Natamam binar ağaclar aşağıdakı üsulla təsvir edilir. Binar ağac tam ağaca qədər tamamlanır, zirvələr ardıcıl nömrələnir. Massivə yalnız ilkin natamam ağacda olan zirvələr daxil edilir. İlkin binar ağacda olmayan zirvələr massivdə fərqləndirilməlidir. Bunu massivin uyğun element-

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 143

iərinə xüsusi qiymət, adətən, 0 daxil etməklə yerinə yetirmək olar. Nəticədə ağac strukturu birölçülü massivlə təsvir edilir (şəkil 3.7).

Şəkil 3.7. Natamam binar ağacın massiv şəklində təsviri

Massivdə istənilən zirvənin ünvanını ünvan = 2k — 1 + i — 1

düsturu ilə hesablamaq olar, burada, A:-zirvənin səviyyəsinin nömrəsi, i - tamam binar ağacda k səviyyəsində nömrədir. Kökün ünvanı vahidə bərabər olur. İstənilən zirvə üçün sol və sağ nəsillərin ünvanlarını, müvafiq olaraq, belə hesablamaq olar:

Ljinvan = 2k + 2(İ —1),R_ünvan = 2k + 2(ı — 1) + 1.Yaddaşın ardıcıl xanalarında binar ağacların təsvir

edilməsinin üstünlüyü həm əcdaddan nəslə, həm də nəsildən əcdada girişin sadəliyində, çatışmazlığı isə. əgər ağac tamam deyilsə (natamamdırsa), massivdə çoxlu miqdarda boş elementlərin olmasındadır (şəkil 3.7). Massivin ölçüsünün məhdud olması ağaca yeni düyünlərin əlavə edilməsini çətinləşdirir, belə ki, bu halda massivin ölçüsünü dəyişdirmək lazım gəlir. Ağacdan düyünün silinməsi və onun strukturunun

144 Məhərrəmov Z. T., Vəliyev H.P.

müvafiq dəyişiklikləri də həmçinin massivin tərkibinin modifıkasiya edilməsini tələb edir.

Binar ağacın baxdığımız təsviredilmə üsulunun əsas çatışmazlığı verilənlərin strukturunun statik olmasındadır. Massivin ölçüsü binar ağacın səviyyələrinin maksimal mümkün miqdarına əsaslanaraq seçilir. Həm də ağac nə qədər natamam olarsa, yaddaş bir o qədər az səmərəli istifadə olunur.

3.3.1.2. Siyahılar əsasında təsvir

Binar ağaclar siyahılar əsasında kifayət qədər asanlıqla təsvir edilir. Yadda saxlamaq lazımdır ki, ağac informasiyanın yaddaşda məntiqi təşkilidir, yaddaş özü isə xəttidir. Ağac yaddaşda təsvir olunduqda onun düyünləri açar və informasiyadan (veriləndən) ibarət olur. Əgər informasiya yaddaşın ixtiyari yerində (proqramçıya məlum olmayan) saxlanarsa, onda ağacın ümumiləşmiş strukturu şəkil 3.8-də göstərilmiş qaydada təsvir edilə bilər:

AçarVerilən

Sol Sağ

Şəkil 3.8. Ağacın düyününün ümumiləşmiş strukturu

Binar ağacların siyahı kimi təsviri ağacın müvafiq düyünlərinə uyğun elementlərinə əsaslanır. Hər element verilənlər sahəsindən və iki göstərici sahələrindən ibarət olur. Göstəricilərdən biri elementi sağ, digəri isə sol nəsillə əlaqələndirmək üçün istifadə olunur. Yarpaqlar nəsillərin boş göstəricilərinə malik olur. Ağacın belə təsvir üsulunda ağacın kökü olan düyünə göstəricini mütləq saxlamaq lazımdır.

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 145

Şəkil 3.9-da binar ağac və onun siyahı şəklində təsviri göstərilmişdir.

İxtiyarı ağacı da siyahı şəklində təsvir etmək mümkündür. Bu zaman siyahıda ikidən çox göstərici olur və ağac çox əlaqəli və ya multi siyahılar şəklində təsvir edilir. Bellə təsvir nümunəsi şəkil 3.10-da göstərilmişdir.

Şəkil 3.9. Binar ağacın siyahı şəklində təsviri

Şəkil 3.10. İxtiyar ağacın multi siyahı şəklində təsviri

3.4. Binar ağaclarda dövrə vurma

Ağaclardan istifadə edən bir çox alqoritmlərdə kökdən başlayaraq onun bütün düyünlərini araşdırmaq zərurəti yaranır. Belə prosedur ağaca dövrə vurma (tree traversal, dolanma, baş çəkmək) adlanır. Hər zirvəyə bir dəfə baş

146 Məhərrəmov Z.T., Vəliyev H.P.

çəkilməlidir. Zirvəyə baş çəkmək müəyyən hesablamaların icra edilməsi və ya onlarda saxlanılan verilənlərin emalı ilə əlaqədar ola bilər.

Binar ağacın eninə və dərinliyinə dövrə vurmaq olar. Ağaca dövrə vurmanın bütün üsulları kökə baş çəkməkdən başlayır.

Eninə dövrə vurmada (brcadth fırst search, BFS) ağacın düyünlərinə soldan sağa, səviyyədən səviyyəyə keçməklə baş çəkilir. Məsələn, şəkil 3.3-də göstərilmiş ağaca eninə dövrə vurma vaxtı zirvələrə aşağıdakı ardıcıllıqla baş çəkiləcək:

1,2,3, 4, 5, 6, 7, 8, 9,10.Dərinə dövrə vurmada (depth fırst search, DFS)

əvvəlcə sol alt ağacın törəmə zirvələrinə baş çəkilir, yalnız bundan sonra cari düyünün sağ alt ağacına keçilir.

Ağaca dərinliyə dövrə vurmanın üç üsulu mövcuddur. Onlar zirvələrə və onların törəmə düyünlərinə baş çəkilməsi ardıcıllığına görə bir-birindən fərqlənir.

1. Düz ardıcıllıqla dövrə vurma (pre-order traversal, ön şəkilçili dövrə vurma) - düyünün nəsillərinə rekursiv baş çəkilənə qədər hər düyünə baş çəkilir. Hər bir x düyünü üçün aşağıdakı rekursiv əməllər ardıcıllığı yerinə yetirilir: x düyününə baş çəkmək; sol alt ağacı dolanmaq; sağ alt ağacı dolanmaq. Şəkil 3.3-də göstərilmiş ağacda belə dövrə vurduqda onun düyünlərinə aşağıdakı ardıcıllıqla baş çəkiləcək:

1,2,4, 8, 9,5,10,3, 6, 7.2. Simmetrik dövrə vurma (in-order traversal, infıks

dövrə vurma) - əvvəlcə sol alt ağacın düyünün nəsillərinə baş çəkilir, sonra düyünün özü və daha sonra isə sağ alt ağacın nəsillərinə baş çəkilir. Hər bir x düyünü üçün aşağıdakı rekursiv əməllər ardıcıllığı yerinə yetirilir: sol alt ağacı dolanmaq, x düyününə baş çəkmək, sağ alt ağacı dolanmaq. Şəkil 3.3-də göstərilmiş ağacda simmetrik dövrə vurduqda onun düyünlərinə aşağıdakı ardıcıllıqla baş çəkiləcək:

8. 4, 9,2,5,10,1,6, 3, 7.

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 147

3. Əks ardıcıllıqla dövrə vurma (post-order traversal, postfiks dövrə vurma) - düyünün nəsillərinə rekursiv baş çəkildikdən sonra hər düyünə baş çəkilir. Hər bir x düyünü üçün aşağıdakı rekursiv əməllər ardıcıllığı yerinə yetirilir: sol alt ağacı dolanmaq, sağ alt ağacı dolanmaq, x düyününə baş çəkmək. Şəkil 3.3-də də göstərilmiş ağacda əks ardıcıllıqla dövrə vurduqda onun düyünlərinə aşağıdakı ardıcıllıqla baş çəkiləcək:

8.9, 4.10, 5,2,6, 7,3, 1.

3.4.1. Dövrə vurma əməliyyatlarının kompüterdə reallaşdırılması

Yuxarıda baxdığımız dövrə vurma əməliyyatlarını kompüterdə müşahidə edək. Bunun üçün P.Deytel və X.Deytelin kitabında (düşünürük C# dilinə aid yazılmış ən yaxşı kitablardan biridir) tərtib edilmiş alqoritmdən istifadə edək. Əvvəlcə həmin proqramı olduğu kimi təqdim edək (yalnız şərhlər tərcümə edilmişdir):

using System;namespace BinaryTreeLibrary2 {// TreeNode sinfinin elan edilməsi class TreeNode<// Avtomatik reallaşdırılan// LeftNode xassəsiPublic TreeNode LeftNode { get; set; }

// Avtomatik reallaşdırılan Data xassəsiPublic IComparable Data { get; set; }

// Avtomatik reallaşdırılan// RightNode xassəsiPublic TreeNode RightNode { get; set; }

148 Məhərrəmov Z.T., Vəliyev H.P.

// Data xassəsiin inisiallaşdırılması və // yarpaq düyününün formalaşdırılması Public TreeNode(IComparable nodeData) {Data = nodeData;LeftNode = RightNode = null; // Düyündə

// törəmə düyün yoxdur} // Konstruktorun sonu

/* Düyünləri olan ağacaTreeNode obyektinin qoyulması dublikatlar (təkrar olunanlar) nəzərə alınmır */

Public void Insert(IComparable insertValue)

{// Sol alt ağaca yerləşdirməif (insertValue.CompareTo(Data) < 0)

(// new TreeNode3 əlavə edilməsiıf (LeftNode == null)

LeftNode = new TreeNode( insertValue);

else// sol alt ağaca keçid davam edir

LeftNode.Insert(insertValue);) // if sonuelseif (insertValue.CompareTo(Data)>0)

// Sol alt ağaca {

// yeni TreeNode obyektinin// əlavə edilməsiif (RightNode == null)

RightNode = new TreeNode( insertValue);

else // sağ alt ağaca keçid davam edirRightNode.Insert(insertValue);

// else if sonu

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 149

) // Insert metodunun sonu) // TreeNode sinfinin sonu

// Tree sinfinin elan edilməsi Public class Tree ( private TreeNode root;

// IComparable obyektli boş ağacın// konstruksiya edilməsiPublic Tree () { root = null;

} // Konstruktorun sonu

/* Binar axtarış ağacına yeni düyünün qoyulmasıƏgər kök düyününə göstərici null olarsa, kök düyününü yaratmaq Əks halda TreeNode sinfinin Insert metodu çağrılır */ Public void InsertNode(IComparable

insertValue) (

if (root == null) root = new TreeNode(insertValue);

elseroot.Insert(insertValue);

) // InsertNode metodunun sonu

//duzünə dövrə vurmanın başlanması Public void PreorderTraversal() (PreorderHelper(root);

} // PreorderTraversal metodunun sonu

// Düzünə dövrə vurmanın icrası// üçün rekursiv metod private void PreorderHelper(

Məhərrəmov Z. T., Vəliyev H.P.ISO

TreeNode node) (

if (node != null) {Düyünün verilən, ekrana çıxarılması Console.Write(node.Data + " ");

f Sol alt ağaca dövrə vurma PreorderHelper(node.LeftNode);

// Sağ alt ağaca dövrə vurma PreorderHelper(node.RightNode);

} // if sonu> // PreorderHelper metodunun sonu

// Simmetrik dövrə vurmanın başlanması Public void InorderTraversal() {InorderHelper(root);// InorderTraversal metodunun sonu

// Simmetrik dövrə vurmanın icrası// üçün rekursiv metodPtivate void InorderHelper(

TreeNode node) {

if (node != null) {

'/ Sol alt ağaca dövrə vurma InorderHelper(node.LeftNode);

'/ Düyünün verilənlərinin// ekrana çıxarılması

Console.Write(node.Data + " ");// Sağ alt ağaca dövrə vurma

InorderHelper(node.RightNode);} // if sonu

} // InorderHelper metodunun sonu

// Əksinə dövrə vurmanın başlaması Public void PostorderTraversal!) {

üçüncü fasü. Verilənlərin qeyri-xətti dinamik strukturları 151

PostorderHelper(root);} // PostorderTraversal metodunun sonu

// Əksinə dövrə vurmanın icrası// üçün rekursiv metodPrivate void PostorderHelper(

TreeNode node) { if (node != null) {

// Sol alt ağaca dövrə vurmaPostorderHelper(node.LeftNode);

// Sağ alt ağaca dövrə vurmaPostorderHelper(node.RightNode);

// Düyünün verilənlərinin// ekrana çıxarılması

Console.Write(node.Data + " ");} // if sonu

)// PostorderHelper metodunun sonu )// class Tree sinfinin sonu

class Program {public static void Main(string[] args) iint[] intArray={8, 2, 4, 3, 1, 7, 5, 6};

double[] doubleArray ={8.8,2.2,4.4,3.3,1.1,7.7,5.5,6.6);

string[] stringArray = ("Sekkiz", "iki", "Dord", "Doqquz",

"Bır", "Yeddi", "On", "Alti" );

// int tipli ağacın yaradılması Tree intTree = new Tree () ;PopulateTree(intArray,

intTree, "intTree");TraverseTree(intTree, "intTree");

152 Məhərrəmov Z.T., Vəliyev H.P.

// double tipli ağacın yaradılması Tree doubleTree = new TreeO; PopulateTree(doubleArray,

doubleTree, "doubleTree");TraverseTree(doubleTree, "doubleTree");

// string tipli ağacın yaradılması Tree stringTree = new Tree();PopulateTree(stringArray,

stringTree, "stringTree");TraverseTree(stringTree, "stringTree");

Console.Read();) // Main sonu

// Massivin elementləri ilə// ağacın doldurulmasıprivate static void PopulateTree(Array

array, Tree tree, string name) {Console.WriteLine(”\n\n" + name +

" agacinin yaradılmasi:");

foreach (IComoarable data ın array) {Console.Write(data + " ");tree.InsertNode(data);

) // foreach sonu) // PopulateTree metodunun sonu

// Ağaca dövrə vurmalarprivate static void TraverseTree(

Tree tree, string treeType)

// ağacda düzünə dövrə vurmanın icrasıConsole.WriteLine("\n\n" +treeType +

" agacinda enine dovre vurma");tree.PreorderTraversal();

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 153

// ağacda simmetrik dövrə // vurmanın icrasıConsole.WriteLine("\n\n"+treeType+ "

agacinda duz ardicilliqla dovre vurma ");

tree.InorderTraversal();

// ağacda əks dövrə vurmanın icrası Console.WriteLine("\n\n"+ treeType+"

agacinda eks ardicilliqla dovre vurma");

tree.PostorderTraversal();) // TraverseTree metodunun sonu) // Program sinfinin sonu}

Bu proqram binar ağac yaradır və ona üç üsulla: rekursiv simmetrik, düz və əks istiqamətlərdə dövrə vurur.

TreeNode sinfi üç TreeNode tipli LeftNode, RightNode və int tipli Data xassələrindən ibarət özünə aid olan sinifdən ibarətdir. Başlanğıcda hər bir TreeNode obyekti yarpaq düyünündən ibarətdir, ona görə də konstruktor LeftNode və RiqhtNode göstəricilərinə null qiyməti verməklə onları inisiallaşdırır. TreeNode sinfinin Insert metoduna sonra baxacağıq.

Tree sinfi TreeNode sinfinin obyektləri ilə işləyir, root bağlı dəyişəni ağacın kök düyününə göstəricidən ibarətdir. InsertMode açıq metodu ağaca yeni düyün qoyur, PreorderTraversal. InorderTraversal və PostorderTraversal açıq metodları ağaca dövrə vurmağa başlayır. Bu metodların hər biri ağacın daxili təsvirinə dövrə vurma əməliyyatının icra edilməsi üçün ayrı köməkçi rekursiv metod çağırır. Tree konstruktoru root dəyişənini null qiyməti ilə inisiallaşdırır; bu onu göstərir ki, ağacın ilkin vəziyyətində ağacın düyünləri yoxdur.

154 Məhərrəmov Z. T., Vəliyev H.P.

InsertNode metodu əvvəlcə ağacın boş olmasını yoxlayır. Əgər ağacda düyünlər yoxdursa, onda root=new TreeNode(insertValue); kodu yeni TreeNode obyektini yaradır, ağaca yerləşdirilmiş düyünü inisializasiya edir və yeni düyünü root-a mənimsədir. Əgər ağac boş deyilsə, onda InsertNode metodu TreeNode sinfinin Insert metodunu çağırır. Bu metod ağacda yeni düyünün mövqeyini rekursiv müəyyən edir və düyünü bu mövqeyə qoyur. Binar axtarış ağacında düyün yalnız yarpaq kimi qoyula bilər.

TreeNode sinfinin Insert metodu qoyulan qiyməti kök düyününün verilənlərində saxlanan qiymətlə müqayisə edir. Əgər qoyulan qiymət kök düyününün verilənlərindən kiçik olarsa, proqram sol alt ağacın boş olmasını yoxlayır (if (LeftNode==null)). Əgər o boşdursa, onda LeftNode=new TreeNode(insertValue); kodu ye­ni TreeNode düyününü yaradır, onu qoyulan qiymətlə inisializasiya edir və yeni düyünün obyektini LeftNode göstəricisinə mənimsədir. Əks təqdirdə LeftNode.Insert(insertValue); kodu sol alt ağaca yerləşdirmə prosedurunu təkrarlamaq üçün rekursiv olaraq Insert metodunu sol alt ağac üçün çağırır. Əgər qoyulan qiymət kök düyününün verilənlərindəm böyük olarsa, onda proqram sağ alt ağacının boş olmasını yoxlayır (if (RightNode==null)). Əgər o boşdursa, onda RightNode=new TreeNode(insertValue); kodu yeni TreeNode düyününü yaradır, onu qoyulan qiymətlə inisializasiya edir və yeni düyünün obyektini RightNode göstəricisinə mənimsədir. Əks təqdirdə RightNode . Insert (insertValue) ; kodu sağ alt ağaca yerləşdirmə prosedurunu təkrarlamaq üçün rekursiv olaraq Insert metodunu sağ alt ağac üçün çağırır. Əgər qoyulan qiymət mövcud düyünün qiyməti ilə eyni olarsa, ona məhəl qoyulmur.

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 155

InorderTraversal, PreorderTraversal və PostorderTraversal metodları ağaca dövrə vurma və düyünlərin qiymətlərinin çıxardılması üçün müvafiq olaraq köməkçi InorderHelper PreorderHelper və PostorderHelper metodlarını çağırır. Tree sinfinin köməkçi metodları ona görə lazımdır ki, proqramçı kök düyününə ilkin istinad almadan və bu istinadla rekursiv metodunu növbəti dəfə çağırmadan dövrə vurmağa başlaya bilsin. InorderTraversal, PreorderTraversal və PostorderTraversal metodları sadəcə olaraq ağaca dövrə vurmanın başlanması üçün bağlı root dəyişəninin qiymətini müvafiq köməkçi metoda verir.

Dövrə vurma əməliyyatları aşağıdakı alqoritmlərlə yerinə yetirilmişdir.

Simmetrik dövrə vurma alqoritmiInorderHelper metodu simmetrik dövrə vurmada

aşağıdakı əməliyyatlar ardıcıllığını müəyyən edir:1. Əgər arqument null qiymətinə bərabərdirsə, ağac

emal edilmir;2. InorderHelper metodunu çağırmaqla

(InorderHelper (node.LeftNode);) sol alt ağaca keçmək;

3. Düyündə qiyməti emal etmək (Console. Write (node. Data + " " ) ;);

4. InorderHelper metodunu çağırmaqla (InorderHelper(node.RightNode);) sağ alt ağaca keçmək.

Simmetrik dövrə vurmada düyünün qiyməti yalnız sol alt ağacın qiymətləri emal edildikdən sonra emal edilir.

Binar axtarış ağacına simmetrik dövrə vurduqda qiymətlər artma sırası ilə nizamlanmış şəkildə ekrana çıxarılır. Binar axtarış ağacının yaradılması prosesində (simmetrik dövrə vurmaya uyğun olaraq) verilənlər nizamlanır, bu proses isə binar ağacın nizamlanması adlanır.

156 Məhərrəmov Z.T., Vəliyev H.P.

Düz istiqamətdə dövrə vurma alqoritmiPreorderHelper metodu düz istiqamətdə dövrə

vurmada aşağıdakı əməliyyatlar ardıcıllığını müəyyən edir:1. Əgər arqument null qiymətinə bərabərdirsə, ağac

emal edilmir;2. Düyündə qiyməti emal etmək (Console . Write

(node .Data + " " ) ;);3. PreorderHelper metodunu çağırmaqla

(PreorderHelper (node . LeftNode) ;) sol alt ağaca keçmək;

4. PreorderHelper metodunu çağırmaqla (PreorderHelper (node . RightNode ) ;) sağ alt ağaca keçmək.

Düz istiqamətdə dövrə vurmada hər düyünün qiyməti ona baş çəkmə zamanı emal edilir. Verilmiş düyündə qiymət emal edildikdən sonra, əvvəlcə sol alt ağacın qiymətləri, sonra isə sağ alt ağacın qiymətləri emal edilir.

Əks istiqamətdə dövrə vurma alqoritmiPostorderHelper metodu əks istiqamətdə dövrə

vurmada aşağıdakı əməliyyatlar ardıcıllığını müəyyən edir:1. Əgər arqument null qiymətinə bərabərdirsə, ağac

emal edilmir;2. PostorderHelper metodunu çağırmaqla

PostorderHelper(node.LeftNode) ; sol alt ağaca keçmək.

3. PostorderHelper metodunu çağırmaqla PostorderHelper (node . LeftNode) ; sağ alt ağaca keçmək.

4. Düyündə qiyməti emal etmək (Console . Write ( node. Data + " " ) ;).

Əks istiqamətdə dövrə vurma zamanı hər düyünün qiyməti onun bütün törəmə düyünlərinin qiymətləri emal edildikdən sonra emal edilir.

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 157

Təkrarlanmanın aradan qaldırılmasıBinar axtarış ağacı təkrarlanmanın aradan

qaldırılmasını avtomatik təmin edir. Ağac qurulduqda yerləşdirmə əməliyyatı təkrarən yerləşdirmə cəhdlərini tanıyır, çünki hər müqayisə vaxtı təkrarlanan qiymət ilkin qiymətin tabe olduğu “sola keç" və ya "sağa keç" qaydalarına riayət edir. Beləliklə, yerləşdirmə əməliyyatı yekunda təkrarlanan qiyməti düyündəki həmin qiymətlə müqayisə edir. Bu mərhələdə yerləşdirmə əməliyyatı təkrarlanan qiyməti sadəcə olaraq tullaya bilər.

Tərtib edilmiş proqramı icra etmək üçün, koddan göründüyü kimi, binar ağacla əməliyyat aparmağa imkan verən Tree sinfi əsasında Main metodu tərtib edilmişdir. Main metodunda Tree sinfinin boş nüsxəsi yaradılmış və sonra Tree sinfinin InsertNode metodu ilə elementləri int (tam), double (həqiqi) və string (sətir) tipli olan qiymətlərlə ağac doldurulur. Proqram ağacı intArray, doubleArray və stringArray massivlərinin qiymətləri ilə doldurur. Ağacın belə müxtəlif tipli elementlərlə doldurulması üçün obyektyönlü proqramlaşdırmanın əsas prinsiplərindən olan polimorfizm istifadə edilmişdir. TreeNode və Tree siniflərinin müxtəlif tipli obyektlərlə işləyə bilməsi üçün IComparable interfeysi (System adlar fəzasına daxildir) istifadə edilmişdir. IComparable interfeysini reallaşdıran siniflərdə obyektləri müqayisə etmək üçün CompareTo metodu müəyyən etmişlər. Bu metodu çağırdıqda dəyişənlər arqumentlərlə ona ötürülür. Proqramda CompareTo metodunu istifadə etməklə Icomparable obyektləri müqayisə edilir, bundan sonra metodun qaytardığı qiyməti yoxlayır: sıfırdan kiçikdir (çağıran obyekt obyekt- arqumentdən kiçikdir) və ya sıfırdan böyükdür (çağıran obyekt obyekt-arqumentdən böyükdür).

PopulateTree metodu öz arqumentləri ilə qiymətlərdən ibarət massiv, massivin elementləri yerləşəcək

158 Məhərrəmov Z.T., Vəliyev H.P.

Tree obyekti və Tree adlı sətir alır və bundan sonra bu elementlər ağaca yerləşdirilir. TraverseTree metodu Tree obyekti və Tree adlı sətir alır və bundan sonra ağac boyu düz istiqamətdə, simmetrik və əks istiqamətdə dövrə vurmanın verilənlərini ekrana çıxarır (şəkil 3.11).

■ ■ F:\ZAKIR\VSA\OBXOD\OBXOD\bin\Debug\OBXOD.exe 1 ■=' I

İntTree agacinin yaradilnasi: 12 4 3 1 7 5 6

İntTree agacinda duz ardicllllqla dovre uurna 12 1 4 3 7 5 6

İntTree agacinda sinnetrik dovre vurna 12 3 4 5 6 7 8

İntTree agacinda eks ardicllllqla dovre vurna 13 6 5 7 4 2 8

loubleTree agacinin yaradilnasi: 1,8 2.2 4,4 3.3 1,1 7.7 5.5 6.6

loubleTree agacinda duz ardicllllqla dovre vurna 1,8 2,2 1,1 4,4 3,3 7,7 5.5 6,6

loubleTree agacinda sinnetrik dovre vurna 1,1 2,2 3,3 4,4 5,5 6.6 7,7 8,8

loubleTree agacinda eks ardicllllqla dovre vurna 1,1 3.3 6.6 5.5 7,7 4,4 2,2 8.8

ıtringTree agacinin yaradilnasi: tekkiz iki Dord Doqquz Bir Yeddi On Alti

ıtringTree agacinda duz ardicllllqla dovre vurna iekkiz iki Dord Doqquz Bir Alti On Yeddi

ItringTree agacinda sinnetrik dovre vurna llti Bir Doqquz Dord iki On Sekkiz Yeddi

ıtringTree agacinda eks ardicllllqla dovre vurna llti Bir Doqquz Dord On iki Yeddi Sekkiz _

Şəkil 3.11. Elementləri tam, həqiqi və sətir tipli olan ağac üzərində əməliyyatların nəticələri

Hər Tree obyektinə simmetrik dövrə vurmada ağacda saxlanan verilənlərin tipindən asılı olmayaraq onları nizamlanmış şəkildə ekrana çıxarır. Hər qiymətin mövqeyə

Üçüncü fəsil. Veril,inlərin q ey r i-xətti dinamik strukturları 159

yerləşdirilməsi üçün Tree sinfinin polimorf realizasiyası verilənin tipinə uyğun Compare.To metodunu çağırır. Nəticədən görünür ki, sətir tip verilənlər də nizamlanmışdır.

3.5. Ağaclar üzərində əməliyyatlar və onların kompüterdə reallaşdırılması

Siyahılar üzərində aparılan elementin əlavə edilməsi, silinməsi, elementə keçmə (baxış) və elementlərin axtarışı kimi əsas əməliyyatlar ağaclar üzərində də aparıla bilər.

Binar axtarış ağacları çoxluqları (set) və assosiativ massivləri (associative array) reallaşdırmaq üçün nəzərdə tutulmuşdur (assosiativ massivlərə lüğətlər (dictionaries) də deyirlər). Assosiativ massivlər çoxluqlardan onunla fərqlənir ki, massivlərdə yalnız açarlar saxlanır, assosiativ massivlərdə isə hər açarla yanaşı müəyyən qiymət də saxlanır.

Binar axtarış ağacının strukturu ağacın düyünlərində yerləşən bütün açarları effektiv nizamlı araşdırmağa imkan verir. Ona görə də belə ağaclar verilənlərin abstrakt tiplərinin reallaşdırılması üçün nizamlanmış çoxluqdan (ordered set) geniş istifadə edir.

Binar axtarış ağacı (binary search tree) - elə binar ağacdır ki, onun hər düyünü açara (key) malikdir, həm də sol alt ağacın düyünlərindəki açarlar valideyn düyünündəki açardan kiçik, sağ alt ağacın düyünlərindəki açarlar isə valideyn düyününün açarından böyükdür.

Binar ağaclarda aparılan əməliyyatlarda ən çox açarların müqayisəsi əməliyyatı yerinə yetirilir. Bir qayda olaraq verilənlərin baza tipləri (tam, həqiqi ədədlər, simvol, məntiqi) üçün müqayisəetmə əməliyyatı 0(1) vaxtı ərzində yerinə yetirilir. Əgər açar tərkibli tipə (məsələn, sətir) aid olarsa, onda əməliyyatın hesablama mürəkkəbliyi açarın uzunluğundan asılı olacaqdır.

160 Məhərrəmov Z.T., Vəliyev H.P.

Şəkil 3.12-də düyünlərində açarların qiymətləri yazılmış binar axtarış ağacının nümunəsi göstərilmişdir.

Şəkil 3.12. 7 düyündən ibarət binar axtarış ağacı

Binar axtarış ağacının tərifinə görə, onun düyünlərində eyni açarlı iki düyün ola bilməz.

Binar axtarış ağacının üstünlüyü: əgər ağac nizamlanmışdırsa (bu ağac məhz belədir), onda axtarış əməliyyatı binar axtarışın effektivliyinə yaxın effektivliklə çox tez yerinə yetirilir.

Binar axtarış ağacının imkan verdiyi əməliyyatların bəziləri ilə tanış olaq.

3.5.1. Düyünlərin yaradılması və əlavə edilməsi

İnformasiyanı daxil etməklə binar axtarış ağacının yaradılması prosesinə baxaq. Tutaq ki, qiymətləri 70, 60, 85, 87, 90, 45, 30, 88, 35, 20, 86, 82 olan açarlardan ibarət ardıcıl informasiya daxil edilir.

1.70 - kök (birinci düyün);

Üçüncü fiıxil. Venbulzrin qeyri-xətti dinamik strukturları 161

2. 60 < 70 olduğu uçun, aydındır ki. yeni düyün 70- dər. solda yerləşdinləcək;

3. 85 70. deməli. yeni düyün 70-dən sağdayerləşdiriləcək;

4. 87 > 70. deməli. 87 sağ budaqda yerləşdiriləcək:5. 87 •> 85, deməli, 87 ədədi 85 ədədindən sağda

■ ərləşdiriləçək, və s. (şəki! 3.13).

Səkilə 13. Binas m- İmiş ağacının ı. ..ırmmmas!

Mövcud binar avtanş əMem.' ' əmarlı yem düyün əlavə eldikdə elə yarpaq tapmaq f<rndir ki. o yeni düşün üçün valideyn olsun. Belə yarptğm axtarışı kökdən başlayıı. Əgər yem əlavə edilən A açarı cari düyünün açarından kiçik olarsa, onda sol törəmə düyün cari düyün edilir əM halda sağ Mrəmə element cari element olur. Ağac bovımca emş car düyün rrc 11 qivməlini alana kimi '.Livanı edir Ru c deməkdir kı. biz yarpağa çatmışıq Bundan sonra, tapılmış ••■arpağa msbəldə təmmə (dan xcm du :. yəıadıiır.

162 Məhərrəmov Z. T., Vəliyev H.P.

Binar axtarış ağacına yeni düyünün əlavə edilməsi əməliyyatının hesablama mürəkkəbliyi açarların müqayisə edilməsinin sayından asilidir. Yeni zirvə üçün yarpaq düyününü axtardıqda bizə 0(h) qədər müqayisə tələb olunur, butada, h - binar axtarış ağacının hündürlüyüdür. Beləliklə, binar axtarış ağacına yeni düyünün əlavə edilməsi əməliyyatının hesablama mürəkkəbliyi O(h) təşkil edir.

İndiyə kimi baxdığımız strukturların əksəriyyətindən fərqli olaraq ağaclarla işləmək üçün C# dilində xüsusi siniflər yoxdur. Ağaclar üzərində yerinə yetiriləcək əməliyyatları biz özümüz proqramlaşdırmalıyıq. Ona görə də ağacın yaradılması və düyünün əlavə edilməsi üçün sinif yaradaq. BinarAgac adlandırdığımız sinif aşağıdakı verilənlərdən ibarətdir:

• verilənlər - tam tipli ədədlər (long?, ? simvolu dəyişənin null qiyməti ala bilməsi üçündür);

• sol düyünün qiymətləri;• sağ düyünün qiymətləri;• valideyn (kök elementində olmayacaq).Bu verilənlər aşağıdakı metodlarla emal ediləcək:

public long? Data { get; private set; }public BinarAgac SOL { get; set; }public BinarAgac SAG { get; set; }public BinarAgac Valideyn { get; set; )

Əvvəlcə elementi (tam ədədləri) binar ağaca yerləşdirək:

public void Insert(long data){if (Data == null II Data == data){Data = data; return;

}

I çütıcii fasii. l'erifoıılsrin qeyri-xvtti dinamik strukturları 163

; ' 30J.-=n:J■ SGL=new BinarAgac: ( - ; 1»,sert ■ aata, S-..L, rb.ıs)

,ı » AG==n.jt' S«G-.m<ı B ■ r.ar.Aga . ') ; i nsert ..data, 3AG,

Bu metodda cari düyün üçün -ota qiymətinin verilməsi çoxlarım. əgər bu qiymət verilməmişdirsə və ya ağacda olan qiymətlə eynidinsə. onda carı qiymət həmin qiymətlə əvəz olunur. Əgər cari düyün üçün qiymət artıq •.uilmişdmsə, onda biz yoxlamalıyıq ki. qiyməti gələcəkdə hansı budağa qoymaq lazımdır Bunun üçün qoyulan qiyməti car' qiymətlə müqayisə etmək lazımdır, əgər cari qiymət böyükdürsə. onda onu sol. əks lıaida isə s.ığ budağa qoymaq lazımdır.

Ağaca yem düyün əlavə etmək və valideyn elementini vermək üçün həmin, metodun yenidən yüklənməsi metodunu yaradırıq.

uıivate vcj.'d Irsrr*: ı ionq da‘.d, ScnnrAşi.r n_ae, BinarAgac paren.t ;

u. : n<?de . f;.d • qat^ ;

164 Məhərrəmov Z. T., Vəliyev H. P.

{if (node.SOL == null)

node.SOL = new BinarAgac();Insert (data, node.SOL, node);

) else ı

if (node.SAG == null)node.SAG = new BinarAgac();

Insert(data, node.SAG, node); ) )

private void Insert(BinarAgac data, BinarAgac node, BinarAgac parent)

(if (node.Data == null I|

node.Data == data.Data){ node.Data = data.Data; node.SOL = data.SOL; node.SAG = data.SAG; node.Valideyn = parent; return;

)if (node.Data > data.Data) {

if (node.SOL == null) node.SOL = new BinarAgac();

Insert(data, node.SOL, node);) else {

if (node.SAG == null) node.SAG = new BinarAgac();

Insert(data, node.SAG, node);) )

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 165

3.5.2. Düyünlərin sayının hesablanması

Yuxarıdakı kodla ağacın yaradılması başa çatır. Lakin biz, ağacdakı elementlərin sayma nəzarət edə bilməyimiz üçün aşağıdakı kodu yazaq:

private long CountElements(BinarAgac node)

(long count = 1;if (node.SAG != null) {count += CountElements(node.SAG);

}if (node.SOL != null) {count += CountElements(node.SOL) ;

) return count; })

3.5.3. Əməliyyatların nəticələrinin müşahidə edilməsi

Ağaca aid əməliyyatların nəticələrini müşahidə edə bilmək üçün sinif yaradaq:

// Nəticələrin ekranda təsviri// üçün sinifPublic class AgacGoster {Public static void Print(BinarAgac node) { if (node != null) { if (node.Valideyn == null)

166 Məhərrəmov Z.T., Vəliyev H.P.

Console.WriteLine("AĞACIN KOKU (root):{0)", node.Data);

else (if (node.Valideyn.SOL == node) {Console.WriteLine("Sol alt agac {1} -->

{0}", node.Data, node.Valideyn.Data);}if (node.Valideyn.SAG == node) {Console.WriteLine("Sag alt agac {1} -->

{0}", node.Data, node.Valideyn.Data); ) ) if (node.SOL != null)

Print(node.SOL); } if (node.SAG != null) ( Print(node.SAG); ) ) } }

Bu sinif və metodları vahid bir proqramda birləşdirib aşağıdakı proqramla nəticələri ala bilərik:

class Program {static void Main(string[] args)

var tree = new BinarAgac();tree.Insert(20) ; tree.Insert (40); tree.Insert (10); tree.Insert (30); tree.Insert(80);

Üçüncü fəsil. Verilənlərin qeyri-xətli dinamik strukturları 167

tree.Insert(29);tree.Insert(31) ;tree.Insert(32) ;tree.Insert(70) ;

Console.WriteLine("Yaradilmis agac\n");AgacGoster.Print(tree);Console.WriteLine("Ağacda elementlərin

sayi= "+tree.CountElements());

Console.WriteLine();Console.WriteLine(("").PadRight(35,

// Yeni elementin əlavə edilməsi tree.Insert(15) ;Console.WriteLine("\nElement elave

edildikden sonra agac:\n");AgacGoster.Print(tree);Console.WriteLine("Ağacda elementlərin

sayi= " + tree.CountElements());Console.Read();} }

Proqramın nəticəsi şəkil 3.14-də göstərilmişdir.

3.5.4. Düyünün axtarılınası

Verilmiş açara görə düyünün axtarılması ağacın kökündən başlayır. Əgər axtarılan açar cari düyünün açarından kiçikdirsə, onda sol törəmə düyünü cari düyün edirik, əks halda sağ törəmə element cari element olur. Ağac boyunca eniş tələb olunan düyün tapılana kimi və ya cari düyün null qiyməti alana kimi davam etdirilir. Cari düyünün null qiyməti alması o deməkdir ki, ağacda belə açar yoxdur.

168 Məhərrəmov Z.T., Vəliyev H.P.

AJ F:\ZAKIP.\VSA\BinarELAVEET\BinarEL.. I, ° |

aradiİmis agac

GfiCIN KOKU <root>:20Bol Sag Sol Bol Sag Bag Sag Sol

alt alt alt alt alt alt alt alt

agac agac agac agac agac agac agac agac

2020403030314080

—> 10 -> 40--> 30 —> 29-> 31 -> 32-> 80 —> 70

gacda elementlerin sayi= 9

Element elaue edildikden sonra agac

AGfiCIN KOKU <root>:20Bol Bag Bag Bol Bol Bag Bag Bag Bol

alt alt alt alt alt alt alt alt alt

agac agac agac agac agac agac agac agac agac

20 —> 1010 --> 1520 --> 4040 —> 3030 —> 2930 —> 3131 --> 3240 —> 8080 —> 70

Ağacda elementlerin sayi= 10

rrr r

Şəkil 3.14. Binar ağacın yaradılması və ona yeni elementin əlavə edilməsi

Tutaq ki, şəkil 3.12-də göstərilmiş ağacda 5 qiymətini tapmaq istəyirik (onu k ilə işarə edək). Axtarış alqoritmi belə olacaqdır:

I. k<9, sol alt ağacla enirik;2. k>4, sağ alt ağacla enirik;3. k<8, sol alt ağacla enirik;4. k=5, element tapıldı.

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 169

Ən yaxşı halda açar ağacın kökündə yerləşir və bu 0(1) sayda müqayisə tələb edir. Qalan hallarda (orta və ən pis) axtarılan açar ağacın həm daxili düyünündə, həm də yarpağında yerləşə bilər. İstənilən halda açarı axtardıqda müqayisələrin sayı O(h) olacaqdır.

Elementin axtarılması kodu belədir:

public BinarAgac Find(long data) {if (Data == data) return this;if (Data > data) {return rind(data, SOL);

)return Find(data, SAG);1public BinarAgac Find(long data,

BinarAgac node) {if (node == null) return null;

if (node.Data == data) return node;if (node.Data > data) (return Findfdata, node.SOL);

)return Findfdata, node.SAG);J

3.5.5. Minimal və ya maksimal düyünün axtarılması

Binar axtarış ağacının strukturu minimal və maksimal qiymətli açarın yerləşdiyi düyünü birmənalı tapmağa imkan verir (şəkil 3.15).

170 Məhərrəmov Z.T., Vəliyev H.P.

Şəkil 3.15. Minimal (Min) və maksimal (Max) qiymətli açarlardan ibarət düyünlər

Ən kiçik qiymətli açardan ibarət düyün kökün ən solda yerləşən nəslidir. Onu tapmaq üçün kökdən başlayaraq düyünlərin sol göstəricisinə görə hərəkət etmək lazımdır.

Ən böyük qiymətli açardan ibarət düyün kökün ən sağda yerləşən nəslidir. Onu tapmaq üçün kökdən başlayaraq düyünlərin sağ göstəricisinə görə hərəkət etmək lazımdır.

Minimal və ya maksimal düyünün axtarılması əməliy­yatlarının hesablama mürəkkəbliyi ağacın hündürlüyündən və açarın ağacda paylanmasından asılıdır. Ümumi halda sol və sağ göstəricilərə görə ağac boyunca keçidlərin sayı O(h) olacaqdır.

3.5.6. Düyünün silinməsi

Ağacdan düyünün silinməsi axtarış əməliyyatından çox mürəkkəbdir, çünki silinən düyün kök, sol və ya sağ düyün ola bilər.

Ən sadə hal yarpağın və ya yalnız bir budağın çıxdığı düyünün silinməsidir.

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 171

Ən mürəkkəb hal isə alt ağacın kök düyününün (və ya bütün ağacın) silinməsidir, çünki, bir neçə göstəriciyə düzəlişlər etmək lazım gəlir. Silinəcək yerə qoyulacaq uyğun düyünü tapmaq lazımdır, həm də bu elementin yerini dəyişmək lazımdır. Belə düyün həmişə mövcuddur. Bu, ya sağ budağın sol düyünü, ya da sol budağın sağ düyünüdür.

Əgər bu sol budağın ən sağdakı düyünüdürsə, onda bu düyünü əldə etmək üçün sol budaq boyunca silinən düyündən növbəti düyünə keçmək lazımdır, sonra isə yalnız sağ budaq boyunca növbəti sağ göstərici null qiyməti alana qədər növbəti düyünlərə keçmək lazımdır. Belə düyünün birdən çox budağı ola bilməz. Ağacdan düyünün pozulması sxemi şəkil 3.16-da göstərilmişdir.

Şəkil 3.16. Ağacdan düyünün silinməsi

Şəkil 3.17-də göstərilmiş ağac üzərində silinmə əməliyyatını nümayiş etdirək.

Yarpağın silinməsiƏgər silinən element yarpaqdırsa, onda onun

valideynində bu elementə göstəricini silirik (məsələn, 31). Onu silək.

Sol alt ağaci olan, lakin sağ alt ağaci olmayan düyünün silinməsi31 elementi silindikdən sonra, sol alt ağacı olan, lakin

sağ alt ağacı olmayan element 20 olur. Onu ağacdan silək:1. Göstəririk ki, indi 17 elementinin valideyni 5

elementi olacaq:

172 MəhərrəmovZ.T., VəliyevH.P.

2. Göstəririk ki, indi 5 elementinin sağ nəsli 17 elementidir.

31 və 20 qiymətlərinin silinməsindən sonra ağac şəkil 3.18-də göstərildiyi vəziyyətdə olacaqdır.

Şəkil 3.17. Üzərində silinmə əməliyyatı aparılacaq ağac

Şəkil 3.18. 31 və 20 elementlərinin silinməsindən sonra alınan ağac

Sağ alt ağacı olan, lakin sol alt ağacı olmayan düyünün silinməsi

1. 17 elementini silək. Onun sağ alt ağacına valideyn kimi 5 elementini mənimsədək;

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 173

2. 5 elementinə göstərək ki, indi onun sağ alt ağacı 18 elementidir.

Bu əməliyyatlardan sonra şəkil 3.19-da göstərilən ağac alınacaqdır.

Şəkil 3.19. 17 və 5 elementlərinin silinməsindən sonra alınan ağac

Şəkil 3.20. 34 elementi əlavə edildikdən sonra alınmış ağac

Hər iki tərəfdə alt ağacı olan düyünün silinməsiBirinci hal. Sağ alt ağacın nəsli yoxdur.Bu halı nümayiş etdirə bilməyimiz üçün ağaca 34

elementini əlavə edək (şəkil 3.20).35 elementini silək. Bunun üçün:

174 Məhərrəmov Z. T., Vəliyev H.P.

1. Sağ alt ağacını (99) valideyn kimi 33 elementinə mənimsədək;

2. Ona sol alt ağacı kimi 34 elementini mənimsədirik;3. 34 elementinə onun yeni valideynini (99) göstəririk;4. Silinən elementin valideyninə (33) göstəririk ki, indi

onun sağ alt ağacı 99 elementi olur.Şəkil 3.21-də göstərilən ağacı alacağıq.

İkinci hal. Sağ alt ağacının özü nəsillərə malikdir.5 elementini silək. 5 elementinin birinci nəsli (eyni zamanda ən sol — onun alt ağacında minimal element) 18-dir:1. 18 elementinə sol düyün kimi 1 elementini

mənimsədirik;2. 1 elementinə valideyn kimi 18 mənimsədirik;3. 33 elementinə (silinən elementin valideyninə) sol

törəmə düyün kimi 18 elementini göstəririk;4. 18 elementinə valideyn kimi 33 elementini (silinən

elementin valideynini) göstəririk.Şəkil 3.22-də göstərilən ağacı alacağıq.

Şəkil 3.21. 35 elementlərinin silinməsindən sonra alınan ağac

Üçüncü fəsil- Verilənlərin qeyri-xətti dinamik strukturları 175

Şəkil 3.22. 5 elementinin silinməsindən sonra alınan ağac

Əgər minimal sol elementin sağ nəsilləri varsa, həm də silinən elementin birinci nəsli deyilsə, onda onun sağ nəsli alt ağacın minimal elementinin valideyninə mənimsədilir.

Silmə əməliyyatının kodu belə olacaqdır:

public void Remove(BinarAgac node) (if (node == null) return;var me = MeForParent(node);// Əgər sol törəmə yoxdursa, onda sağ // törəmə silinənin yerinə qoyulurif (node.SOL==null && node.SAG==null) {

ıf (me == BinSide.Left) (node.Valideyn.SOL = null;

} else (node.Valideyn.SAG = null;

}return;

)// Əgər sağ törəmə yoxdursa, onda sol // törəmə silinənin yerinə qoyulur

176 Məhərrəmov Z. T., Vəliyev H.P.

if (node.SOL == null) {

if (me == BinSide.Left){node.Valideyn.SOL = node.SAG;

)else{

node.Valideyn.SAG = node.SAG;}

node.SAG.Valideyn = node.Valideyn; return;}// Əgər sağ törəmə yoxdursa, onda sol// törəmə silinənin yerinə qoyulurif (node.SAG == null)

if (me == BinSide.Left) {node.Valideyn.SOL = node.SOL;

)else{node.Valideyn.SAG = node.SOL;

}

node.SOL.Valideyn = node.Valideyn; return;

}

//Əgər hər iki törəmə düyün olarsa//onda sağı silinənin yerinə qoyuruq//solu isə sağa qoyuruq

if (me == BinSide.Left) (node.Valideyn.SOL = node.SAG;

}if (me == BinSide.Right)

Üçüncü fəsil. Verilənlərin qeyri-xətli dinamik struklurları 177

(node.Valideyn.SAG = node.SAG;

) if (me == null)

var bufLeft = node.SOL;var bufRightLeft = node.SAG.SOL;var bufRightRight = node.SAG.SAG;node.Data = node.SAG.Data;node.SAG = bufRightRight;node.SOL = bufRightLeft;Insert(bufLeft, node, node);

)else

node.SAG.Valideyn = node.Valideyn;Insert(node.SOL, node.SAG, node.SAG);

}public void Removeflong data)(var removeNode = Find(data);if (removeNode != null){Remove(removeNode);

)}

İndi bu proqramı Main metodunda tətbiq edək:

static void Main(string[] args) (

var tree = new BinarAgac();

tree.Insert(20);tree.Insert(40);tree.Insert(10);tree.Insert(30);

178 Məhərrəmov Z. T., Vəliyev H.P.

tree.Insert (80);tree.Insert (29);tree.Insert (31) ;tree.Insert (32) ;tree.Insert(70);

Console.WriteLine("Yaradilmis agac\n");

AgacGoster.Print(tree);

Console.WriteLine("Ağacda elementlerin sayi= " + tree.CountElements());

Console.WriteLine ();Console.WriteLine ( ("") .PadRight(35,

'-'));

// Elementin silinməsi tree.Remove(40);

Console.WriteLine("\nElement silindikden sonra agac:\n");

AgacGoster.Print(tree);

Console.WriteLine("Ağacda elementlerin sayi= " + tree.CountElements());

tree.Remove(30);Console.WriteLine();Console.WriteLine(("").PadRight(35,

'-'));Console.WriteLine("\nElement silindikden

sonra agac:\n");AgacGoster.Print(tree);Console.WriteLine("Ağacda elementlerin

sayi= " + tree.CountElements());

Console.Read();)

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 1?2.

Proqramın nəticəsi şəkil 3.23-də göstərilmişdir.

Şəkil 3.23. Ağacdan elementlərin silinməsi əməliyyatlarının nəticələri

180 Məhərrəmov Z. T,, Vəliyev H.P.

3.5.7. Binar axtarış ağacı üzərində əməliyyatların kompüterdə reallaşdırılması

Binar ağac üzərində yuxarıda yerinə yetirilmiş ayrı-ayrı əməliyyatları icra edən proqramları bir yerə yığaq:

using System;

namespace binar2 {public enum BinSide{

Left, Right

}

public class BinarAgac {public long? Data { get; private set; } public BinarAgac SOL { get; set; } public BinarAgac SAG { get; set; }public BinarAgac Valideyn { get; set; }

public void Insert(long data) {if (Data == null || Data == data) {Data = data; return;

}if (Data > data)(

if (SOL==null) S0L=new BinarAgac(); Insert(data, SOL, this);

} else

if (SAG==null) SAG=new BinarAgac();

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 181

Insert(data, SAG, this);i )

private void Insert(long data, BinarAgac node, BinarAgac parent)

if (node.Data==null || node.Data==data) {node.Data = data;node.Valideyn = parent;return;

}if (node.Data > data)(

if (node.SOL == null)node.SOL = new BinarAgac();

Insert (data, node.SOL, node);} else I

if (node.SAG == null)node.SAG = new BinarAgac();

Insert(data, node.SAG, node);

private void Insert(BinarAgac data, BinarAgac node, BinarAgac parent)

(

if (node.Data == null ! inode.Data == data.Data)

{node.Data = data.Data;node.SOL = data.SOL;node.SAG = data.SAG;node.Valideyn = parent;

182 Məhərrəmov Z.T., Vəliyev H.P.

return;}if (node.Data > data.Data) {

ıf (node.SOL == null)node.SOL = new BinarAgac();

Insert(data, node.SOL, node);} else {

if (node.SAG == null)node.SAG = new BinarAgac();

Insert(data, node.SAG, node);}

}

private BinSide? MeForParent(BinarAgac node)

{if (node.Valideyn == null) return null;if (node.Valideyn.SOL == node)

return BinSide.Left;if (node.Valideyn.SAG == node)

return BinSide.Right;return null;

public void Remove(BinarAgac node) { if (node == null) return;var me = MeForParent(node) ;// Əgər düyündə törəmə element yoxdursa, // onu cəsarətlə pozmaq olarif (node.SOL==null && node.SAG==null) {if (me == BinSide.Left) {node.Valideyn.SOL = null;

}

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 183

else

node.Valideyn.SAG = null; ) return;}//Əgər sol törəmə yoxdursa, onda sağ // törəmə silinənin yerinə qoyulur if (node.SOL == null) {if (me == BinSıde.Left) {node.Valideyn.SOL = node.SAG;

else (node.Valideyn.SAG = node.SAG;

)

node.SAG.Valideyn = node.Valideyn; return;)//Əgər sağ törəmə yoxdursa, onda sol // törəmə silinənin yerinə qoyulur İf (node.SAG == null) {if (me == BinSide.Left){node.Valideyn.SOL = node.SOL;

} else <node.Valideyn.SAG = node.SOL;

}

node.SOL.Valideyn = node.Valideyn; return;)

184 Məhərrəmov Z. T., Vəliyev H.P.

//Əgər hər iki törəmə düyün olarsa //onda sağı silinənin yerinə qoyuruq //solu isə sağa qoyuruq

if (me == BinSide.Left) f

node.Valideyn.SOL = node.SAG; ) if (me -= BinSide.Right) {

node.Valideyn.SAG = node.SAG; } if (me == null) { var bufLeft = node.SOL;var bufRightLeft = node.SAG.SOL;var bufRightRight = node.SAG.SAG; node.Data = node.SAG.Data;node.SAG = bufRightRight;node.SOL = bufRightLeft; Insert(bufLeft, node, node); } else (node.SAG.Valideyn = node.Valideyn; Insert(node.SOL, node.SAG, node.SAG); }

}

public void Removeflong data) (var removeNode = Find(data);if (removeNode != null)

Remove(removeNode); ) I

public BinarAgac Find(long data)

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 185

if (Data == data) return this; if (Data > data){

return Findfdata, SOL);)return Find(data, SAG);

public BinarAgac Find(long data, BinarAgac node)

{if (node == null) return null;

if (node.Data == data) return node; if (node.Data > data) {return Findfdata, node.SOL);

) return Findfdata, node.SAG); )

public long CountElements(){ return CountElements(this);

)

private long CountElements(BinarAgac node)

{long count = 1;if (node.SAG != null) {count += CountElements(node.SAG);

)if (node.SOL != null){ count += CountElements(node.SOL);

)

186 Məhərrəmov Z. T., Vəliyev H.P.

return count;} }

public class AgacGoster {

public static void Print(BinarAgac node) (

if (node != null) {

if (node.Valideyn == null) {Console.WriteLine("ROOT:{0}",

node.Data); > else {

if (node.Valideyn.SOL == node)

Console.WriteLine("Sol for {1} —>{0}", node.Data, node.Valideyn.Data);

)

if (node.Valideyn.SAG == node) (Console.WriteLine("Sag for {1} --> {0}", node.Data, node.Valideyn.Data);

) )

if (node.SOL != null) {Print(node.SOL) ;

}

Üçüncü fəsil. Verilənlərin qeyri-xətti dinamik strukturları 187

if (node.SAG != null){Print(node.SAG);

}}}}

class Program{

static void Main(string[] args){var tree = new BinarAgac();

tree.Insert(20);tree.Insert(40);tree.Insert(10);tree.Insert(30);tree.Insert(80);tree.Insert(29);tree.Insert(31);tree.Insert(32);tree.Insert(70);

Console.WriteLine("Yaradilmis agac\n");

AgacGoster.Print(tree);

Console.WriteLine("Ağacda elementlerin sayi= " + tree.CountElements());

Console.WriteLine();Console.WriteLine(("").PadRight(35,

'-'));

// Yeni elementin əlavə edilməsi tree.Insert(15);

188 Məhərrəmov Z.T., Vəliyev H.P.

paradiİmis

Element elaue edildikden sonra agac:

Element silindikden sonra agac

F:\ZAKIR\VSA\binar2\binar2\bin...

Şəkil 3.24. Ağacın yaradılması, yeni elementin əlavə edilməsi və elementlərin silinməsi əməliyyatlarının nəticələri

R00T:20 Bol Bag Bol Bol Bag Bag Bag BolBgacda elementlerin sayi= 9

agac

for 20 — > 10for 20 --> 40for 40 —> 30for 30 —> 29for 30 —> 31for 31 —> 32for 40 —> 80for 80 —> 70

B00T:20 Bol Bag Bag Bol Bol Bag Bag Bag BolBgacda elementlerin sayi= 10

for 20 — > 10for 10 —> 15for 20 —> 40for 40 —— > 30for 30 —— > 29for 30 —> 31for 31 —> 32for 40 —> 80for 80 — > 70

R00T:40 Kol Bol Bol Bag Bag Bag Bag BolBgacda elementlerin sayi= 9

for 40 — > 30for 30 —> 29for 29 — 1 > 10for 10 —> 15for 30 —> 31for 31 —> 32for 40 —> 80for 80 —> 70

Uçüncü fəsil. Verilənlərin qeyri-xətli dinamik strukturları 189

Console.WriteLine("\nElement əlavə edildikdən sonra agac:\n");

AgacGoster.Print(tree);

Console.WriteLine("Ağacda elementlərinsayi= " + tree.CountElements() ) ;

// Elementin silinməsi tree.Remove(20);

Console.WriteLine();Console.WriteLine(("").PadRight(35,

Console.WriteLine("\nElement silindikden sonra agac:\n");

AgacGoster.Print(tree);

Console.WriteLine("Ağacda elementlərinsayi= " + tree.CountElements());

Console.Read(); } } )

Proqramın nəticəsi şəkil 3.24-də göstərilmişdir.

FƏSİL

VERİLƏNLƏRİNƏLDƏ EDİLMƏSİNİNSÜRƏTLƏNDİRİLMƏSİMETODLARI

4.1. Xeş-cədvəl

Xeş-cədvəl (Hash table) - massivə oxşar verilənlər strukturudur, amma burada elementlərin indeksləşdirilməsi yüksək elastikliyə malikdir. Massivdə elementlər ardıcıl kəmiyyətlərin köməyi ilə indeksləşdirildiyi halda, xeş- cədvəlin elementləri istənilən obyekt vasitəsi ilə indeksləşdirilə bilər. Xeş-cədvəldə saxlanılan verilənlər yığımının hər biri unikal açar vasitəsi ilə tanına bilər. Bu açar vasitəsi ilə verilənlər yiğımında istənilən elementi axtarıb tapmaq olar. Lakin bu unikal açarın bilavasitə qiymətinin saxlanması əvəzinə, onu xeşləşdirirlər (ingiliscə hesh - təkrar üyütmək, qarışdırmaq). Xeşləşdirmə açarı indeksin nömrəsinə çevirir, açarla əlaqəli qiymətlər isə bu indekslə müəyyən edilmiş saxlama yerinə yerləşdirilir. Beləliklə, xeş- cədvəl xeş-funksiya ilə hesablanan qeyri-adi ünvanlı adi massivdən ibarətdir.

Xeşləşdirmə - giriş verilənlərinə görə müəyyən ədədi hesablamaqdan ibarətdir ki, həmin ədəd verilənlərin

Dördüncü fəsil. Xeş-cədvəl 191

ötürülməsinə, cədvəldə verilənlərin axtarışına, parolla mühafizənin təşkilinə nəzarət üçün istifadə edilə bilər.

I üğət və ya ensiklopediyam götürək. Burada əsas axtarış açarı kimi hərflər götürülə bilər, başqa sözlə, xeşləşdirmə alqoritminin əsas elementi açar olacaqdır. Əlavələrin əksəriyyətində açar verilənlərə dolayı istinad təmin edir.

Xeş-cədvəl haqqında aydın təsəvvür yaranması üçün başqa misala da baxaq. Təsəvvür edin ki, Sizdən kitabxana yaratmaq və onu kitablarla doldurmağı xahiş ediblər. Amma Siz dolabları ixtiyari (nizamsız) qaydada doldurmaq istəmirsiniz.

İlk ağıla gələn o olur ki, bütün kitabları əlifba sırası ilə yerləşdirmək və onların adlarım hər hansı bir məlumat kitabçasına yazmaq yaxşı olar. Bu zaman lazım olan kitabı bütün kitabxanada yox, yalnız məlumat kitabçasında axtarmaq kifayət edər.

Ancaq bu işi daha rahat etmək olar. Əgər lap başdan kitabların və ya müəlliflərin adlarından imtina etsək, onda hər hansı xeşləşdirmə alqoritmindən istifadə etmək daha yaxşı olar, belə ki, həmin alqoritm daxil olan qiyməti emal edəcək və lazım olan kitaba uyğun dolabın və rəflərin nömrəsini verəcək. Xeşləşdirmənin bu alqoritmini bilməklə. Siz adma görə lazım olan kitabı çox tez tapa biləcəksiniz.

Böyük həcmli informasiyanın saxlanması orada saxlanılan verilənlərin sürətlə əldə edilə bilməsinin təşkilini tələb edir. Verilənlərin sürətlə əldə edilə bilməsinin təşkili üsullarından biri xeşləşdirmədir. Xeşləşdirmənin əsas ideyası ondan ibarətdir ki, giriş verilənlərinə görə qeyd olunmuş ölçülü hər hansı bir ədəd hesablanır və bu ədəd cədvəldə verilənlərin ünvanını göstərmək üçün istifadə edilir. Bu ədəd - xeş (və ya xeş-kod), onu hesablayan funksiya isə xeş- funksiya adlanir.

Xeş-funksiyaların əsas xüsusiyyəti onların dönməzliyidir, yəni xeşə görə onun hesablandığı ilkin

192 Məhərrəmov Z.T., Vəliyev H.P.

verilənləri bərpa etmək mümkün deyil. Məsələn, y=a%b qalığı tapma əməliyyatında biz a ədədini b ədədinə bölüb asanlıqla qalığı hesablaya bilirik, lakin qalığa görə biz heç vaxt a ədədini hesablaya bilmirik. Bu xüsusiyyət xeşləşdirməni kompüter təhlükəsizliyi və kriptoqrafıya kimi əhəmiyyətli sahələrdə tətbiq etməyə imkan verir. Bu zaman kriptoqrafiyada tətbiq edilən xeş-funksiyalar kriptoqrafik dayanıqlığın tələblərini təmin etməlidir: məlum verilənlər üçün verilənlərin xeş-funksiya ilə eyni olan digər ardıcıllığını seçmək praktik olaraq mümkün olmamalıdır və, bundan başqa, xeşlə eyni olan bəxtəbəxt götürülmüş verilənlərin iki ardıcıllığı praktik olaraq mümkün olmamalıdır. Burada “praktik olaraq” sözü riyazi təyin edilən seçimin dərrakəli çətinliyini nəzərdə tutur.

Xeşlərin dönməzliyi onları parolla mühafizənin təşkili üçün tətbiq etməyə imkan verir, belə ki, verilənlər bazasında parolların özləri yox, onların xeşi saxlanılır. Beləliklə, hətta əgər bədəməl hər hansı yolla verilənlər bazasını sındırmağa nail olmuşsa və xeşi oxuya bilmişsə də, bu onsuz da ona heç vaxt kömək etməyəcək.

Xeş-funksiyalar verilənlərin yoxlanmasında geniş istifadə olunur. Əgər ötürülmüş və qəbul edilmiş verilənlərin xeşi eyni olarsa, onda hesab edilir ki, verilənlərin ötürülməsi prosesi uğurla başa çatmışdır. Məhz bu sahədə xeşləşdirməyə ən yaxşı misal məlumatın nəzarət cəminin tapılması ola bilər: bu halda məlumata daxil olan bütün simvolların kodlarının cəmi xeş kimi xidmət edir, yəni, cəmin bir neçə son rəqəmi xeşin qiyməti olur.

Xeş-cədvəllərin strukturunun əsas üstünlüyü, hətta, böyük verilənlər yığımlarında elementlərin sürətlə axtarılmasındadır. Əgər verilənlərin istədiyimiz qiyməti üçün açar məlumdursa, onda açar xeşləşdirilə bilər və onun vasitəsi ilə qiymətin yeri bilavasitə tapıla bilər. Elementi tapmaq və ya ikili axtarış məqsədi ilə yığımı nizamlamaq üçün bütün verilənlər yığımını araşdırmağa ehtiyac yoxdur.

Dördüncü fəsil. Xeş-cədvəl 193

4.2. Verilənlərin xeşləşdirilməsi

Cədvəllərdə verilənlərə müraciətin sürətləndirilməsi üçün açarların qiymətlərinə müvafiq olaraq cədvəlin ilkin nizamlanmasından istifadə etmək olar.

Bu zaman verilənlərin nizamlanmış strukturlarında axtarış metodlarından, məsələn, yarıya bölmə metodundan istifadə etmək olar ki, bu da açarın qiymətinə görə verilənlərin axtarılması vaxtını əhəmiyyətli dərəcədə azaldır. Ancaq cədvələ yeni yazının əlavə edilməsi tələb olunduqda cədvəli yenidən nizamlamaq tələb olunur. Cədvəlin təkrarən nizamlanmasına itirilən vaxt axtarış vaxtının azaldılmasından əldə edilmiş uduşdan əhəmiyyətli dərəcədə çox ola bilər. Buna görə cədvəllərdə verilənlərə müraciət vaxtının azaldılması üçün təsadüfi nizamlamadan və ya xeşləşdirmədən istifadə olunur. Bu halda key açarının qiymətinə görə i ünvanlarını hesablayan

i = h(key) xeş-funksiyasının köməyi ilə verilənlər cədvəl şəklində təşkil olunur (şəkil 4.1).

cədvəl (veril, bazası fayllan)Açar veril, sahəsi

sah ələr (qeyd otunmuş tipli)

Şəkil 4.1. Xeş-cədvəl

Qeyd edək ki, xeş-funksiya aşağıdakı xassələrə malik olmalıdır:

• eyni açar üçün həmişə eyni ünvan qaytarmalıdır;• müxtəlif açarlar üçün müxtəlif ünvanlar qaytarmaq

mütləq deyil;• bütün ünvan fəzasından eyni ehtimalla istifadə edir;

194 Məhərrəmov Z.T., Vəliyev H.P.

• ünvanı sürətlə hesablayır.İdeal xeş-funksiya elə xeş-funksiyadır ki, istənilən iki

müxtəlif açar üçün müxtəlif ünvanlar verir:kl =£ k2^əh(/il) /ı(/c2).

Belə funksiyam o vaxt seçmək olar ki, açarların bütün mümkün qiymətləri qabaqcadan məlum olsun. Verilənlərin belə təşkili “mükəmməl xeşləşdirmə” adlanır. Açarların qiymətlər çoxluğunun qeyri-müəyyən olması və cədvəlin uzunluğunun məhdud olması haqqında qabaqcadan məlumat olmadıqda mükəmməl funksiyanın seçilməsi çətin olur. Buna görə şərtin yerinə yetirilməsinə zəmanət verməyən xeş- funksiyalar daha çox istifadə edilir.

Adi massivlər üzərində xeşləməni izah edək. Bir daha xatırladaq ki, massiv eyni tipli ardıcıl indeksləşdirilmiş elementlər yığımıdır. Başqa sözlə, z-ci element sabit 0(1) vaxtı ərzində yazıla və oxuna bilər.

Ancaq yalnız bəzi hallarda bizi maraqlandıran elementin mövqeyi məlum olur. Məsələn, müəssisənin əməkdaşlarının verilənlər bazasına baxaq. Tutaq ki, hər bir əməkdaş sosial sığorta kartının nömrəsinin köməyi ilə unikal qaydada müəyyən edilə bilər və bu kartın nömrəsinin strukturu belədir: DDD-DD-DDDD. Burada, D - 0, I, .... 9 rəqəmləridir. Əgər bizdə əməkdaşların nizamlanmamış massivi olsaydı, onda, deyək ki, 111-22-3333 nömrəli əməkdaşı tapmaq üçün potensial olaraq bizə əməkdaşlar massivinin bütün elementlərini araşdırmaq lazım olardı ki, belə əməliyyatın mürəkkəbliyi O(n) təşkil edəcək. Bundan daha yaxşı olardı ki, əməkdaşları onların sosial sığorta kartlarının nömrəsinə görə qabaqcadan nizamlayaydıq, bu halda asimptotik axtarış vaxtı O(log n)-ə qədər azaldıla bilərdi.

İdeal halda, biz hər bir konkret əməkdaş haqqında yazıları 0(1) vaxtı ərzində tapmaq istərdik. Bunu reallaşdırmaq üsullarından biri elementlərinin nömrəsi sosial sığorta kartının nömrəsi olan çox böyük həcmli massiv

Dördüncü fəsil. Xeş-cədvəl 195

yaratmaqdan ibarət olardı. Yəni, bizim massivimiz 000-00- 0000 nömrəli elementdən başlayıb 999-99-9999 nömrəli elementlə qurtarardı (şəkil 4.2).

455-11- 0189455-1 1-0190455-1 1- 0191

999-99-9999

Adı Telefonu Maaşı000-00-0000 Oqtay 395 66 77 450.00

Rauf 444 50 60 500.00Zaur 765 45 78 365.00Ziya 987 67 32 648.00

Yusif 888-44 99 1000.00

Şəkil 4.2. 9 rəqəmli indekslərdən ibarət massiv

Şəkildə göstərildiyi kimi, əməkdaşlar haqqında massivin hər yazısı müəyyən informasiyanı özündə saxlayır; Adı, Telefon nömrəsi, Maaşı və s. Hər yazı sosial sığorta kartının nömrəsi vasitəsi ilə indeksləşdirilir. Belə massivdə istənilən işçi haqqında informasiya sabit O(]) vaxti ərzində alına bilər. Lakin belə yanaşmanın çatışmazlığı yaddaşdan ifrat dərəcədə israfçılıqla istifadə edilməsindədir, belə ki, sosial sığorta kartının 109 milyard müxtəlif nömrəsi mövcuddur. 1000 əməkdaşın işlədiyi şirkət üçün, massivin yalnız 0,0001%-i faktiki olaraq istifadə ediləcəkdir (bu massivi tamamilə doldurmaq üçün, şirkətə nə az, nə çox Yer kürəsinin əhalisinin altıda bir hissəsini işə götürmək lazım olacaq!).

Aydın məsələdir ki, min əməkdaş haqqında informasiyanın saxlanılması üçün milyard elementdən ibarət massivin yaradılması yolverilməzdir. Biz çox istərdik ki, verilənlərin strukturunda elementlərin sayından asılı

196 Məhərrəmov Z.T.t Vəliyev H.P.

olmayaraq yüksək məhsuldarlıqla və sabit vaxt ərzində hər bir konkret əməkdaş haqqında məlumat ala bilək. Mümkün bir variant kimi, əməkdaşların yazılarını nömrələmək üçün sosial sığorta kartının nömrəsinin bütün rəqəmlərini yox, yalnız sonuncu 4 rəqəmini istifadə etmək olar. Beləliklə, 000- 00-0000 elementindən 999-99-9999 elementinə qədər uzanan massivin yerinə biz 0000-dan 9999-a qədər elementlər diapazonundan ibarət massiv alacağıq. Şəkil 4.3-də belə “kəsilmiş’" massiv göstərilmişdir.

Şəkil 4.3. Kəsilmiş massiv

Adı Telefonu Maaşı0000 Oqtay 395 66 77 450.00

0189 Rauf 444 50 60 500.000190 Zaur 765 45 78 365.000191 Ziya 987 67 32 648.00

9999 Yusif 888-44 99 1000.00

Belə yanaşmada biz həm sabir axtarış vaxtı (əməkdaşların sayından asılı olmayan), həm də müqayisə olunacaq dərəcədə yaddaşa qənaət edirik. Vacib deyil ki, hökmən sonuncu 4 rəqəmi seçək. Eyni müvəffəqiyyətlə biz 4 orta rəqəmdən və ya, tutaq ki, birinci, üçüncü, səkkizincini və doqquzuncu rəqəmləri istifadə edə bilərik.

Burada yerinə yetirdiyimiz doqquz rəqəmli ədədin dörd rəqəmli ədədlə riyazi əvəz edilməsi xeşləşdirmə əməliyyatıdır, özünün indekslər fəzasını sıxmaq üçün xeşləşdirmədən istifadə edən massiv isə xeş-cədvəl (hash table) adlanır. Sosial sığorta karlının nömrəsi üçün h xeş- funksiyası aşağıdakı kimi təsvir edilə bilər:

h (x) = x ədədinin sonuncu 4 rəqəmi.

Dördüncü fəsil. Xeş-cədvəl 197

h funksiyasının girişinə sosial sığorta kartının istənilən 9 rəqəmli nömrəsi verilir. Çıxışda isə daxil edilən ədədin sonuncu 4 rəqəmindən ibarət dördrəqəmli ədəd alırıq. Riyazi terminlərlə desək, h - sosial sığorta kartının 9 rəqəmli çoxluğunu 4 rəqəmli ədədlər çoxluğuna inikas edir. Bu, şəkil 4.4-də göstərilmişdir.

sosial sığorta kartının 9 rəaəmli nömrələr coxluiu

rəqəmli nömrələr çoxluğu

Şəkil 4.4. 9 rəqəmli ədədlər çoxluğunun 4 rəqəmli ədədlər çoxluğuna inikas edilməsi

Şəkil bütün xeş-funksiyalara məxsus olan bir hadisəni - kolliziyanı (ingiliscə coliisions, toqquşma) nümayiş etdirir. İki və ya daha çox açarın eyni bir ünvan göstərməsi xeşləşdirmədə kolliziya adlanır. Bizim misalda 0000 ilə qurtaran sosial sığorta kartının bütün nömrələri xeş-funksiya ilə 0000-da inikas olunacaqdır. Başqa sözlə, 000-00-0000, 113-14-0000, 933-66-0000 və digər çoxlu başqa nömrələr üçün xeş-funksiyanın qiyməti eyni, yəni 0000 olacaq.

Əməkdaşlardan ibarət massivə qayıdaq. Baxaq görək, biz massivə nömrəsi 123-00-0191 olan yeni əməkdaş haqqında yazı əlavə etməyə çalışsaq nə baş verəcək. Aydındır

198 Məhərrəmov Z. T., Vəliyev H. P.

ki, biz bu halda problemlə qarşılaşacağıq, çünki, massivdə artıq 0191 nömrəli xanada əməkdaş (Ziya) mövcuddur.

Buradan aydın olur ki, kolliziyanın baş verməsi problemlər yaradır. Növbəti bölmədə kolliziyanın aradan qaldırılması yollarını araşdıracağıq.

Hələlik isə C# dilində qeyri-mükəmməl xeş- funksiyanın reallaşdırılmasına baxaq. Fərz edək ki, açar dörd simvoldan ibarətdir, cədvəl isə 0-dan 10000-ə qədər ünvanlar diapazonuna malikdir. Bu xeşləşdirməni belə proqramlaşdıra bilərik:

static void H(string key, out long f) {//Açara görə funksiyanın qiymətinin// hesablanması:f=(char)(key[0]) - (char)(key[l])+

(char)(key[2]) - (char)(key[3]);

/* funksiyanın qiymətinin başlanğıc oblastının xeş-cədvəlin başlanğıc ünvanı ilə uyğunlaşdırılması (a= 1): */f=f+255*2;

/* funksiyanın qiymətinin son oblastının xeş-cədvəlin son ünvanı ilə uyğunlaşdırılması (a= 10000): */f=MathiDivRem((f*10000), (255*4),

out long q);}

Xeş-funksiyanın bu metodla qiymətini hesablamaq üçün ona aşağıdakı proqramla müraciət etmək olar:

static void Main(string[] args) {string key = "abcd"; long f;H(key, out f);Console.WriteLine(f) ;

Dördüncü fəsil. Xeş-cədvəl 199

Console.Read(); }

Hesablama nəticəsində xeşin qiyməti 4 98 0 alına­caqdır.

4.3. Kolliziyanın həlli metodları

Verilənləri xeş-cədvələ əlavə etdikdə kolliziyanın yaranması bir çox xoşagəlməzliklərə səbəb olur. Əgər kolliziya yaranmasaydı, biz, sadəcə olaraq, verilənləri indeksini qabaqcadan xeş-funksiyanın köməyi ilə hesabla­dığımız massivin elementinə yazardıq; kolliziya bizi əlavə əməliyyatlar yerinə yetirməyə məcbur edir. Kolliziya yarandıqda yerinə yetirilən əməliyyatların sayı artır, ona görə bizim əsas məqsədimiz kolliziyaların baş verməsi hallarının sayını azaltmaq olmalıdır.

Kolliziyaların tezliyi istifadə edilən xeş-funksiyanın özü ilə və onun girişinə verilən verilənlərin paylanması ilə birbaşa bağlıdır. Yuxarıda təsvir etdiyimiz massiv misalında əməkdaşın sosial sığorta kartının sonuncu 4 rəqəmli nömrəsi kimi istifadə etdiyimiz xeş-funksiyalar praktik olaraq aşağıdakı halda mükəmməl variant ola bilər: məsələn, sosial sığorta kartının nömrələri insanlara tamamilə təsadüfi qaydada verilir. Ancaq, əgər bu nömrələr aşağıdakı kimi təyin olunarsa, kolliziyaların sayı daha da artacaqdır: eyni ildə və ya eyni yerdə doğulmuş insanlara son rəqəmləri eyni olan nömrələr verilir və əməkdaşların doğum tarixi və yerləri bərabər paylanmır.

Xeş-funksiyanın dəqiq analizi riyazi statistika sahəsindən müəyyən biliklər tələb edir. Əsasən tələb olunur ki, k sayda xanaları olan xeş-cədvəl üçün xeş-funksiyanın qiymətlər oblastından hər konkret qiymətin seçilməsi ehtimalı bərabər, yəni, 1/k olsun.

200 Məhərrəmov Z.T., Vəliyev H.P.

Kolliziyanı aradan qaldırmağın bir neçə metodları vardır. Ən sadə metodlardan biri sınaqların xətti ardıcıllığı (linear probing) adlanır və belə işləyir:

1. Xeş-cədvələ yeni element əlavə etdikdə, elementin onun hansı xanasına yazılacağını müəyyən etmək üçün xeş- funksiyadan istifadə edilir;

2. Birinci addımda xeş-funksiyanın köməyi ilə tapılmış mövqedə elementin mövcudluğu yoxlanılır. Əgər mövqe boşdursa, ora elementi yerləşdiririk, əks təqdirdə üçüncü addıma keçirik;

3. Tutaq ki, xeş-funksiya ilə tapılmış mövqenin nömrəsi ı-dir. Onda /+7-ci mövqeni yoxlayırıq, əgər o da tutulmuşdursa /+ 2-ci mövqeni və s., boş mövqe tapana kimi yoxlayırıq.

Baxdığımız massivə bu metodu tətbiq edək. Bunun üçün massivin elementlərinə şəkil 4.5-də göstərilmiş yazıları daxil edək.

Adı Telefonu Maaşı0000 Oqtay 395 66 77 450.00

1234 Rauf 444 50 60 500.001235 Zaur 765 45 78 365.001236 Ziya 987 67 32 648.001237 Nadir 222 45 90 700.001238 Namiq 322 78 56 650.00

9999 Yusif 888-44 99 1000.00

Şəkil 4.5. Oxşar nömrəli əməkdaşlardan ibarət xeş-cədvəl

Dördüncü fasil. Xeş-cadval 201

Tutaq ki, xeşləşdirmə nəticəsində Raufun sosial kartının nömrəsi üçün tapılan xeş 1234 olmuşdur və ona aid yazı massivin 1234-cü xanasına yazılmışdır. Sonra, Zaurun nömrəsi üçün də eyni xeş hesablanmışdir. yəni, 1234, ancaq 1234-cü xana artıq Raufa aid yazı ilə tutulmuşdur, beləliklə, Zaur növbəti boş xananı tutur - 1235. Zaurdan sonra biz Nadirə aid yazını əlavə edirik, çünki, xeş-funksiya onun sosial sığorta kartının nömrəsi üçün 1237 qiymətini vermişdir. 1237-ci xanada heç kim olmadığı üçün Nadirə aid yazı orada yerləşdirilir. Növbəti - Ziyadır. Onun nömrəsi üçün xeş 1235 hesablanmışdır. Lakin, 1235-ci mövqe tutulmuşdur, onda 1236 nömrəli xana yoxlanır. 1236 boş olduğu üçün Ziya oraya yazılır. Sonda Namiqin yazısı əlavə edilir, onun sosial sığorta kartının nömrəsi üçün də 1235 xeş ədədi alınmışdır. 1235-ci xana tutulduğu üçün 1236 yoxlanır. O da həmçinin tutulmuşdur, ona görə 1237-ci xana yoxlanılır. Bu xana isə Nadirə aid yazı ilə tutulmuşdur, onda 1238-ci xana yoxlanılır. O boşdur. Beləliklə, Namiqin yazısı 1238-ci xanaya əlavə edilir.

Xeş-cədvəldə axtarış apardıqda da kolliziyaya görə problemlər yaranır. Məsələn, təsəvvür edək ki, bizə xeş- cədvəldə Namiq haqqında informasiyanı tapmaq lazımdır. Biz Namiqin sosial sığorta kartının 111-00-1235 nömrəsini götürürük, onu xeşləşdirib 1235 xeş ədədini alırıq və axtarışa başlayırıq. 1235-ci xanada biz Namiqi yox, Zauru tapırıq. Beləliklə, bizə indi 1236-cı xananı yoxlamaq lazımdır, amma orada Ziyadır. Beləliklə, biz ya Namiqi tapana kimi, ya da boş xanaya çatana kimi xətti axtarışı davam etdirəcəyik. Boş xanaya çatmaq o deməkdir ki, xeş-cədvəldə sosial sığorta kartının nömrəsi 111-00-1235 olan əməkdaş mövcud deyil.

Sınaqların xətti ardıcıllığı metodu sadə prosedurdur, ancaq o kolliziyaların aradan qaldırılması üçün çox da yaxşı üsul deyil, belə ki. klasterlərin (clustering) yaranmasına səbəb olur. Bu anlayışı izah edək. Təsəvvür edək ki, xeş-cədvələ əlavə etdiyimiz birinci 10 əməkdaşın hamısı eyni 4 rəqəmlə

202 Məhərrəmov Z. T., Vəliyev H.P.

qurtaran sosial sığorta kartının nömrəsini göstərən xeşə, məsələn, tutaq ki, 3344 xeşinə malikdir. Onda massivin 3344- dən 3353-ə qədər 10 ardıcıl xanası tutulacaqdır. Bu 10 əməkdaşdan istənilən birinin verilənlərinin axtarışına cəhd etdikdə sınaqların xətti ardıcıllığı prosesi baş verəcək. Bundan başqa, xeş-funksiyasının qiyməti 3345-3353 aralığına düşən əməkdaşların xeş-cədvələ əlavə edilməsi klasterin yenidən böyüməsinə gətirib çıxaracaq. Sürətli axtarış üçün, əlbəttə, xeş-cədvəldə verilənlərin müəyyən nöqtələr ətrafında klasterləşmiş yox, müntəzəm paylanmasına nail olmaq daha yaxşıdır.

Kolliziyanı aradan qaldırmaq üsullarından biri də sınaqların kvadratik ardıcıllığı metodudur. Bu nisbətən mürəkkəb metoddur, burada ardıcıl yerləşmiş yox, bir- birindən kvadratik məsafədə yerləşmiş xanalar yoxlanır. Yəni, əgər 5 xanası doludursa, sınaqların xətti ardıcıllığında olduğu kimi, s + 1 xanasının, sonra isə s 4- 2 xanasının və s. yoxlanmasının əvəzinə, əvvəlcə (s + l)2 xanası, sonra (s — l)2, sonra (s 4- 2)2, sonra (s — 2)2, sonra (s 4- 3)2 və s. yoxlanır. Ancaq, hətta, sınaqların kvadrat ardıcıllığı metodu da klasterlərin yaranmasına gətirib çıxara bilər.

4.4. Xeş-funksiyanın keyfiyyətinin qiymətləndirilməsi

Artıq qeyd etdiyimiz kimi, xeş-funksiyanın düzgün seçilməsi çox vacibdir. Xeş-funksiyanı düzgün seçdikdə cədvəl daha müntəzəm doldurulur, kolliziyaların sayı azalır və cədvəldə axtarış, əlavəetmə və silinmə əməliyyatlarının yerinə yetirilmə vaxtı azalır. Xeş-funksiyanın keyfiyyətini qabaqcadan qiymətləndirmək üçün imitasiya modelləşdirməsini icra etmək olar. Modelləşdirmə aşağıdakı qaydada aparılır. Uzunluğu xeş-cədvəlin uzunluğuna uyğun gələn tamədədli massiv yaradılır. Təsadüfi olaraq kifayət qədər böyük sayda açarlar yaradılır və hər açar üçün xeş-

Dördüncü fəsil. Xeş-cədvəl 203

funksiya hesablanır. Massivin elementlərində bu ünvanın generasiyaları sayılır. Belə modelləşdirmənin nəticələrinə görə xeş-funksiyanın qiymətlərinin paylanması qrafiki qurulur. Düzgün qiymətləndirmənin alınması üçün yaradılan açarların sayı cədvəlin uzunluğundan bir neçə dəfə çox olmalıdır. İmitasiya prosesində alınmış kolliziyaların paylanmasının bir variantı şəkil 4.6-da nümayiş etdirilmişdir.

Şəkil 4.6. İmitasiya prosesində alınmış kolliziyaların paylanması

Əgər cədvəlin elementlərinin sayı kifayət qədər çox olarsa, onda qrafik ayrı-ayrı ünvanlar üçün yox, ünvanlar qrupları üçün qurulur. Məsələn, bütün ünvan fəzası 100 fraqmentə ayrılır və hər fraqment üçün neçə ünvanın düşməsi sayılır. Böyük qeyri-müntəzəmlik cədvəlin ayrı-ayrı yerlərində kolliziyaların yüksək ehtimalına dəlalət edir. Əlbəttə, belə qiymətləndirmə təxminidir, amma o xeş- funksiyanın keyfiyyətini qabaqcadan qiymətləndirməyə və onun qurulmasında kobud səhvlərdən qaçmağa imkan verir.

Əgər yaradılan açarlar xeş-cədvəl doldurulduqda istifadə edilən real açarlara daha yaxın olarsa, onda

204 Məhərrəmov Z.T., Vəliyev H.P.

qiymətləndirilmə daha dəqiq olacaq. Simvol açarları üçün real açarda olan simvolların kodlarının simvolların yaradılan kodlarına uyğun olması çox vacibdir. Bunun üçün açarda hansı simvolların istifadə edildiyini təhlil etmək lazımdır.

Məsələn, əgər açar Azərbaycan dilində soyaddan ibarətdirsə, onda Azərbaycan əlifbasının simvollarından istifadə edilməlidir (əlbəttə, proqramlaşdırma dili bu dili dəstəkləyirsə). Həm də birinci simvol böyük hərf, yerdə qalanlar isə kiçik hərflər ola bilər.

Birinci hərfi böyük, yerdə qalanları isə kiçik hərflər olan on latın hərfindən ibarət açarların generasiyası misalına baxaq.

Əvvəlcə açarları yaradan metodu kodlaşdıraq:

static void H( char[] s) ıRandom r = new Random(); int a = r.Next(l, [90 - 65)); s[0]- (char) (a + 65) ; for (int i = 1; i < 10; i + +) {int b = r.Next(l, (122 - 97)); s[i] = (char) (b + 97);

) 1

Nəticəni almaq üçün kod yazaq:

static void Main(string[] args)

{char[] s = new char [10];H (s) ;Console.WriteLine () ;for (int i = 0; i < 10; i++) Console.Write(s[i]+ " ");

Console.Read();}

Dördüncü fəsil. Xeş-cədvəl 205

Metod təsadüfi ədədlərlə işlədiyi üçün proqram hər dəfə müxtəlif qiymətlər verəcək. Bir variantda yaradılan açarlar şəkil 4.7-də göstərilmişdir.

Şəkil 4.7. Birinci hərfi böyük, yerdə qalanları isə kiçik hərflər olan on latın hərfindən ibarət açarların

generasiyası

Bu xeşləşdirmədə simvolların mümkün kodları kod cədvəlində ardıcıl fasiləsiz sahələrdə yerləşir. Daha ümumi hala baxaq. Tutaq ki, kodları (nl, n2) diapazonunda yerləşən ardıcıl simvollardan m sayda açarlar yaratmaq lazımdır.

(nl, n2) diapazonunda yerləşən ardıcıl simvollardan açarların yaradılması:

class Program{static void H(int nl, int n2, char[] s) {Random r = new Random();for (int i = 0; i < (n2 - nl); i++) {int a = r.Next(0, (n2 - nl));s [i] = (char) (a + nl) ;

1 1

static void Main(string[] args)1char[] s = new char [10]; int nl = 80, n2 = 90;H(nl, n2, s) ;

206 Məhərrəmov Z.T., Vəliyev H.P.

Console.WriteLine() ;for (int i = 0; i < (n2 - nl); i++) Console.Write(s [i] + " ");

Console.Read();I }

Proqramın nəticəsi şəkil 4.8-də göstərilmişdir.

Şəkil 4.8. (8 0, 90) diapazonunda yerləşən ardıcıl simvollardan açarların generasiyası

Praktikada elə variantlar mümkündür ki, eyni mövqelərdə açarın simvolları kodların müxtəlif diapazonlarına aid ola bilər, həm də bu diapazonlar kəsilə bilər. Məsələn, kodları (nl, n4) aralığında olan simvollardan açarlar yaradaq. Ancaq bu aralıq n2-dən n3-ə qədər kəsilir (şəkil 4.9).

nl 112 n3 n4

Şəkil 4.9. Simvolların kodlarının kəsilmiş diapazonları

Bu hal üçün kodu belə yaza bilərik:

class Program {static void H(int nl, int n2, int n3,

int n4, char[] s)

Dördüncü fəsil. Xeş-cədvəl 207

Random r = new Random();for (int i=0; i<(n4-n3)+(n2-nl); i++) {int a=r.Next(0, (n4 - n3)+(n2-nl));if (a<=(n2-nl)) s[i]=(char)(a + nl);else s [i] = (char) (a + nl + n3 - n2);

} }

static void Main (string[] args) {char[] s = new char[20];int nl = 70, n2 = 80, n3 = 90, n4 = 100;H(nl, n2, n3, n4, s);Console.WriteLine();for (int i=0; i< (n4-n3) + (n2-nl) ; i++)Console.Write(s [i] + " ");

Console.Read();} }

Proqramın nəticəsi şəkil 4.10-da göstərilmişdir

Şəkil 4.10. (70, 80) və (90, 100) diapazonlarında yerləşən ardıcıl olmayan simvollardan açarların

generasiyası

Geniş yayılmış xeş-funksiyalardan biri bölmə metoduna əsaslanır. Funksiyanın girişinə hər hansı tam tipli key açarı və cədvəlin m ölçüsü verilir, çıxışda isə bu açarın cədvəlin ölçüsünə bölünməsindən alınan qalıq alınır. C# dilində bu metoda uyğun funksiyanı və ona müraciət kodunu belə tərtib edə bilərik:

208 Məhərrəmov Z. T., Vəliyev H.P.

static int Func(int key, int m) {return key % m;

}

static void Main(string[] args) {

int q=Func(342, 10);Console.WriteLine("qaliq= " + q);Console.Read ();

(Bölmə metodunda m=10 olduqda xeş-funksiya ədədin

kiçik mərtəbəsini, m=100 olduqda isə ədədin iki kiçik mərtəbəsini qaytarır. Xeş-cədvəldə bu hallara uyğun ünvanlaşdırma uyğun olaraq şəkil 4.11 və şəkil 4.12-də nümayiş etdirilmişdir.

Xeş-cədvəl (m=10)

Xeş-ünvan ı: H I 7 17 P M 5161 71 * I 9 I> / \ |

*<y = 342 *<y = 756 \ k Kolliziya

key = 55556 J

Şəkil 4.11. m=10 olduqda xeş-funksiya açarın kiçik mərtəbəsini qaytarır

Xeş-ünvan i:

Xeş-cədvəl (m=l 00)

I 00 | 07 | 02 | ... | 97 | 98 | 99 |* / \ T

fcy = 3402 iO’=7597 \ Kolliziya

= 55597 J

Şəkil 4.12. m=10 0 olduqda xeş-funksiya açarın iki kiçik mərtəbəsini qaytarır

Dördüncü /əsil. Xeş-cədvəl 209

4.5. Xeş-cədvəlin kompüterdə reallaşdırılması

4.5.1. Hashtable sinfi

.NET Framework platforması xeş-cədvəlin reallaşdırılması üçün bütün funksional imkanlara malik olan Hashtable sinfini təqdim edir. Hashtable sinfi lüğətlər yığımından ibarətdir. Kolleksiyanın hər elementi iki xassəyə malik olan DictionaryEntry obyektidir: key obyekti və value obyekti. Bütün verilənlər bir cüt açar/qiymət şəklində saxlanır.

Xeş-cədvələ elementlər əlavə edildikdə xeş-kod avtomatik yaradılır. Bu kod proqramçılardan gizlədilmişdir. Lakin cədvəlin qiymətlərinə müraciət açar obyektin köməyi ilə əldə edilir.

Hashtable sinfi System.Collections adlar sahəsində yerləşir, ona görə, xeş-cədvəllərlə işlədikdə proqramın adlar fəzasına using System. Collections kodu əlavə edilməlidir. Aşağıdakı kod yeni boş xeş-cədvəl yaradır:

Hashtable cedvel = new Hashtable ();İlkin yaradılan xeş-cədvəllərin həcmi məhdud olur.

Cədvələ aid sahə tam dolduqda onun həcmi avtomatik böyüyür. Cədvəlin maksimal ölçüsü əvvəlcədən məlum olarsa, onu konstruktorda tam ədədlə vermək olar, bu halda xeş-cədvəlin ölçünün dəyişdirilməsi ehtiyacı aradan qaldırılır və məhsuldarlıq artır:

Hashtable cedvel = new Hashtable(150);Xeş-cədvəllərin məhsuldarlığı yüklənmə əmsalından,

yəni, xeş-cədvəldə saxlanılan obyektlərin miqdarının xanaların ümumi sayına nisbətindən asılıdır. Yüklənmə əmsalı artdıqca kolliziyaların yaranması ehtimalı artır. Xeş- cədvəlin yüklənmə əmsalı sürət ilə yaddaş sərfi arasında razılaşma yaradır, belə ki, yüklənmə əmsalı artdıqda yaddaş sərfi azalır, amma kolliziyaların yaranma tezliyi artır və bu

210 Məhərrəmov Z.T., Vəliyev H.P.

səbəbdən əlavə daha yavaş işləməyə başlayır. Yüklənmənin əmsalının azalması kolliziyaların sayını azaldır ki, bu da sürətin artmasına imkan yaradır, amma yaddaş sərfinin effektivliyi azalır, çünki xeş-cədvəlin əksər hissəsi boş qalır. Yüklənmə əmsalı 0 .1-1.0 diapazonunda qiymətlər ala bilər. 0.1 qiyməti onu göstərir ki, xeş-cədvəlin həcmi artırılana qədər kolleksiyanın ümumi saxlanma fəzasının yalnız onda bir hissəsi istifadə olunacaq. Bu, kodla belə təsvir ediləcək:

Hashtable myData = new Hashtable(100, 0.1 f) ;

Qeyd edək ki, yüklənmə əmsalına hansı qiymətin verilməsindən asılı olmayaraq, o avtomatik olaraq 72%-dək azaldılacaqdır. Hətta 1 qiyməti verildikdə də xeş-cədvəlin doldurulma səviyyəsi 72%-i aşmayacaqdır. Məsələ ondadır ki, Microsoft şirkətində təcrübə yolu ilə müəyyən etmişlər ki, xeş-cədvəlin ən optimal yüklənmə əmsalı 1-ə bərabərdir (bu isə kolleksiyaya ayrılan həcmin 72%-i deməkdir). Odur ki, konstruktorda yüklənmə əmsalını 1 götürmək lazımdır.

4.5.2. Xeş-cədvəlin yaradılması, elementlərin əlavə edilməsi və onlar üzərində əməliyyatlar

Elementlər xeş-cədvələ Hashtable sinfinin Add metodu ilə əlavə edilir. Əvvəlcə xeş-cədvəl yaradaq, sonra onun üzərində yerinə yetirilmiş əməliyyatları izah edək.

using System;using System.Collections;class Program

public static void Main() {Hashtable eded = new Hashtable (); //1-ci

// XEŞ-CƏDVƏL

Dördüncü fəsil. Xeş-cədvəl 211

// Xeş-cədvələ sətir tipli açar və // həqiqi ədədlərin əlavə edilməsi eded.Add("aleks", 1.6);eded.Add("roza", 2);eded.Add("elba", 3.8);eded.Add("abel", 4);eded.Add("dronga", 5.095);

strıng s = new string('- 1,30) ;Console.WriteLine("\naleks acharli

element= " + eded["aleks"]);Console.WriteLine(s);

// Xeş-cədvəldəki açarların ekrana// çıxarılmasıConsole.WriteLine("\nXesh-cedvelin

acharlari:");foreach (var key in eded.Keys) (

Console.WriteLine(key);)Console.WriteLine (s) ;

// Xeş-cədvəldəki qiymətlərin ekrana // çıxarılmasıConsole.WriteLine("\nXesh-cedvelin

qiyır.etler i : " ) ;foreach (var qiymet in eded.Values) {Console.WriteLine(qiymet);

)

//Yeni XEŞ-CƏDVƏLin yaradılması Hashtable shair = new Hashtable(); //2-

//ci XEŞ-CƏDVƏL

// Xeş-cədvələ sətir tipli açar və sətı// tıplı qiymətlərin əlavə edilməsi

212 Məhərrəmov Z. T., Vəliyev H.P.

shair.Add("Nizami" , "Xosrov ve Shirin"); shair.Add("Fuzuli", "Leyli ve Mecnun"); shair.Add("Vurğun", "Ferhad ve Shirin"); shair.Add("Nevaı", "Ferhad ve Shirin");

shair["Nizami"] = "ISGENDERNAME";shair["Xetaı"] = "DEHNAME";

Console.WriteLine(s);Console.WriteLine("\nXesh-cedvelin

qiymetleri:");foreach (var qiymet in shair.Values) (Console.WriteLine(qiymet);

}

Console.WriteLine(s);

Console.WriteLine ();// Açara görə elementin tapılmasııf (shair.ContainsKey("Nizami")){string Eser =

(string) shair["Nizami"];Console.WriteLine("Nizaminin eseri:

" + Eser.ToStringı));}elseConsole.WriteLine("Xesh-cedvelde

Nizami yoxdur");

Console.ReadKey();) ;

Proqramın nəticəsi şəkil 4.13-də göstərilmişdir.Bu proqramla iki xeş-cədvəl yaradılmışdır. Onlardan

birinin elementləri həqiqi tipli ədədlərdən (eded cədvəli), digərinin elementləri isə sətir tipli elementlərdən (shair

Dördüncü fəsil, Xeş-cədvəl 213

cədvəli) ibarətdir. Add metodu iki arqumentdən ibarətdir: birinci arqument açar, ikinci arqument isə elementin qiymətidir.

F:\ZAKIR\VSA\433h8Wash8..r[HIH]^^^r

Şəkil 4.13. Xeş-cədvəlin yaradılması

Cədvəlin istənilən elementinə adi massivin elementinə müraciət edildiyi kimi müraciət edilir. Məsələn.

Console.WriteLine("\naleks acharli element= " + eded["aleks"]);

kodu ilə aleks açarlı element ekranda təsvir edilir. Elementə müraciət edib ona qiymət verməklə cədvəldə onun qiymətini dəyişdirmək olar. Əgər cədvəldə belə açarlı

214 Məhərrəmov Z.T., Vəliyev H.P.

element olmazsa, onda o cədvələ əlavə ediləcəkdir. Proqramda bu əməliyyatlar aşağıdakı kodla icra edilmişdir:

shair["Nizami"] = "ISGENDERNAME";shair [ "Xetai"] = "DEHNAME";Birinci kodla, cədvəldə Nizami açarı olduğu üçün,

Xosrov ve Shirin qiyməti ISGENDERNAME ilə əvəz ediləcək, ikinci kodla isə cədvələ yeni DEHNAME adlı element əlavə ediləcəkdir.

Hashtable sinfinin Keys xassəsi mövcuddur. Bu xassə xeş-cədvəldə mövcud olan açarları qaytarır. Bu xassəni foreach dövründə tətbiq etməklə cədvəlin açarlarını ekrana çıxardıq:

foreach (var key in eded.Keys){

Console.WriteLine(key);}Göründüyü kimi, açarların Keys xassəsi ilə ekranda

təsvir edilmiş ardıcıllığı proqramda daxil edən ardıcıllıqla eyni deyil. Açarların ardıcıllığı açarlı elementin saxlandığı daxili massivdə xanaların ardıcıllığına uyğun gəlir.

Əksər hallarda bütün siyahını araşdırmaq yox, bilavasitə elementin qiymətinə müraciət etmək lazım gəlir. Bu əməliyyat Hashtable sinfinin Value xassəsi ilə yerinə yetirilir. Value xassəsi elementin qiymətini qaytarır. Bu xassə proqramda, məsələn, aşağıdakı kodda istifadə edilmişdir:

foreach (var key in eded.Keys) {

Console.WriteLine(key);1Proqramda Hashtable sinfinin ContainsKey ()

metodundan da istifadə edilmişdir. Onun nəticəsi məntiqi tiplidir. Biz bu metoddan xeş-cədvəldə Nizami açarlı elementin axtarılması üçün istifadə etmişik (if (shair . ContainsKey ( "Nizami" ) )).

Dördüncü fəsil. Xeş-cədvəl 215

Tərtib etdiyimiz proqrama nəzər saldıqda təbii olaraq belə sual yaranır: bəs xeş-funksiyaya aid bu qədər izahlar verildi, ancaq proqramda xeş-funksiya, ümumiyyətlə, istifadə edilmədi? Bu zahirən belədir, əslində bütün əməliyyatlar həmin bu proqramda da xeş-funksiya əsasında yerinə yetirilmişdir. Məsələ ondadır ki, xeş-funksiya Hashtable sinfinin tərkibində öz işini görür və onun ifadəsi belədir:

H(key)=[GetHash(key)+1+(((GetHash(key)>> 5) +1) % (has-hsize-1) ) ] %hashsize.

Burada, GetHash (key) - key obyektinin GetHashCode () metodu çağrıldıqda qaytarılan susmaya görə qiymətdir (Siz GetHash () funksiyasım özünüz də müəyyən edə bilərsiniz). GetHash(key)>>5 ifadəsi key üçün xeşi hesablayır, yəni, 5 bit qədər sağa sürüşdürmə əməliyyatı yerinə yetirir ki, bu da xeşləşdirmənin nəticəsinin 32-yə bölünməsinə ekvivalentdir. Bildiyimiz kimi, % operatoru bölmə əməlində । qalığın tapılması üçündür (xatırlayaq ki, x%y əməliyyatı-x-in y-ə bölünməsi əməlində qalığı hesablayır və bu qalıq :0-(y-l).; diapazonunda yerləşir), hashsize - xeş-cədvəldə bütün xanaların ümumi- sayıdır. Bərabərliyin sağ tərəfindəki bölmə əməlində qalıq hesablandığı üçün. H(key) funksiyasının son nəticəsi, həmişə 0-(hashsize-1) diapazonunda olacaq, hashsize isə xeş-cədvəldə bütün xanaların ümumi sayı olduğundan, xeş-funksiya ilə hesablanmış nəticə həmişə yolverilən hüdudlarda yerləşəcək.

ALQORİTMLƏRİ

Proqramlaşdırmada ən çox rast gələn məsələlərdən biri verilənlərin axtarılmasıdır. Axtarılan element verilənlərin müxtəlif strukturlarında yerləşə bilər. Biz elementi massiv­lərdə axtaracağıq. Bu prinsipial əhəmiyyət kəsb etmir, belə ki, biz istənilən strukturdan (yazı, siyahı və s.) massiv yarada bilərik. Massivdə açar adlanan elementi axtaracağıq. Bildiyimiz kimi, massivin elementləri O-dan w-ə kimi nömrələnir. Massiv nizamlanmış və ya nizamlanmamış ola bilər. Nizamlanmamış massivlərdə lazım olan element tapılana kimi massivin bütün elementləri araşdırılır. Belə axtarış üçün ardıcıl axtarış üsulundan istifadə edilir. Nizamlanmış massivlərdə isə binar (ikili) axtarış üsulunun tətbiq edilməsi daha səmərəli olur.

5.1. Ardıcıl axtarış üsulu

Artıq qeyd etdiyimiz kimi, bu axtarış üsulunda massivin bütün elementləri araşdırılır və axtarılan elementlə

Beşinci fəsil. Axtarış alqoritmləri 217

müqayisə edilir. Qəbul edək ki, massivin elementləri O-dan n- ə kimi nömrələnmişdir. Əgər massivdə açar element yoxdursa, onda tərtib edilmiş proqram bizə -1 qiyməti (bu şərtidir, istənilən əlamət seçmək olar) qaytaracaqdır. Axtarılan element massivdə təkrarlana və ya təkrarlanmaya bilər.

Hələlik şərtləşək ki, element təkrarlanmayacaq və ardıcıl axtarış üsulunun alqoritmini psevdokodla yazaq:

AXTARIŞ (massiv, n, x)

/*massiv - baxılan massivdirn - massivdə elementlərin sayıdır x - axtarılan elementdir* /

for (int i = 0; i < n i++) if (x==massiv[i]) return i end if

end forreturn -1

Bu psevdokod əsasında alqoritmin müxtəlif hallarda mürəkkəbliyini təhlil edək.

pis hal. Alqoritmin iki ən pis halı var: birinci halda axtarılan element massivin sonunda yerləşir, ikinci halda isə o massivdə, ümumiyyətlə, yoxdur. Alqoritm axtarılan elementi massivin bütün elementləri ilə müqayisə etdiyi üçün, belə müqayisələrin ümumi sayı n olacaqdır. Element massivdə olmadıqda da müqayisələrin ümumi sayı n olacaqdır. Deməli, n alqoritmin mürəkkəbliyinin yuxarı sərhəddi olacaqdır. Mürəkkəbliyin yuxarı sərhəddi ilə ən pis halda mürəkkəblik fərqli anlayışlardır. Yuxarı sərhəd

218 Məhərrəmov Z.T., Vəliyev H.P.

məsələnin özünə xasdır, ən pis hal isə onu həll edən alqoritmə aiddir.

Orta hal. Axtarış alqoritmi üçün də iki ora hal var: birinci halda nəzərdə tutulur ki, axtarış uğurla başa çatır, ikinci halda isə axtarılan element massivdə, ümumiyyətlə, yoxdur. Əgər axtarılan element massivdə mövcuddursa, onda o n mümkün haldan birinə uyğun gələ bilər: o birinci, ikinci, üçüncü və s. ola bilər. Bu vəziyyətlərin hər biri ilə rastlaşma ehtimalı bərabərdir və bu ehtimal 1/n olacaq. Aydındır ki, element massivdə birinci yerdə dayanarsa — 1, ikinci yerdə dayanarsa - 2, və s., n-ci yerdə dayanarsa, n sayda müqayisə aparılacaqdır. Onda orta halda orta hesablama vaxtının hesablanması üçün aşağıdakı düsturu yaza bilərik:

nA( s 1 V • ln<n + 4(n) = - ) ı =------- ------

nZ-ı n 2n + 1

2^O(n)

ı=ı

Element massivdə olmadıqda orta halın hesablama vaxtı cəmi ‘/ı qədər artacaqdır. Beləliklə, ardıcıl axtarış üsulunun mürəkkəbliyi O(n) olacaqdır.

İndi isə ardıcıl axtarış üsulunun C# dilində proqramını tərtib edək:

using System;

namespace AXTARISH {class Program {class ARDICIL_AXTAR {public int TAPILMADI = -1;

public int ADI—AXTAR(int[] massiv, int x)

{

Beşinci fəsil. Axtarış alqoritmləri 219

int netice = TAPILMADI;for (int i = 0; i < massiv.Length; i++) {

if (massiv[i] == x) {

netice = i;

return netice; )

public int USTUN_AXTAR(int[] massiv, int x)

{for (int i=0; i<massiv.Length; i++) (

ıf (massiv(ij == x){

return i;}

)return TAPILMADI;

public int NEZARETLI_AXTAR(int[j massiv, int say, int x)

(int sonuncu = massıv[say - 1];massiv[say - 1] - x;int i = 0;while (massiv[i] != x)

i ;

massivfsay - 1] = sonuncu;if (i<say~l ıI massiv[say-1j==x)

return i;

1

^2__________________ Məhərrəmov Z. T., Vəliyev H.P.

} return TAPILMADI; )

static void Main(string[] args) {// [0,n] parçasında təsadüfi ədədlərin// yaradılmasıint n = 20;int[] a = new int[n];Random r = new Random();Console.WriteLine("\nTesadufi ededler

massivi:" );for (int i = 0; ı < n; i++) (

a[i] = r.Next(0,n/2);Console.Write (a [i] + " ");

}

/*// [0,n] parçasında təkrarlanmayan // təsadüfi ədədlərin yaradılması int i = 0;while (i < n){int k = r.Next(0,n);ıf (a[kj == 0)(

a [ k ] = i ;

}}for (i = 0; i < n; i++)Console.Write( a[i]+" ");

*/

ARDICIL_AXTAR f = new ARDICIL_AXTAR(); int x = 3;

Beşinci fəsil. Axtarış alqoritmləri 221

Console.WriteLine("\n\nAxtarilan element: " + x);

Console.WriteLine("\nAxtarilan elementin massivde sira nomresi:");

Console.WriteLine("\nADI_AXTAR metodu ile i—" + f.ADI_AXTAR(a, x));

Console.WriteLine("\nUSTUN_AXTAR metodu ile i = " + f.USTUN_AXTAR(a, x) ) ;

Console.WriteLine("\nNEZARETLI_AXTAR metodu ile i=" +

f.NEZARETLI_AXTAR(a, n, x));

Console.Read(); 1 } }

Proqramın nəticəsi şəkil 5.1 -də göstərilmişdir.

■ lı F:\ZA»OR\VSA\AXTARISH\AXTARISH\bin\Debijç\AXTAREH.exe

Tesadufi ededler nassivi:93395921374886628

Axtarilan elenent: 3

Axtarilan elenent in nasslvda sira nonrssl:

ADI.AXTAR netodu ile 1-19

USTUN-AXTAR netodu ile 1-1

NEZARETLI_AXTAR netodu ile i-1

9 8 3

Şəkil 5.1. Ardıcıl axtarış üsulunun nəticəsi

Proqram tam ədədlərdən ibarət massivin elementini ardıcıl axtarmaq üçün üç üsuldan ibarətdir:

ADI AXTAR - ən sadə və uğursuz üsuldur. Bu üsulda istənilən halda massivin bütün elementləri axtarılır.

USTUN AXTAR - bu üsul o vaxt tətbiq edilə bilər ki. massivdə axtarılan elementə bərabər olan bir neçə element mövcuddur. Onda bu üsul dövrün başlanğıcında elementi

222 Məhərrəmov Z. T., Vəliyev H.P.

tapacaq, lakin massivin yerdə qalan bütün elementlərini araşdıracaqdır.

NEZARETLI_AXTAR - bu üsul hər iki üsulun çatış­mazlığından azaddır və elementi tapan kimi dərhal öz işini yekunlaşdırır.

Birinci iki üsulun girişinə int [ ] a massivi və tapılacaq element (int x), sonuncu üsula isə, bunlara əlavə olaraq, massivin elementlərinin sayı (int say) verilir. Hər üç üsulun nəticəsi axtarılan elementin sıra nömrəsi return i: olur. Əgər element tapılmazsa, üsullar -1 qiyməti qaytarır.

Main üsulunda a massivi təsadüfi ədədlərdən yaradılır. Burada iki variant nəzərdə tutulmuşdur: massivdə elementlər təkrarlanır və təkrarlanmır. Massivdə elementlərin təkrarlan- maması halını icra etmək üçün şərh işarələri daxilinə yerləşdirilmiş kodu aktivləşdirmək lazımdır (həmin kod elementləri təkrarlanmayan massiv yaradır).

5.2. Binar (ikili) axtarış üsulu

Yuxarıda qeyd etdik ki, binar axtarış nizamlanmış massivlərə tətbiq edilir. Axtarılan element massivin ortadakı elementi ilə müqayisə edilir və bu zaman aşağıdakı üç nəticədən biri ola bilər: qiymətlər bərabərdir, axtarılan element massivdəki elementdən kiçikdir və axtarılan element massivdəki elementdən böyükdür. Əgər qiymətlər bərabər- dirsə. deməli element tapılmışdır. Yerdə qalan hər iki halda massiv yarıya bölünür.

Əgər axtarılan element ortadakı elementdən kiçikdirsə, onda ortadakı elementdən sağ tərəfdəki elementlər nəzərdən atılır və ortadakı elementdən sol tərəfdəki elementlər yenidən yarıya bölünür və s.

Əgər axtarılan element ortadakı elementdən böyük­dürsə. onda ortadakı elementdən sol tərəfdəki elementlər

Beşinci fəsil. Axtarış alqoritmləri ... 223

nəzərdən atılır və ortadakı elementdən sağ tərəfdəki elementlər yenidən yarıya bölünür və s.

Belə yarıya bölmə əməliyyatları yerinə yetirildiyi üçün bu üsula varıya bölmə və ya dixolomiya üsulu da deyirlər.

Con Benlli Bcutjih - >KeMHy>KHHi>ı nporpaMMH- poBaHun kitabı) bu üsulu belə izah edir. “... Mən fikrimdə I- dən 100-ə qədər ədədlər içərisindən bir tam ədəd tuturam, Siz isə onu tapırsınız. Bu 5O-dir? Yox, 50-dən böyükdür. 75-dir? Yox, 75-dən kiçikdir. Və Siz mənim fikrimdə tutduğum ədədi tapana kimi oyun davam edir”.

Binar axtarışın mahiyyəti şəkil 5.2-də göstərilmiş təsvirlə tam aydın olur.

I 26 I 26 | 31 | 31 | 32 | 38 I 38 | 41 | 43 | 46 | 50 | 53 | 58 | 59 | 70 | 90 || | j

I 43 2

1

Şəkil 5.2. 50 ədədinin tapılması

Bu sxemlə 50 ədədinin tapılması nümayiş etdirilmişdir. Göründüyü kimi, massiv 16 elementdən ibarətdir. Onu yarıya bölürük. Elementlərin sayı tək ədəd, məsələn. 15 olduqsa intervalın uzunluğu 7 və ya 8 götürülə bilər. Bu son nəticəyə təsir etməyəcək. Baxılan halda intervalın ortası kimi 41 ədədi götürülmüşdür. Axtardığımız 50 ədədi 41-dən böyük olduğu üçün sol tərəfdəki elementləri nəzərdən atırıq və massivin sağ tərəfdə qalan hissəsini yarıya bölürük və görürük ki, 50<53. İndi (41, 53) intervahnı yarıya bölürük və s.

Alqoritmdə axtarılan element massivdəki qiymətə bərabərdirsə. bu ən yaxşı haldır və alqoritm axtarışı dərhal qurtarır. Yerdə qalan digər hallarda massivin elementlərinin yarısı atılır.

Beləliklə, binar axtarış alqoritmini psevdokodla belə təsvir edə bilərik:

BİNAR (a, n, x)

224 Məhərrəmov Z. T., Vəliyev H.P.

/*a - baxılan massivdirn - massivdə elementlərin sayıdı b - axtarılan elementdir*/

Sol=0Sağ=n-1while (Sağ - Sol > 1) {orta = (Sol + Sağ)/2; // Massivin

// ortasıif (a[orta)>=b) Sağ= orta; // Sağ

// sərhəddin yerini dəyişirik else Sol = orta; // Əks halda sol

// sərhəddin yerini dəyişirik j if (a[orta] == b) return Sağ;elsereturn -1

Alqoritmin mürəkkəbliyini təhlil edək.Alqoritm hər dəfə siyahını yarı böldüyünə görə, onu

təhlil etdikdə güman edəcəyik ki, hər hansı k üçün n = 2k - 1. Əgər bu belədirsə, onda ikinci keçiddə nə qədər element qalacaq? Bəs üçüncüdə? Ümumiyyətlə, bir neçə keçiddə dövr massivdə 27 — 1 sayda elementi emal edir, onda massivin birinci yarısında 27-1- 1 sayda element, ortasında bir element və siyahının ikinci yarısında 27-1 — 1 element olur. Buna görə növbəti keçidə 27-1 — 1 element qalır (1 <, j < k olduqda).

ün pis hal. Hər dövrdə massivin qalan elementlərinin sayı bir vahid azalır. Massivdə 1 element qaldıqda dövrün sonuncu iterasiyası icra olunur, bu isə / = 1 olduqda baş verir (belə ki. 21 — 1 = 1). Bu o deməkdir ki, n = 2k — 1

Beşinci fəsil. Axtarış alqoritmləri 225

olduqda dövrlərin sayı Ä-nı aşmayacaq. Sonuncu tənlikdən /< = ]og2(n + l) tapırıq. Bu isə O(log2(n)) mürəkkəbliyi deməkdir.

Orta ha!. Orta halı təhlil etdikdə ardıcıl axtarışda olduğu kimi, iki halın mümkün olmasını nəzərə alacağıq: birinci halda axtarılan element massivdə var, ikinci halda isə yoxdur. Ardıcıl axtarışda olduğu kimi, burada da göstərmək olar ki, hesablama vaxtı birinci halda log2(n + 1) — 1, ikinci halda isə log2(n + l)—7 olacaq. Bu ifadələrdən isə orta halda mürəkkəbliyin O(log2(n)) olması qənaətinə gəlirik.

O(]og2(n)) nə deməkdir? Əgər massiv 1000 elementdən ibarətdirsə, onda element 10 itcrasiyaya, 1000000 elementdən ibarət olduqda isə 20 itcrasiyaya tapılacaqdır. Bu isə kifayət qədər böyük sürətdir.

İndi binar axtarış üsulunun proqramını təqdim edək. Bu proqramda müqayisə etmək məqsədi ilə ardıcıl axtarış üsulu yenidən proqramlaşdırılmışdır. Hər iki üsulun proqramlarına giriş verilənləri kimi massiv, elementlərin sayı və axtarılan element daxil edilir.

using System;

namespace BINAR_ARDICIL (class Proqram {static int say; // müqayisələrin sayıstatic readonly int n=40; // elementlə-

// rin sayıstatic int;] a = new int[nl;

// Ardıcıl axtarış metodu static int ARDICIL(int b) { int k = -1;say = 0;

226 Məhərrəmov Z.T., Vəliyev H.P.

for (int i = 0; i < n; i++) {say++;ıf (a[i] == b){k = i; break;

} ;}return k;}

// Binar axtarış metodu static int BINAR(int b) {int orta; // massivin ortasıint sol = 0; // sol sərhədint sag = n - 1; // sağ sərhədorta = (sag + sol) / 2;say = 0;while (sol < sag - 1)fsay++;orta = (sag + sol) / 2;if (a [orta] == b) return orta;

say++;if (a[ortaj < b)

sol = orta;else

sag = orta;

if (a [orta] != b) {

if (a[sol] == b) orta - sol;

else{

if (a [ sag] == b) orta = sag;

Beşinci fəsil. Axtarış alqoritmləri 227

else orta = -1;

} } return orta;}

static void Main(string[] args) {// Təkrarlanmayan elementli nizamlanmış // təsadüfi ədədlər massivinin // yaradılması Random r = new Random();a [ 0 ] = r.Next(1, 5);Console.Write(a[0]);for (int i = 1; i < n; i++) {a[i] = a[i - 1] + r.Next(l, 20); Console.Write("\t{0} ", a[i]);

}

Console.WriteLine("\n----------------------") ;

Console.Write("\nAxtarilan elementi daxil edin: ");

int b = Convert.Tolnt32(Console.ReadLine());

Console.WriteLine("----------------------") ;

// Ardıcıl axtarış int k = ARDICIL(b); Console.WriteLine("Ardicil metodla

axtaris:");if (k > -1) Console.WriteLine("Axtarilan elementin

nomresi = {0}, Devr daxilindemuqayiselerin sayi = {1}", k, say);

else

228 Məhərrəmov Z. T., Vəliyev H.P.

Console.WriteLine("Axtarilan element yoxdur, Devr daxilinde muqayiselerin

sayia = { 0 } " , say);

Console.WriteLine("---------------------") ;

// Binar axtarış k = BİNAR(b);Console.WriteLine("Binar metodla

axtaris:"); if (k > -1)Console.WriteLine("Axtarilan elementin

nomresi = {0}, Devr daxilinde muqayiselerin sayi = {1}", k, say);

elseConsole.WriteLine("Axtarilan element yoxdur, Devr daxilinde muqayiselerin

sayi = {0}", say);Console.Read(); } } }

Proqramın nəticəsi şəkil 5.3-də göstərilmişdir. Şəkildən görünür ki. elementin tapılması üçün ardıcıl axtarış üsulu 27 müqayisə apardığı halda, binar üsul cəmi c müqayisəyə nəticəni tapır.

■ • F\ZA<lc\VS4\B:NAR_AftCiai\Bl'İAR^ARCHC:(.\b.n\0ebo9\e:NAR_AR0KT_d

Şəkil 5.3. Binar axtarış üsulunun nəticəsi və onun ardıcıl üsulla müqayisəsi

Beşinci fəsil. Axtarış alqoritmləri 229

Sonda qeyd edək ki, binar üsulunu binar ağac üzərində də yerinə yetirmək olar. Bu zaman massivin ortasında yerləşən element kök düyünü, ondan əvvəl və sonrakı elementlər isə müvafiq olaraq sol və sağ budaqları təşkil edəcək.

İ 0 1 2 3 4 5 6 7|

FƏSİL

NİZAMLAMAALQORİTMLƏRİ

6.1. Nizamlama alqoritmləri haqqında ümumi məlumatlar

Nizamlama - alqoritmlərin öyrənilməsi üçün çətin və əhəmiyyətli məsələlərdən biridir. Bu ondan irəli gəlir ki, birincisi, nizamlama bir sıra kompüter əlavələri üçün ümumi məsələdir. Praktiki olaraq, istənilən massiv (siyahı) o vaxt dəyərli olur ki, o müəyyən bir prinsip ilə nizamlanmış olur. İkincisi, bir sıra nizamlama alqoritmləri proqramlaşdırma nöqteyi-nəzərindən çox maraqlıdır.

Hər bir nizamlama alqoritminin özünün xarakteristi­kaları, üstün və çatışmayan cəhətləri vardır. Müxtəlif alqoritmlərin məhsuldarlığı verilənlərin tipindən, ilkin yerləşməsindən, ölçü və qiymətindən asılıdır. Konkret məsələ üçün ona uyun alqoritmin seçilməsi çox vacibdir.

Onlarla nizamlama alqoritmləri mövcuddur ki, onlardan bir neçəsi aşağıda göstərilmişdir:

• Xətti nizamlama (Select'ıon sort);• Yerləşdirməklə nizamlama (Insertion sort);• Qabarcıq alqoritmi (Bubble sort);

Altıncı fəsil. Nizamlama alqoritmləri 231

• Şell nizamlaması (Shell sort);• Piramidavari nizamlama (Heap sort);• Birləşdirməklə nizamlama (Merge sort);• Sürətli nizamlama (Quick sort);• Xarici çoxfazlı nizamlama (External polyphase

merging) və s.

Öyrənəcəyimiz baza alqoritmlərinin hamısında nəzərdə tutacağıq ki. massiv elementlərin qiymətlərinin artması ardıcıllığı ilə nizamlanacaqdır. Bu isə prinsipial əhəmiyyət kəsb etmir, çünki, alqoritmdə “>” işarəsini “<” işarəsi ilə əvəz etməklə massivin elementlərini onların qiymətlərinin azalması ardıcıllığı ilə nizamlamaq olar. Elementlər isə tam. sətir simvolları və ya daha mürəkkəb qiymətlər ola bilər. Əsas odur ki. biz həmişə bir cüt elementi müqayisə edəcəyik.

Ümumi halda yuxarıdakı üsulların nizamlama prinsiplərini şərh edək.

Xətti nizamlama (bu üsula seçməklə nizamlama deyirlər) alqoritmində massivin ən kiçik elementi tapılır və o nizamlanmamış massivin birinci elementi ilə müqayisə edilir. Əgər bu element daha kiçik olarsa, onda o yeni minimum olur və onların mövqeləri dəyişdirilir. Nəticədə birinci yerə birinci ən kiçik element, ikinci yerə ikinci ən kiçik element və s. yazılmış olur. Yerləşdirməklə nizamlama alqoritmində hər növbəti element artıq nizamlanmış massivin lazım olan yerinə qoyulur. Qabarcıq alqoritmində elementlər cüt-cüt müqayisə edilərək onların yerləri dəyişdirilir. Şell nizamlaması çoxkeçidli nizamlamadır, hər keçiddə massiv alt massivlərə bölünür, hər alt massiv ayrılıqda nizamlanır və bu zaman hər keçiddə alt massivlərin sayı azalır, onların uzunluğu isə artır. Piramidavari nizamlama alqoritmində binar ağac qurulur, hər bir düyündəki qiymət əcdadın qiymətini aşır. Nəticədə massivin ən böyük elementi kökə yerləşdirilir və onu pozduqdan sonra, növbəti piramidanı seçdikdə, kökdə növbəti böyük element rastlaşır. Bu proses

232 Məhərrəmov Z.T., Vəliyev H.P.

yeni massivdə bütün elementlər nizamlanana qədər davam etdirilir. Birləşdirməklə nizamlama alqoritmi artıq iki nizamlanmış massivi götürür və onları birləşdirməklə yeni nizamlanmış massiv yaradır. Sürətli nizamlama rekursiv alqoritmdən ibarətdir, həlledici element seçilməklə massiv iki hissəyə bölünür ki, bu massivlər uyğun olaraq seçilmiş elementdən kiçik və böyük elementlərdən ibarət olur. Birləşdirməklə xarici çoxfazlı nizamlama alqoritmi isə həddən çox böyük massivlərlə işləmək üçün nəzərdə tutulmuşdur. Bu massivlər o qədər böyük olur ki, onlar kompüterin yaddaşına sığışmır.

Biz sonrakı izahlarımızda həmişə massivlərin nizamlanmasından danışacağıq, lakin bütün mülahizələr eyni dərəcədə siyahılara da aiddir.

Qeyd edək ki, C# dilində massivlərlə işləmək üçün xüsusi Array sinfi və onun bir sıra metodları, o cümlədən, massivin elementlərinin nizamlanması üçün Sort () metodu mövcuddur. Bu metodla a massivini nizamlamaq üçün sadəcə bir kod yazmaq kifayətdir:

Array.Sort(a);Lakin bu halda elementlər yalnız artma sırası ilə

nizamlanır (artma sırası ilə nizamlanmış massivi sonradan ReverseO metodunu tətbiq etməklə əks ardıcıllıqla nizamlamaq olar). Bundan başqa, alqoritmin mahiyyəti aydın olmur və yalnız massivlərə tətbiq oluna bilir.

Ona görə biz yuxarıda sadaladığımız nizamlama üsullarının bir neçəsinin alqoritmlərinin tərtibinin xüsusiyyətlərini və onların mürəkkəbliyini izah edəcəyik.

6.2. Xətti nizamlama alqoritmi

Massivi nizamladıqda verilmiş ilkin ədədlərdən ən kiçiyi tapılır və o, yeni massivin birinci mövqeyinə yazılır, ilkin massivdən isə həmin ədəd yox edilir. İlkin massivin

Altıncı fəsil. Nizamlama alqoritmləri 233

yerdə qalan elementləri içərisindən ən kiçiyi tapılır, yeni massivin ikinci mövqeyinə yazılmaqla, ilkin massivdən həmin ədəd yox edilir. Növbəti elementlər üçün bu prosesi davam etdirməklə, sonuncu ən böyük ədədi alacağıq ki, bu ədəd yeni massivin sonuncu elementi olacaqdır. Belə alqoritmdə biz faktiki olaraq eyni ölçülü iki massivdən - ilkin və yeni massivlərdən istifadə edirik. Proqramlaşdırmada isə belə israfçılığa yol vermək olmaz (massiv çox böyük ölçülü ola bilər). İndi bu alqoritmi təkmilləşdirək.

Xətti nizamlama alqoritminin mahiyyəti aşağıdakılar­dan ibarətdir.

I. a, (/' = 1,. . .,«) massivinin ən kiçik elementini taparaq onu a/ elementinə yazaq. Bunun üçün a/ elementini verilmiş ilkin massivin bütün növbəti elementləri ilə müqayisə edək. Əgər hər hansı element a /-dən kiçik olarsa, onda onların yerlərini dəyişərək müqayisəetməni sonuncu elementə qədər davam etdirmək lazımdır. Belə müqayisə zamanı, əgər hər hansı element a/-dən böyük və ya ona bərabər olarsa, onda elementin yerini dəyişmədən növbəti elementlə müqayisəni davam etdirmək lazımdır.

2. Birinci mövqedəki elementi nəzərdən atmaqla, göstərilən prosesi ikinci mövqedən təkrar etmək lazımdır. Başqa sözlə, yerdə qalan elementlər içərisindən göstərilən üsulla ən kiçik elementi tapıb, onu a? elementinə yazmaq lazımdır.

3. Bu əməlləri, axırıncı element müstəsna olmaqla, bütün elementlər üçün icra etmək lazımdır.

Tutaq ki, bizə n ədəddən ibarət massiv verilmişdir. Qeyd edək ki, alqoritmin iş prosesində ədədlərin sayı dəyişmir: hər addımda biz ilkin yığımdan ədədlərdən birini yekun yığıma keçiririk. A-cı keçiddən sonra nəticə k ədəddən, ilkin yığım isə n-k sayda ədəddən ibarət olur.

Alqoritmi konkret misal üzərində nümayiş etdirək.6 ədəddən ibarət massiv üzərində alqoritmi izah edək: 3, 6, 1, 2, 9, 5.

234 Məhərrəmov Z. T., Vəliyev H.P.

Birinci addımda ən kiçik ədəd olan 1 tapırıq və onu birinci yerə keçirməliyik. Lakin orada 3 ədədi yerləşmişdir, bəs onu nə edək? Cavab sadədir: 3 ədədini 1 ədədinin yerinə keçirmək. Beləliklə, biz sadəcə olaraq iki ədədin yerini dəyişirik:

1 | 6, 3, 2, 9, 5.Biz şərti olaraq massivi iki hissəyə ayırdıq: sol hissədə

nizamlanmış, sağ hissədə isə ilkin massivin qalan elementləri.İkinci addımda biz sağ tərəfdəki ən kiçik ədədi tapırıq

(2) və onun yerini ikinci yerdəki ədədlə dəyişirik:1, 2 | 3, 6, 9, 5.Sonra biz növbəti minimal ədədi (3) tapıb, üçüncü

yerdəki ədədlə onun yerini dəyişməliyik, lakin həmin ədəd elə öz yerindədir. Biz buna əhəmiyyət vermirik, onu müqayisə edib özü ilə yerini dəyişirik və s.:

1, 2, 3 | 6, 9, 5*.Üsulun iş prinsipini anladıqdan sonra alqoritmin

aşağıdakı C# kodunu yaza bilərik:

using System;namespace SORT_XETTI {class Program {static void Main(string[] args) {Const int n= 20; int i,yeni,x;int'] a=new int[n];Console.WriteLine("{0,45}","XETTİ

NİZAMLAMA:");

// Təsadüfi ədədlərin yaradılması Random r = new Random();Console.WriteLine("\nTesadufi ededler

massivi:");for ( i = 0; i < n; i++) {

Altıncı fəsil. Nizamlama alqoritmləri 235

a[i] = r.Next(50, 100);Console.Write(a [i] +

}Console.Write("\n-------------------------

-\n");

// Xətti nizamlamafor (i = 0; i < n; i + +) {for (yeni=i+l; yeni<n; yeni++){

if (a [i] > a[yeni]) {

x = a [ i ] ;a[i] = a[yeni];a[yeni] = x;

}}

}Console.WriteLine("\nNizamlanmiş massiv:

") ;for (i = 0; i < n; i++)Console.Write(a[i]+"\t");

Console.ReadLine () ; } } }

Proqramın nəticəsi şəkil 6.1-də göstərilmişdir.

I! F\ZAKJR\VSA\SOKT_XErn\SORT_XEm\bin\Debug\SORT_XErn.exe

lesadufi ededler nassiui:7458

5753

9573

6963

6383

9865

»6 83 9912 64 81

6193

Uzanlannis nassiv:12 53 5? 58 61 63 63 64 65 69»3 74 81 83

83 93 95 96 98 99

Şəkil 6.1. Xətti nizamlama alqoritminin nəticəsi

236 Məhərrəmov Z. T., Vəliyev H.P.

İndi isə əməliyyatları &-cı addım üçün ümumiləşdirək və alqoritmin mürəkkəbliyini təhlil edək. Əvvəlcə bizə massivim k, k + mövqelərindəki ədədlər arasında ən kiçiyini tapmaq lazımdır. Bundan sonra həmin elementi £-cı elementlə dəyişmək lazımdır. Bəs bütün massivi nizamlamaq üçün bizə neçə addım lazım olacaq? İlk baxışda elə gəlir ki. n sayda. Lakin tələsməyək. Qəbul edək ki. n-1 addım yerinə yetirilmişdir. Onda nizamlanmamış sağ tərəfdə bir ədəd qalacaq və aydındır ki, bu ən böyük ədəddir. Yekunda o harada dayanmalıdır? Əlbəttə massivin sonunda. Ona görə də /7-ci addımı icra etmək lazım gəlmir.

Beləliklə, aydınlaşdırdıq ki, alqoritm n-1 dəfə minimum axtarır: birinci dəfə n elementlər arasında və buna n əməliyyat tələb olunur, ikinci dəfə n-1 element arasında və s. Beləliklə, minimumun axtarılması üçün n + (n — l) + ... + 3 + 2 = (n + 2)(n - l)/2 sayda əməliyyat tələb olunur ki, bu da təxminən n2/2 əməliyyat deməkdir. Minimumların öz yerlərinə keçirilməsinə n əməliyyat tələb olunur, rc-nin böyük qiymətlərində n2/2 qiyməti /?-dən çox- çox böyük olduğu üçün yerdəyişmə əməliyyatlarını nəzərə almamaq olar. Onda deyə bilərik ki, alqoritm n2/2 vaxt ərzində yerinə yetiriləcəkdir ki. bu da 0(n2') mürəkkəblikli alqoritm deməkdir.

Alqorilmdə ilkin massiv üçün tələb olunan yaddaşdan əlavə yaddaş tələb olunmur. Bu alqoritm ən sürətli olmasa da, böyük olmayan massivləri qənaətbəxş sürətlə nizamlayır. Bir sıra digər alqoritmlər o qədər mürəkkəbdir ki. hətta çox kiçik massivləri nizamladıqda belə, çox yavaş işləyir.

6.3. Yerləşdirməklə nizamlama alqoritmi

Yerləşdirməklə nizamlamanın əsas ideyası ondan ibarətdir ki, yeni element artıq nizamlanmış massivin ixtiyari yerinə yox, dərhal lazım olan yerinə əlavə edilir ki, bu da

Altıncı fəsil, Nizamlama alqoritmləri 237

sonradan bütün massivi yenidən nizamlamaqdan bizi azad edir. Yerləşdirməklə nizamlama istənilən massivin birinci elementini uzunluğu 1 olan nizamlanmış massiv hesab edir. İki elementli nizamlanmış massiv ilkin massivin ikinci elementini birinci elementi özündə saxlayan bir elementli massivin lazım olan yerinə yerləşdirməklə yaradılır. İndi ilkin massivin üçüncü elementini nizamlanmış iki elementli massivə yerləşdirmək olar. Bu proses o vaxta qədər təkrarlanır ki, ilkin massivin bütün elementləri massivin genişlənən nizamlanmış hissəsində olsun (şəkil 6.2).

g 111g 13141s 161Şəkil 6.2. Yerləşdirməklə nizamlama alqoritmi

Bütün bu prosesi reallaşdıran alqoritm belədir:

using System;

namespace SORT_YERLESH {class Program {

static void Main(string[] args) {const int n = 20;int i, yeni, x, yer;

238__________________ Məhərrəmov Z.T., Vəliyev H.P.

int[] a = new int[n];Console.WriteLine("{0,45, "YERLESHDİRMEKLE NİZAMLAMA:");

// Təsadüfi ədədlərin yaradılmasıRandom r = new RandomO;Console.WriteLine("\nTesadufi ededler

massivi:");for (i = 0; i < n; i++){

a[i] = r.Next(50, 100);Console.Write(a[i] + "\t");

)

Console.Write("\n---------------------------\n");

// Yerləşdirməklə nizamlama

for (i = 1; i < n; i++){yeni= a [ i];yer= i- 1;while ((yer >= 0) && (a(yer] > yeni)){ a[yer + 1] = a[yer];

yer = yer - 1;}

a[yer + 1]= yeni;}

Console.WriteLine("XnNizamlanmiş massiv: ") ;

for (i =0; ı < n; i++)Console.Write(a[i] + "\t");

Console.ReadLine () ;

I} }

Altıncı fəsil. Nizamlama alqoritnıləri 239

Proqramın nəticəsi şəkil 6.3-də göstərilmişdir.

Şəkil 6.3. Yerləşdirməklə nizamlamanın nəticəsi

Bu alqoritm əlavə edilən yeni qiyməti yeni dəyişəninə yazır. Sonra, o, massivdə bütün böyük elementləri bir mövqe sürüşdürərək (while dövründə) bu yeni element üçün yeri azad edir. Dövrün sonuncu iterasiyası yer + 1 nömrəli elementi yer+2 mövqeyinə keçirir. Bu onu bildirir ki, yer+1 mövqeyi "yeni" element üçün azad edilir.

Alqoritmi təhlil edək.Ən pis halın təhlili. Əgər while daxili dövrünə

baxsaq, onda görərik ki, ən çox əməliyyatlar o vaxt yerinə yetirilir ki, yenidən əlavə edilən element massivin artıq nizamlanmış hissəsində olan bütün elementlərindən kiçik olur. Bu halda, yer dəyişəninin qiyməti 0-a bərabər olduqda, dövrün icrası başa çatır. Ona görə də hər bir yeni element massivin başlanğıcına əlavə edildikdə alqoritm daha böyük miqdarda əməliyyat icra edir. Belə hal yalnız o zaman baş verir ki, ilkin massivdə elementlər azalma sırası ilə düzülmüş olsun. Bu ən pis hallardan biridir, lakin digər başqa hallar da mümkündür.

Massivin necə emal olunmasına baxaq. Birinci massivin ikinci elementi əlavə edilir. O cəmisi bir elementlə müqayisə edilir. İkinci əlavə edilən element (sıra ilə üçüncü)

240 Məhərrəmov Z. T., Vəliyev H.P.

əvvəlki iki elementlə, üçüncü əlavə edilən element — əvvəlki üç elementlə müqayisə edilir; ümumiyyətlə, z-ci əlavə edilən element əvvəlki i elementlə müqayisə edilir və bu proses n-1 dəfə təkrarlanır. Beləliklə, yerləşdirməklə nizamlama alqoritminin ən pis halda mürəkkəbliyini aşağıdakı düsturla hesablaya bilərik:

21 (n) = i = r-^(n - 1) = ^0(n2).

Başqa sözlə, yerləşdirməklə nizamlama alqoritminin ən pis halda mürəkkəbliyi O(n2) olur.

Orta halın təhlili. Orta halın təhlilini iki mərhələyə bölək. Əvvəlcə növbəti elementin vəziyyətinin təyini üçün lazım olan müqayisələrin orta qiymətini hesablayaq. Sonra birinci addımın nəticəsindən istifadə edərək bütün lazımlı əməliyyatların orta qiymətini hesablamaq olar, z-ci elementin yerini təyin etmək üçün lazım olan müqayisələrin orta qiymətinin hesablanmasından başlayaq. Biz artıq qeyd etdik ki, hətta, əgər element artıq öz lazımlı yerində dursa belə, massivə elementin əlavə edilməsi ən azı bir müqayisəetmə tələb edir.

z-ci element üçün nə qədər mümkün vəziyyətlər mövcuddur? Az elementli massivlərə baxaq və nəticəni ixtiyari sayda verilənlər üçün ümumiləşdirməyə cəhd edək. Birinci əlavə edilən element üçün iki imkan var: o nizamlanmış iki elementli massivdə birinci və ya ikinci ola bilər. İkinci əlavə edilən elementin 7, 2 və 3 nömrəli üç mümkün vəziyyəti ola bilər. Məlum olur ki, z-ci əlavə edilən element mümkün olan i+1 vəziyyətlərdən birində ola bilər. Qəbul edək ki, bütün bu imkanlar bərabər ehtimallıdır.

Hər bir mümkün i+1 mövqelərinə çatmaq üçün nə qədər müqayisələr tələb olunur? Yenə də z-nin kiçik qiymətlərinə baxaq və nəticəni ümumiləşdirməyə cəhd edək. Əgər dördüncü əlavə edilən element 5-ci mövqeyə düşürsə, onda artıq birinci müqayisə yalan olacaq. Əgər onun düzgün mövqeyi 4 olarsa, onda birinci müqayisə doğru, ikinci isə yalan olacaq. 3 mövqeyinə düşdükdə birinci və ikinci

Altıncı fəsil. Nizamlama alqoritmləri 241

müqayisələr doğru, üçüncü isə yalan olacaq. 2 mövqeyində birinci, ikinci və üçüncü müqayisələr doğru, dördüncü isə yalan olur. Birinci mövqeyə düşdükdə isə birinci, ikinci, üçüncü və dördüncü müqayisələr doğru olacaq, yalan müqayisələr isə olmayacaq. Bu onu bildirir ki, i 4-1, i, i — 1, 1, 2 mövqelərinə düşən z’-ci element üçün müqayisələrin sayı müvafiq olaraq 1,2, 3, ..., i-yə bərabər olacaq, birinci mövqeyə düşdükdə isə müqayisələrin sayı i- yə bərabər olacaq, z-ci elementin əlavə edilməsi üçünmüqayisələrin orta qiyməti belə hesablana bilər:

Bu, z-ci elementi əlavə etmək üçün tələb olunan əməliyyatların orta qiymətidir. İndi bu nəticələri massivin hərbir n-1 elementi üçün cəmləmək lazımdır:

i=ı ı=ı

n-1 n-1

Sonuncu düsturda çevirmələr apararaq yerləşdirməklə nizamlama alqoritminin orta halı üçün aşağıdakı mürəkkəblik ifadəsini alarıq:

— n4

n A(n)~— + (n — 1) — (İn n — 1) =

n2 + 3n - 44

n- (İnn — İ)*— ^>0(n2).

242 Məhərrəmov Z. T., Vəliyev H.P.

6.4. Qabarcıq alqoritmi

Daha bir üsula baxaq. Bu üsul “qabarcıq” üsulu adlanır. Bu alqoritmin işləmə prinsipi çox sadədir: massivin birinci elementindən sonuncu elementinə qədər keçirik, yolüstü nizamsız qonşu elementlərin yerini dəyişirik. Nəticədə birinci keçiddə sonuncu yerə ən böyük element “üzüb” çıxır. Massivin nizamlanmamış hissəsindən (birinci elementdən sonuncudan əvvəlkinə kimi) yenidən keçirik və yolüstü nizamsız qonşu elementlərin yerini dəyişirik. İkinci ən böyük element sonuncudan əvvəldə yerləşəcək. Bu qayda ilə massivin hər dəfə kiçilən nizamlanmamış hissəsindən keçməklə maksimal elementi sona yerləşdiririk. Mahiyyət etibarı ilə hər bir element “qabarcıq” kimi üzüb öz yerinə keçir. Şəkil 6.4-də göstərilmiş misalda əvvəlcə alqoritm aşkar edir ki, 6 və 3 elementləri nizamsızdır və onların yerlərini dəyişir. Növbəti keçiddə 5 və 3 elementlərinin, növbəti keçiddə 4 və 3 elementlərinin yerlərini dəyişir. Daha bir növbəti keçiddə aşkar edir ki, elementlər nizamlanmışdır və öz işini dayandırır.

Şəkil 6.4. Elementin “üzməsi”

Altıncı fəsil. Nizamlama alqoritmləri 243

Dediklərimizi ümumiləşdirərək üsulun mahiyyətini belə izah etmək olar. Məlumdur ki, massivin elementləri artma sırası ilə düzülmüşdürsə, onda hər bir element özündən sonrakı elementdən kiçik olacaqdır. Bu sadə fakt qabarcıq üsulunun əsas ideyasını təşkil edir. Belə ki, məhz bu qayda massivlərin elementlərini yeni üsulla müqayisə etməyə əsas verir, yəni kifayətdir ki, yalnız bir cüt qonşu ədədləri müqayisə edək. Əgər xətti nizamlama alqoritmində a/ elementini yerdə qalan bütün elementlərlə müqayisə etmək lazım gəlirdisə, bu alqoritmdə a,ı elementini yalnız a2 ilə müqayisə etmək kifayətdir. Əgər aı<a2 olarsa, onda a2 elementini a2 ilə, a2 elementini a4 ilə və s. müqayisə etmək lazımdır. Belə müqayisə zamanı hər hansı element birbaşa özündən sonra gələn elementdən böyük olarsa, onda onların yerlərini dəyişməklə müqayisəetməni sonadək davam etdirmək lazımdır. Lakin, yerdəyişmə zamanı elə ola bilər ki, a3 elementi a^-dən kiçik olsun. Bu isə o deməkdir ki, növbəti dövr başa çatdıqdan sonra, massivin başlanğıcına qayıdaraq elementlərin cüt-cüt müqayisəetmə prosesini təkrarlamaq lazımdır.

Beləliklə, qabarcıq üsulunun alqoritmi belə olacaqdır: massivin qonşu elementlərini, yəni a/ elementini a2 ilə, a2 elementini 03 ilə, a2 elementini a4 ilə və nəhayət elementini an ilə müqayisə etməklə, müqayisəetmə prosesini 0 qədər təkrar etmək lazımdır ki, elementlərin yeri artıq dəyişməsin.

Üsulun proqramını belə tərtib edə bilərik:

using System;

namespace SORT_QABARCIQ(class Program {static void Main(string[] args) <

244 Məhərramov Z.T., Valiyev H.P.

const int n - 20;int i,x;bool sort;int [ ] a = new int[20];Console.WriteLine("{0,50}", "QABARCIQ

ÜSULLA NİZAMLAMA:");

// Təsadüfi ədədlərin yaradılması Random r = new Random();Console.WriteLine("\nTesadufi ededler

massivi:");for (i = 0; i < n; i++) (a[i] = r.Next(50, 100);Console.Write(a[i] + "\t");

)Console.Write("\n-------------------------

-\n");

// Qabarcıq nizamlama do {sort = false;for (i = 0; i < n-1; i++)if (a[i] > a[i + 1]) {

x = a [ i ] ;a[i] = a[ı+l];a [ i +1 ] = x ; sort = true;

) ) while (sort != false);

Console . Wrı teLme ( " \nNizamlanmişma s s1v:" ) ;

for (i = 0; i < n; i++)Console.Write (a [ı] + "\t");

Altıncı fəsil. Nizamlama alqoritmləri 245

Console.ReadLine();} } }Proqramın nəticəsi şəkil 6.5-də göstərilmişdir.

Şəkil 6.5. Qabarcıq alqoritminin nəticəsi

Ən yaxşı halın təhlili. Hansı halda görüləcək işin həcminin ən az olacağını araşdıraq. Birinci gedişdə for dövrü tamamilə yerinə yetirilməlidir, ona görə də alqoritm ən azı n-1 sayda müqayisələr aparacaqdır. Burada iki hal ola bilər: birinci gedişdə ən azı bir yerdəyişmə aparılmışdır və yerdəyişmə aparılmamışdır. Birinci halda sort yerdəyişmə dəyişəninin qiyməti true olacaq, deməli, while dövrü təkrarən icra olunacaq, bu isə daha n-1 sayda müqayisə tələb edəcəkdir. İkinci halda isə sort dəyişəni özünün false qiymətini saxlayacaq və alqoritmin yerinə yetirilməsi dayanacaqdır. Ona görə də ən yaxşı halda, birinci gedişdə yerdəyişmə aparılmadıqda. n-1 sayda müqayisələr aparılacaqdır.

İlkin vəziyyətdə massivlərin elementləri müəyyən dərəcədə nizamlanmış olduqda qabarcıq üsulu daha səmərəli olur. Ona görə də bu üsulu ilk növbədə əvvəlcədən qismən nizamlanmış massivlər üçün tətbiq etmək daha sərfəlidir.

Ən pis halın təhlili. İlkin verilənlərin ən pis halı odur ki, massivdə elementlər əks ardıcıllıqla düzülsün. Əgər ən böyük element birinci yerdə durarsa, onda massivin sonuna qədər bütün qalan elementlərlə onun yeri dəyişdiriləcək. Birinci gedişin əvvəlində qiymətinə görə ikinci böyük

246 Məhərrəmov Z. T., Vəliyev H.P.

element ikinci mövqeyi tutur, ancaq birinci müqayisə və birinci yerdəyişdirmə nəticəsində o birinci yerə yerləşdirilir. İkinci keçidin başlanğıcında artıq qiymətcə böyük olan ikinci element birinci mövqedə durur və axırıncıdan əvvəlki elementə qədər bütün qalan elementlərlə onun da yeri dəyişdirilir. Bu proses bütün qalan elementlər üçün təkrarlanır, ona görə də for dövrü n-1 dəfə təkrarlanacaq.

Ən pis halda neçə müqayisə yerinə yetirilir? Birinci keçiddə qonşu qiymətlərin n-1 sayda müqayisəsi, ikincidə isə n-2 sayda müqayisəsi yerinə yetiriləcək. Sonrakı tədqiqatlar göstərir ki, hər növbəti keçiddə müqayisələrin sayı 1 vahid azalır. Buna görə ən pis halda mürəkkəblik aşağıdakı düsturla qiymətləndirilə bilər:

LAW =

t=n-ı2n — n

2~-n2 ^>O(n2).

Orta halın təhlili. Yuxarıda göstərdik ki, ən pis halda for dövrü n-1 dəfə təkrarlanacaqdır. Orta halda nəzərdə tutacağıq ki, elementlərin yerlərinin dəyişməməsi halı hər gedişdə eyni ehtimallıdır. Hər gedişdə nə qədər müqayisələrin aparılacağına baxaq. Birinci gedişdən sonra dayandıqda müqayisələrin sayı n-l-ə bərabərdir. İki gedişdən sonra müqayisələrin sayı n-l+n-2 olur. Birinci i keçidlərdə yerinə yetirilmiş müqayisələrin sayını C ilə işarə edək. Heç bir yerdəyişdirmə olmadıqda, alqoritm öz işini dayandırır, ona görə də orta halı təhlil etdikdə bütün bu imkanlara baxmaq lazımdır. Nəticədə aşağıdakı bərabərliyə gəlirik:

4(n) = C(0,n — 1 2—।

Altıncı fəsil. Nizamlama alqoritmləri 247

harada ki, C(i) ilk i gedişləri ərzində for dövründə müqayisələrin sayıdır. C(i) belə hesablanır:

və ya(n - l)n (i - l)i n2-n-i2 + i

C(t) = 2 2 = 2 ‘Onda A(N) üçün belə düstur alarıq:

n-1 7 ?1 n — n — i + i-4(n)=----- -) --------- ---------- .

n — 1 L-ı 21 = 1Müəyyən çevirmələr apardıqdan sonra A(n) üçün

aşağıdakı düsturu ala bilərik:

/l(n) =n7- — n n(2n — 1) n

2 12 + 44n2 — 2n 1---- —---- ^0(n2).

Qabarcıq alqoritmi əsasən tədris prosesində istifadə edilir, praktiki məsələlərin həllində isə, demək olar ki, istifadə edilmir. Lakin o. bir sıra daha mükəmməl nizamlama alqoritmlərinin əsasını təşkil edir.

6.5. Şell alqoritmi

Bu nizamlama alqoritmi Şell (Donald L. Shell) tərəfindən təklif edilmişdir. Onun qeyri-adiliyi ondan ibarətdir ki, o bütün massivə qarışdırılmış alt massivlərin məcmusu kimi baxır. İlk addımda bu alt massivlər sadəcə iki elementdən ibarət olur. İkinci addımda hər qrupda dörd element olur. Proses təkrar edildikcə hər alt massivdə elementlərin sayı artır, alt massivlərin sayı isə, müvafiq

248 Məhərrəmov Z.T., Vəliyev H.P.

olaraq, azalır. Şəkil 6.6-da alt massivlər təsvir edilmişdir ki, onları 16 elementdən ibarət massivin nizamlanması üçün istifadə etmək olar.

a) Birinci keçid

b) İkinci keçid

5 4 2 1 6 7 3 B 14 11 9 12 16 13 10 15

2 1 3 4 5 7 b 8 9 1 1 10 12 14 13 16 1 5

c) Üçüncü keçid

d) Dördüncü keçid

Şəkil 6.6. Şell alqoritmində dörd keçidin izahı

6.6 (a) şəklində səkkiz alt massiv təsvir edilmişdir, hər massivin iki elementi vardır. Burada, birinci massivə birinci və doqquzuncu elementlər, ikinci massivə — ikinci və onuncu elementlər və s. daxil edilmişdir. 6.6 (b) şəklində biz artıq hər birində dörd element olan dörd massiv görürük. Bu dəfə birinci massivə birinci, beşinci, doqquzuncu və on üçüncü elementlər daxildir. İkinci massiv ikinci, altıncı, onuncu və on dördüncü elementlərdən ibarətdir. 6.6 (c) şəklində, müvafiq olaraq, tək və cüt nömrəli elementlərdən ibarət iki massiv göstərilmişdir. 6.6 (d) şəklində biz yenidən bir massivə qayıdırıq.

Altıncı fəsil. Nizamlama alqoritmləri 249

Alt massivlərin nizamlanması yuxarıda izah etdiyimiz yerləşdirməklə nizamlama alqoritminin bir dəfə tətbiq edilməsi yolu ilə yerinə yetirilir, yəni əslində Şell nizam­laması yerləşdirməklə nizamlamanın modifıkasiyasıdır.

Şell nizamlamasının tam alqoritmini belə tərtib edə bilərik:

using System;namespace SORT_SHELL ıclass Program ıstatic void Main(string[] args) tconst int n = 20; int i, t;int d; // Nizamlama addımıbool k; // Yerdəyişmə əlaməti int[] a - new int[20];Console.WriteLine("{0,50}" , "ŞELL ÜSULU

İLE NİZAMLAMA:");

// Təsadüfi ədədlərin yaradılması Random r = new Randomf);Console.WriteLine("\nTesadufi ededler

massivi:");for (ı = 0; ı < n; İ++) {

a[i] = r.Next(50, 100);Console.Write(a [i] + "\t");

}Console.Write("\n--------------------------

-\n");

// Şell üsulu int q;d= Math.DıvRem(n, 2, out q) ;

//başlanğıcda nizamlama addımı massivin //uzunluğunun yarısına bərabərdir

254 Məharrəmov Z.T., Vəliyev H.P.

while (d > 0) {

k ~ true;// hələ ki yerdəyişmələr var while (k)(

k = f a 1 s e;i = 1 ;for (i =0; i <= n - d-1; i++) ı l

// SORT_YERLESH alqoritmi:// d intervalında elementlərin// müqayisəsi

if (a [i] > a [i + d ] ){

t = a [ i ] ;a[i] = a[i + d];a [ i + d ] = t ;k = true;

1}

}// nizamlama addımını 2 dəfə azaldırıq d = Math.DivRem(d, 2, out q) ;1

Console.WriteLine("\nNizamlanmiş massiv:");

for (i = 0; i < n; i++) Console.Write(a[i] + "\t");

Console.ReadLine() ;} } }Proqramın nəticəsi şəkil 6.7-də göstərilmişdir.Alqoritmi təhlil edək. Bu alqoritmin təhlili

SORT_YERLESH alqoritminin təhlilinə əsaslanır. Shell-

Altıncı fəsil. Nizamlama alqoritmləri 251

_Sort alqoritminin təhlilinə keçməzdən əvvəl, xatırlayaq ki. n elementdən ibarət massiv üçün SORT YERLESH alqoritmi ən pis halda (n2 — n)/2 əməliyyat, orta halda isə n2/4 əməliyyat tələb edir.

Şəkil 6.7. Şell üsulu ilə nizamlamanın nəticəsi

Təhlilə SORT_YERLESH prosedurunun neçə dəfə çağrılmasından və hər çağırış zamanı massivdə elementlərin sayından başlayaq. Massivdə elementlərin sayının 15 olduğu xüsusi hala baxaq (şəkil 6.6). Birinci keçiddə d dəyişəninin qiyməti 7-yə bərabərdir, buna görə uzunluğu 2 olan massivlərdə SORT_YERLESH üsulu yeddi dəfə çağrılacaqdır. İkinci keçiddə d dəyişəninin qiyməti 3-ə bərabərdir, buna görə uzunluğu 5 olan massivlərdə həmin üsul üç dəfə çağrılacaqdır. Üçüncü və son keçiddə uzunluğu 15 olan massivdə bu üsul bir dəfə çağrılacaqdır. Bilirik ki. iki elementdən ibarət massivdə SORT_YERLESH alqoritmi ən pis halda bir müqayisə edir. 5 elementdən ibarət massivdə ən pis halda müqayisələrin sayı 10-a bərabərdir. 15 elementdən ibarət massivdə ən pis halda müqayisələrin sayı 105-ə bərabərdir. Bütün bu ədədləri toplayaraq, biz cəmi 142 müqayisə (7-1 + 3-10 + 1105) alırıq. Biz yaxşı nəticəmi aldıq? Bilirik ki, yerləşdirməklə nizamlamada ən pis halda hər əlavə edilən yeni element massivin başlanğıcına əlavə edilir. Bilirik ki. SORT_SHELL alqoritminin sonuncu keçidində bu ən pis hal həyata keçirilə bilmir, ona görə ki, əvvəlki mərhələlərdə də həmçinin nizamlama həyata

252 Məhərrəmov Z. T., Vəliyev H.P.

keçirilmişdi. Bəlkə, başqa yanaşma işin qalmış həcmini hesablamağa kömək edə bilər?

Nizamlama alqoritmlərinin təhlilində biz bəzən massivdə inversiyaların miqdarını hesablayacağıq. İnversiya — massivdə düzgün olmayan ardıcıllıqla gedən bir cüt elementdir. Məsələn. [3, 2, 4, 11 massivində dörd inversiya - (3, 2), (3, 1), (2, 1) və (4, 1) vardır. Asanlıqla görmək olar ki, inversiyaların ən çox sayı elementləri əks ardıcıllıqla düzülmüş massivdədir: onların sayı (n2 — n)/2 qədərdir.

Nizamlama alqoritminin təhlili üsullarından biri massivin başlanğıc vəziyyətini massivin nizamlanmamış vəziyyətindən fərqləndirən inversiyaların sayını hesabla­maqdan ibarətdir. Alqoritmdə elementlərin hər bir yerdəyişməsi inversiyaların sayını ən azı bir vahid azaldır. Məsələn, qabarcıq nizamlamasında müqayisə nəticəsində, əgər düzgün ardıcıllıqla getməyən iki qonşu element aşkar edilərsə, onda onların yerlərinin dəyişdirilməsi inversiyaların miqdarını düz bir vahid azaldır. Bu fakt yerləşdirməklə nizamlamaya da aiddir. Ona görə qabarcıq və yerləşdirməklə nizamlamada (hər ikisinin mürəkkəbliyi 0(n2) ilə ifadə olunur) hər bir müqayisə bir (və ya daha az) inversiyanı silməyə gətirib çıxara bilər.

Şell nizamlamasının əsasını yerləşdirməklə nizamlama təşkil edir, buna görə də elə görünə bilər ki, həmin iddia burada da özünü doğruldur. Ancaq, nəzərə alsaq ki, Şell nizamlamasında qarışıq alt massivlər nizamlanır, elementlərin yerdəyişməsi inversiyaların sayını birdən çox artıra bilər. Şəkil 6.6-da birinci keçiddə 16 və 14 elementləri müqayisə edilirdi; düzgün yerləşmədiyi üçün onların yeri dəyişdirildi. 16 elementini birinci yerdən doqquzuncu yerə dəyişməklə, biz bu elementdən ibarət yeddi inversiyadan qurtulduq (bu inversiyaların ikinci elementləri ikinci- səkkizinci mövqelərdə yerləşmişdir). Elementlərin həmin yerdəyişməsi 14 elementindən ibarət yeni yeddi inversiyanın yaranmasına gətirib çıxarır. Ona görə o inversiyaların ümumi

Altıncı fəsil. Nizamlama alqoritmləri 253

miqdarını yalnız 1 vahid azaltdı. Əgər 7 və 4 elementlərinin yerdəyişməsinə baxsaq, onda həmin nəticəni alarıq. Ancaq bütövlükdə vəziyyət yaxşılaşır. Birinci keçiddə səkkiz müqayisədən sonra 36 inversiya silindi. İkinci keçiddə 19 müqayisə aparılmışdır və 24 inversiya silinmişdir. Nəhayət, sonuncu addımda 19 müqayisə edilmişdir və 10 son inversiya silinmişdir. Müqayisələrin ümumi miqdarı 62-ə bərabərdir. Hətta, əgər biz yerləşdirməklə nizamlamada ən pis halı orta hal ilə əvəz etsək belə, həmin üsulu çağırdıqda cəmi 152 müqayisə aparılardı.

Sübut edilmişdir ki, seçdiyimiz addımın qiymətləri daxilində, ən pis halda bu alqoritmin mürəkkəbliyi O(/V3^2) bərabərdir.

6.6. Sürətli nizamlama alqoritmi

Sürətli nizamlama mübadilə prinsipinə əsaslanan təkmilləşdirilmiş üsuldur. Qabarcıq nizamlama bütün alqoritmlər içərisində ən effektsiz alqoritmdir. Ancaq təkmilləşdirilmiş alqoritm məşhur üsullar içərisində ən yaxşı rekursiv nizamlama üsuludur. O elə yaxşı xarakteristikalara malikdir ki, onun müəllifi olan T.Hoar (Tony Hoarc) onu sürətli nizamlama adlandırmışdır. Bu nizamlama “parçala və hökm et” alqoritmlər sinfinə aiddir.

Massivdə həlledici adlandırılan hər hansı element seçilir. Sonra o bütün elementlər nizamlandıqdan sonra massivin lazım olan yerinə yerləşdirilir. Həlledici element üçün uyğun yerin tapılması prosesində elementlərin yerləri elə dəyişdirilir ki. onlardan solda həlledici elementdən daha kiçik, sağda isə daha böyük elementlər yerləşir (nəzərdə tutulur ki, massiv artma istiqamətində nizamlanır).

Bununla da massiv iki hissəyə parçalanır:• həlledici elementdən solda nizamlanmamış

elementlər; ■'

254 Məhərrəmov Z.T., Vəliyev H.P.

• həlledici elementdən sağda nizamlanmamış elementlər.

Aşağıdakı misalın nümunəsində (şəkil 6.8) massivin nizamlanmasını izah edək.

10, 4, 2, 14, 67, 2, 11, 33, 1, 15.

a)sağ

15

həlledici sol

10 4 2 14 67 2 11 33 1

b)həlledici sol sağ

c)

d)

e)

10 4 67 2 11 33 14 15

həlledici sol sağ

10 4 2 1 2 67 11 33 | 14 | 15~

həlledici sağ sol

1 10 67 11 33 14 15

sağ həlledici

2 4 2

2 T

Şəkil 6.8. Sürətli nizamlama alqoritminin izahı

Nizamlama alqoritminin reallaşdırılması üçün massivin sol kənar elementinə left göstəricisi istifadə edək. Neçə ki, göstərdiyi elementlər həlledici elementdən kiçikdir, bu

Altıncı fəsil. Nizamlama alqoritmləri 255

göstərici sağa hərəkət edir, right massivin sağ kənar göstəricisi olsun. O isə neçə ki, göstərdiyi elementlər həlledici elementdən böyükdür, sola hərəkət edir.

Tutaq ki, sol kənar element — həlledici element­dir. sol göstəricisini onun ardınca gələn növbəti elementin, sağ göstəricisini isə sonuncunun üzərinə qoyaq (şəkil 6.8. a)). Alqoritm 10 elementin düzgün vəziyyətini müəyyən etməlidir və işin gedişində düzgün yerləşməmiş elementlərin yerlərini dəyişməlidir.

Göstəricilərin hərəkəti o vaxt dayanır ki, həlledici elementə nisbətən düzgün yerləşməmiş elementlər rast gəlsin.

left göstəricisi 10-dan böyük elementi göstərənə qədər, right göstəricisi isə 10-dan kiçik elementi göstərənə qədər hərəkət edir (şəkil 6.8, b)). Bu elementlər yerlərini dəyişir və göstəricilərin hərəkəti bərpa olunur (şəkil 6.8, c)). Proses right göstəricisi left göstəricisindən solda yerləşənə qədər davam edir (şəkil 6.8, d)). Bununla da həlledici elementin düzgün yeri müəyyən ediləcəkdir, right göstəricisinin göstərdiyi elementlə həlledici elementin yerlərinin dəyişdirilməsi həyata keçirilir (şəkil 6.8, e)}. Həlledici element lazım olan yerdədir: ondan soldakı elementlər daha kiçik, sağdakılar isə böyükdür.

Bu alqoritmin C# dilində kodunu belə yaza bilərik.

using System;namespace SORT_SURET iclass Program{static int n = 2 0;static int i, j ;static int [ ] a = new int[n];// Sürətli nizamlamastatic void Sort (int sol, int sag) // sol -massivin sol kənarı, // sag-sağ kənarıdır

256 Məhərrəmov Z, E, Vəliyev H.P.

Imt xl, yl, orta;i = sol;j = sag;decımal s=(sol+sag)/2;orta = (int)Math.Round(s); // orta

// elementxl = a [orta];doiwhile (a[i] < xl) { i++; } /* neçə kı,

sol element orta elementdən kiçikdir, sol kənarı sağa sürüşdürürük */

while (a [j] > xl) { j —; ) /*neçə ki, sağ element orta elementdən böyükdür, sağ kənarı sola sürüşdürürük */

if (i <- j) // əgər sol və sağ// bitişsə

{yl = a [i] ;a[i] “ a[j]; // sol və sağı

// dəyişdiririka [ j ] = yl'i++; // solu sağaj ’ // sağı sola

) ) while (i < j) ; // bir yerdəyişmənin

// sonuif (sol < j) Sort(sol, j); // ya soı,

// ya da sağ tərəfiif (i < sag) Sort(i, sag); // rekursiv

// nizamlayırıq )

static void Main(string[] args) (

Altıncı fəsil. Nizamlama alqoritmləri 257

Console.WriteLine("{0,45}", "SURETLI NİZAMLAMA:");

// Təsadüfi ədədlərin yaradılması Random f = new Random();Console.WriteLine("\nTesadufi ededler

massivi: ") ;for (i = 0; i < n; i++){a[i] = f.Next(50, 100);Console.Write(a [i] + "\t");

}

Sort ( 0, n-1) ;

Console.WriteLine("\n----------------------------\n");

for (int i = 0; i < n; i++) { Console.Write (a [i] + "\t");

} Console.Read(); } } }

Proqramın nəticəsi şəkil 6.9-da göstərilmişdir:

Tl F:\ZACRWSA\SORT SURET\SORT_SURI:T\bin\Debug\SOKT SURET.exe

Şəkil 6.9. Sürətli nizamlama alqoritminin nəticəsi

Alqoritmin mürəkkəbliyinin təhlilini izah edək. Aydındir ki, həlledici element ətrafında massivin iki hissəyə bölünməsi O(n) qədər vaxt tələb edir. Bir rekursiyada bütün əməliyyatlar massivin ayrı-ayrı hissələrini emal etdiyinə görə

258 Məhərrəmov Z. T., Vəliyev H.P.

hər rekursiya səviyyəsində həmçinin O(n) qədər vaxt tələb olunur. Buradan da aydın olur ki, alqoritmin ümumi mürəkkəbliyi rekursiyanın səviyyəsi ilə müəyyən olunur. Rekursiyanın dərinliyi isə, öz növbəsində, giriş verilənlərindən və həlledici elementin tapılması üsulundan asılıdır. Ən yaxşı halı təhlil edək.

Ən yaxşı halın təhlili. Tarazlıq halında massivi hər dəfə böldükdə o, demək olar ki, iki bərabər hissəyə bölünür. Deməli, emal edilən alt massivlərin ölçüləri 1 olduqda, rekursiyanın dərinliyi log2n olacaqdır. Nəticədə müqayisələrin sayı Cn = 2-Cn/2 + n rekursiv ifadəsinə bərabər olacaqdır ki, bu da alqoritmin ümumi mürəkkəbliyinin 0(nlog2n) olduğunu bildirir.

Orta halın təhlili. Giriş verilənləri təsadüfi paylandıqda orta mürəkkəbliyi yalnız ehtimalla qiymətləndirmək olar. Hər şeydən əvvəl qeyd etmək lazımdır ki, həqiqətdə məcburi deyil ki, həlledici element massivi hər dəfə iki eyni hissəyə bölsün. Məsələn, əgər hər mərhələdə ilkin massiv 75% və 25% uzunluqlu massivlərə bölünərsə, onda rekursiyanın dərinliyi log^yn olacaq ki, bu da əvvəlki mürəkkəbliyi verir.

Bölməni o vaxt “uğurlu” hesab edəcəyik ki, həlledici element bölünən massivin 50% mərkəzi elementlərinin arasına düşsün. Aydındır ki, elementlər təsadüfi paylandıqda uğur ehtimalı 0.5 təşkil edir. Uğurlu bölgüdə ayrılmış alt massivlərin ölçüləri 25%-dən az və 75%-dən çox olmur. Hər bir ayrılmış alt massiv də təsadüfi paylanacaqdır, ona görə də bu mülahizələr istənilən nizamlama mərhələsinə və massivin istənilən ilkin fraqmentinə tətbiq oluna bilər.

Uğurlu bölgüdə rekursiyanın dərinliyi log^/^n -dən çox olmur. Uğur ehtimalı 0,5 olduğu üçün k sayda uğurlu bölmə almaq üçün orta hesabla 2-k sayda rekursiv çağırış tələb olunur ki, həlledici element k dəfə 50% massivin mərkəzi elementlərinin arasında olsun. Bu mülahizələri tətbiq etməklə belə qənaətə gəlmək olar ki, rekursiyanın dərinliyi orta hesabla 2-Zo^4/37t-dən çox olmayacaqdır ki, bu da bizə

Altıncı fəsil. Nizamlama alqoritmləri 259

O(logn) mürəkkəbliyini verir. Hər rekursiya səviyyəsində O(n} -dən çox əməliyyat yerinə yetirilmədiyi üçün orta mürəkkəblik O(n-logn) olacaqdır.

On pis halın təhlili. Ən tarazlaşdırılmamış variantda hər bölmə 1 və n-1 ölçülü iki alt massiv verir, yəni hər rekursiv çağırışda böyük massiv əvvəlki dəfədən 1 vahid kiçik olacaq. Bu o zaman ola bilər ki, hər mərhələdə həlledici element kimi bütün emal edilənlər arasında ya ən kiçik, ya da ən böyük element seçilsin. Sadə halda həlledici element kimi massivdə birinci və ya sonuncu element seçilir. Bu halda n-1 bölmə tələb olunur, ümumi iş vaxtı — 0 = 0(n2) əməliyyat təşkil edir, başqa sözlə, nizamlama vaxtın kvadratı ərzində yerinə yetiriləcəkdir. Lakin yerdəyşmələrin sayı və uyğun olaraq iş vaxtı onun ən böyük çatışmazlığı deyildir. Pis odur ki, bu halda rekursiyanın dərinliyi n olacaq, bu isə o deməkdir ki, lokal dəyişənlər və onların qayıdış ünvanları n dəfələrlə yadda saxlanacaqdır. Böyük n-lər üçün proqramın işi zamanı ən pis hal yaddaş çatışmazlığına (stekin dolub- daşmasına) gətirib çıxara bilər.

6.7. Nizamlama alqoritmlərinin müqayisəsi

Əvvəlcə alqoritmləri onların mürəkkəblik dərəcəsinə görə müqayisə edək. Belə müqayisə cədvəl 6.1-də göstərilmişdir.

Xətti nizamlama alqoritm i elementləri tamamilə təsadüfi yerləşmiş və ya düzgün istiqamətlənmiş massivlərdə çox yaxşı nəticə verir. Lakin əksinə nizamlanmış massivlər üçüm bu üsulun məhsuldarlığı azdır. Bu üsul çox sürətli deyil, lakin çox sadədir. Onun alqoritmini tərtib etmək və sazlamaq çəlin deyil, eyni zamanda çox da böyük olmayan massivləri çox sürətlə nizamlayır.

260 Maharramov Z. T., Vəliyev H.P.

Cədvəl 6.1. Alqoritmlərin mürəkkəblik dərəcələri

AlqoritmVerilənlərin strukturu

Alqoritmin mürəkkəbliyi

Orta hal Ən pis hal

Xətti (seçməklə) massiv O(n2) O(n2)Yerləşdirməklə massiv O(n2) O(n2)Qabarcıq massiv O(n2) O(n2)Şell massiv O(n2) O(n3/2)Sürətli massiv O(n/ofl(n)) O(n2)

Yerləşdirməklə nizamlama alqoritmi hər yeni element üçün düzgün mövqenin axtarılmasına çox vaxt sərf edir. Lakin interpolyasiyalı axtarış üsulundan istifadə etdikdə yerləşdirməklə nizamlama alqoritmi nizamlama sürətini artırır.

Qabarcıq alqoritmi, demək olar ki. nisbətən nizamlanmış vəziyyətdə olan massivlər üçündür. Əgər ilkin massiv artıq nizamlıdırsa, alqoritm sürətlə işləyir, elementlərin bir hissəsi öz yerlərində olmadıqda alqoritm ləng işləyir. Ona görə də bu alqoritmi o halda tətbiq etmək sərfəli olur ki, elementlər əsasən nizamlanmış olsun. Böyük olmayan massivlər üçün effektlidir. Onu tədris məqsədi ilə tətbiq edirlər, digər tərəfdən o bir sıra nizamlama alqoritmlərinin əsasını təşkil edir.

Baxmayaraq ki, əksər hallarda Şell nizamlaması sürətli nizamlamaya nisbətən ləng işləyir, o bir sıra üstünlüklərə malikdir;

• stek üçün yaddaş tələb olunmur;• uğursuz verilənlər yığınları üçün pisləşmənin

(deqradasiyanın) yoxluğu — sürətli çeşidləmə O(n2) -a qədər asanlıqla pisləşir (deqradasiya olur) ki, bu da Şell nizamlaması üçün pis zəmanətli nizamlama vaxtından daha pisdir.

Altıncı fəsil. Nizamlama alqoritmləri 261

Əksər proqramçılar əsasən sürətli nizamlama alqoritminə üstünlük verirlər, çünki, o, həqiqətən digər alqoritmlərdən daha məhsuldardır. Lakin bu alqoritm massivdə çoxlu miqdarda eyni elementlər olduqda pis işləyir. Alqoritmin üstünlükləri:

• ümumi təyinatlı nizamlama alqoritmləri'* üçün ən sürətli alqoritmdir (praktikada);

• reallaşdırılması asandır;• yalnız özünün işləməsi üçün əlavə yaddaş tələb edir;• keşləşdirmə və virtual yaddaş mexanizmləri ilə yaxşı

uzlaşır;• təbii paralelləşdirməyə yol verir (ayrılmış alt

massivlərin paralel icra olunan alt proseslərdə nizamlanması);• başlanğıcdan sona və sondan başlanğıca keçidlərə yol

əlaqəli massivlərdə və verilənlərin digər strukturlarında yaxşı işləyir.

ALQORİTMLƏRİ

Riyazi hesablamalar müxtəlif xarakterli proqramların əsasını təşkil edir. Kompüter qrafikası çoxhədlilər və matrislərlə böyük həcmli hesablamalar tələb edir. Belə hesablamalar, adətən, ekranın hər bir nöqtəsi üçün aparılır. Tipik təsvirin ölçüsü məlumdur ki, 1024x1024 nöqtə təşkil edir. Hər nöqtə üçün bir vurma əməlinə qənaət edilərsə, onda bütün təsvir üçün 10242 =104876 sayda vurma əməlinə qənaət olunur. Hətta, adi triqonometrik funksiyalar da çoxhədlilər vasitəsi ilə hesablanır. Matrislərin vurulması ilə ən müxtəlif əlavələrin yaradılmasında rastlaşırıq. Obrazların tanınmasında matrislər bağlaması təsvirin keyfiyyətini yüksəltmək və böyük şəkildə obyektin sərhədlərini müəyyən etmək üçün istifadə olunur. Obyektlər 4x4 ölçülü matrislərlə çevrilir. Matrislər bağlamasında isə 3x3 ölçüdən 11x11 və daha böyük ölçülü matrislərdən istifadə olunur və bu əməliyyatlar dəfələrlə təkrarlanır. Məsələn, matris şəkil bloklarının mümkün vəziyyətlərində bloklara vurulur. Bu o deməkdir ki, 5x5 ölçülü şablonu 512x512 nöqtəli həcmdə şəklə tətbiq etdikdə (yəni, ekranın dörddə birinə) matris 508x508=258064 sayda bloka vurulur. Matrisin standart vurulma alqoritmindən istifadə etdikdə bu əməliyyat

Yeddinci fəsil. Ədədi üsul alqoritmləri 263

3225800 vurma tələb edir. Deməli, daha səmərəli alqoritm tətbiq etdikdə daha çox vaxta qənaət etmək olar.

7.1. Çoxhədlilərin qiymətinin hesablanması

7.1.1. Hörner sxemi

Fərz edək ki. an,an^,... ,a2,alla0 əmsalları məlum olduqda

P(x) = anxn + Un-iX71-1 + ••• + a2x2 - arx + a0

çoxhədlisinin x nöqtəsindəki qiymətini hesablamaq lazımdır.Bunun üçün standart alqoritm aşağıdakı kimidir və xətti

xarakter daşıyır:

static void Polinomf)

x-çoxhədlinin qiymətinin hesablandiğı nöqtə, r-çoxhədlinin x nöqtəsindəki qiyməti

r:=a[ü]+a[1]*x;xl:=x;f o r ( i = '; ı < r ; i *(xl:=xl*x;r : =r*a [i] *xl ;

ıreturn r

Alqoritm tamamilə aydındır. Belə ki, dövrün daxilindəki iki vurma əməli n-1 dəfə yerinə yetirilir. Bur vurma əməli isə dövrdən əvvəl yerinə yetirilir. Beləliklə,

264 Məhərrəmov Z.T., Vəliyev H.P.

vurma əməllərinin ümumi sayı 2(n — l)4-l = 2n — 24- 1 = 2n — lolur. Analoji olaraq, dövr daxilində bir, dövrdən əvvəl də bir toplama əməli yerinə yetirildiyindən, toplama əməllərinin ümumi sayı n olar.

Hörner sxemi P(x) çoxhədlisinin aşağıdakı ekvivalent yazılışına əsaslanır.

P(x) = ((■•■ ((<W + an-i)x + + ■•• + a2)x + a^x+ a0

Belə yazılışa uyğun alqoritm aşağıdakı kimidir:

static void Hörner()

/*x-çoxhədlinin qiymətinin hesablandiğı nöqtə, r-çoxnədlinin x nöqtəsindəkı qiyməti

*/

r : = 1;for (i=n-l; i>=0; i--){r:= r*x;r:=r + a[i j;

1return r

Bu halda dövr n dəfə yerinə yetirilir və dövr daxilində bir vurma, bir toplama əməli var. Ona görə də Hörner sxemi ilə çoxhədlinin x nöqtəsində qiymətinin hesablanmasında n sayda vurma və n sayda toplama əməli yerinə yetirilir ki, bu da standart alqoritmlə müqayisədə 2 dəfə azdır.

Misal.P(x) = x7 4- 2x6 4- 6x5 4- 3x4 + 7x3 4- 0 • x2 4- 5x 4- 4

Yeddinci fəsil. Ədədi üsul alqoritnıləri 265

çoxhədlisinin x = 2 nöqtəsində qiymətinin hesablanmasını hər iki alqoritmin köməyi ilə yerinə yetirək.

Standart alqoritmin C# dilində proqramı belədir:

using System;

namespace STANDART {class Program

static void Main(string[] args) { int i, n;double r, rl, x, xl;double[] a= new double[8]

{4.0,5.0,0.0,7.0,3.0,6.0,2.0,1.0};x= 2; n= 7;

Console.WriteLine();Console.WriteLine();r= a[OJ + a[l] * x; xl= x;// xl: x -in qüvvətlərifor (i = 2; i <= n; i++) (

r 1 = r;x1 = x1 * x; r=r+a[i] * x 1;Console.WriteLine(" xl = {0,3} a[{l}] = {2,2} r = xl*a[{l}] ={0,4}*{2,2} + {4,4} = {4,4}",xl,i,

a [ i ] , r 1, r) ;}Console.WriteLine();Console.WriteLine(" x= {0} noqtesinde

coxhedlinin qiymeti= {l}",x, r) ;

Console.ReadLine(); } } }

266 Məhərrəmov Z. T., Vəliyev H.P.

Proqramın nəticəsi şəkil 7.1-də göstərilmişdir.

İj FAZAKIR\VSA\STANDART\STANDART\bin\Debug\STANDART.exe . - [ o | B |^^.| 4 । ‘ 4 * ___ *_____

xl = 4 a(2] =0 ı> ■ xl*a[2J = 4« 0 ♦ 14 = 14 xl = 8 a(33 -7 r - xl*a(3] = 8» 7 ♦ 70 = 70 xl » 16 a(4) =3 r ■ xl*a(4] = 16» 3 ♦ 118 = 118 xl = 32 a(5] =6 r > xl*al5J = 32» 6 * 310 - 310 xl - 64 a(6J ■ 2 r - xl«a[6] - 64» 2 * 438= 438 xl = 128 a(7J »1 r - xl«a[7J - 128» 1 * 566 = 566

x= 2 noqtesinde coxhedlinin qijıneti= 566

Şəkil 7.1. Çoxhədlinin standart alqoritmləreallaşdırılmasının nəticələri

Proqramın yazılışındakı a — (a0,Oı, ... ,an) massivinin elementləri P(x) çoxhədlisinin əmsallarıdır.

Hörner sxeminə uyğun alqoritm isə belədir:

using System;namespace HÖRNER {class Program {static void Main(string[] args){const int n = 8, x= 2;int i ;double r, rl;double[] a= new double[n]

{ 4, 5, 0, 7, 3, 6, 2, 1 } ;r= 1;Console.WriteLine() ;Console.WriteLine();Console.WriteLinef"

r = { 0, 4 } " , r) ;for (i= n - 2; i >= 0; i--' {

Yeddinci fəsil. Ədədi üsul alqoritndəri 267

r = r * x; r 1 = r; r = r + a [ i ] ;Console.WriteLine(" r= r*{0,2} + a[{1}]={2,3}*{0}+ {3,2} = {4,4}", x, i,

rl/x, a[i], r);}Console.WriteLine();Console.WriteLine(" x = {0} noqtesinde

coxhedlinin qiymeti={1}", x, r);

Console.ReadLine(); } } }

Proqramın nəticəsi şəkil 7.2-də göstərilmişdir.

TJ F:\7AKlRWSA\HORNER\MORNFR\hin\Dehug..

Şəkil 7.2. Çoxhədlinin Hörner sxemi ilə reallaşdırılmasının nəticələri

Proqramın icrası nəticəsində alınmış nəticələrin izahını verək. Əgər

P(x) = anxn + Qn-jX71-1 + —I- a2x2 + atx + a0

268 Məhərrəmov Z. T., Vəliyev H.P.

çoxhədlisi verilmişdirsə, bu çoxhədlinin x-a ikihədlisinə bölünməsindən alınan qismət və qalığı tapmaq üçün Hörner sxemini cədvəl şəklində doldurmaq lazımdır (cədvəl 7.1).

Cədvəl 7.1. Hörner sxemi

a

Çoxhədlinin əmsallarıan an-l an-2 «o

a a3"

3 II ^71-1 “

^n—1 + ’ $

bn-z — an-2 + bn_! ■ a

bo = a0 + br -a

İkinci sətirdəki bn, bn-ı, bn_2> — >bı ədədləri P(x) çoxhədlisinin x-a iki bədiisinə bölünməsindən alman n-1 dərəcəli qismət çoxhədlisinin əmsallarıdır, b0 isə qalıqdır. Başqa sözlə,

P(x) = anxn + a^x'1-1 + + a2x2 4- a^x 4- a0 == (x — a)(h„x’1-1 4- bn_ıXn-2 4------1- bt) 4- b0.

Bu sxemiP(x) = x7 4- 2x6 + 6x5 + 3x4 + 7x3 + 0 ■ x2 + 5x + 4

çoxhədlisi üçün yazaq (a=2, cədvəl 7.2).

Cədvəl 7.2. Hörner sxemi

a=2Çoxhədlinin əmsalları

1 2 6 3 7 0 5 41 4 14 31 69 138 281 566

Birinci sətirdə verilmiş çoxhədlinin əmsalları, ikinci sətirdə işə qismət çoxhədlisinin əmsalları və qalıq yazılmışdır:

x7 + 2x6 + 6x5 + 3x4 + 7x3 4- 0 ■ x2 4- 5x + 4 == (x - 2)(x6 + 4x5 4- 14x4 4- 31x3 + 69x2 +

+ 281) + 566.

Yeddinci fəsil. Ədədi üsul alqoritntfəri 269

Proqramın nəticələrini sonuncu münasibətlə müqayisə etsək, b6 — 1, b5 = 4, b4 = 14, b3 - 31, b2 — 69. br = 281, b0 = 566 olduğunu görərik. b0 = 566 qalıqdır (və ya P(2) = 566).

Qeyd edək ki, Hörner sxeminin tətbiqi nəticəsində P(a) - 0 olarsa, onda a P(x)-in kökü olur.

Əgər oq (i — 0,n) əmsalları tam ədədlərdirsə və P(x~) çoxhədlisinin tam kökləri varsa, onda bu köklər a0 sərbəst həddinin tam bölənləri içərisindədir. Bu xassədən istifadə etməklə Hörner sxeminin köməyi ilə verilmiş çoxhədlini vuruqlara ayırmaq olar. Bu əməliyyatı aşağıdakı proqramla reallaşdırmaq olar:

using System;namespace HORNER_VURUQ { class Program { static int n = 6;static double[] a = new double[7] { 0.3, 0.7, 2.2, 1.7, 2.5, 1.6, 4.3 static double Result;

// Çoxhədlinin vuruqlara ayrılması static void Pn(double x){int i;Result=a [0];for (i=l; i<n; i++)Result=Result*x +a [i];Result=Result + a[n];}

static void Main(string[] args) { double x;Console.WriteLine("\n") ;

270 Məhərrəmov Z. T., Vəliyev H.P.

x= 0.5; Pn (x);Console.WriteLine(" x= {0} Pn({0}) =

{l,10:F5}", x, Result);

x= 1.5; Pn(x);Console.WriteLine(" x= {0} Pn({0}) =

(1,10:F5}x, Result);

x = 3.2; Pn(x) ;Console.WriteLine(" x= {0} Pn({0}) =

{l,10:F5}", x, Result);

x= 4.1; Pn(x) ;Console.WriteLine(" x= (0} Pn({0}) =

{1,10:F5}", x, Result);

x = 6.8; Pn(x);Console.WriteLine(" x= {0} Pn({0}) =

{l,10:F5}", x, Result);

Console.ReadLine(); } ) }

Proqramın nəticəsi şəkil 7.3-də göstərilmişdir.

■J F:\ZAKIR\VSA\HORNER_VUR...

x= 0,5 Pn<0,5> = 7,90313 x= 1,5 Pn<l,5> = 26,72188 x= 3,2 Pn<3,2> = 277,46122 x= 4,1 Pn<4,l> = 741,72507 x= 6,8 Pn<6,8> = 6651,75542

H I rrr I_______________ k

Şəkil 7.3. Hörner sxeminin köməyi ilə çoxhədlinin vuruqlara ayrılması

Yeddinci fəsil. Ədədi üsul alqoritmləri 271

7.2. Matrislərin vurulması

Əgər birinci matrisin sütunlarının sayı ikinci matrisin sətirlərinin sayına bərabərdirsə, onda belə matrisləri vurmaq olar. 3x4 ölçülü matrisi 4x7 ölçülü matrisi vurduqda 3x7 ölçülü matris alınacaqdır. A və B matrisləri üçün, ümumiyyətlə, AB^B-A.

mxn ölçülü A matrisinin nxc ölçülü B matrisinə hasilinin psevdokodla alqoritmini belə tərtib etmək olar:

for(i=l; i<=m; i++! for(j=l; j<=c; j++) H[i,j]=0

for(k=l; k<=n; k++)H[i,j]= H[İ,j]=+A[I,k]*B[k,j]

end for k end for j

end for i

Bu psevdokoda uyğun C# kodunu belə yaza bilərik:

using System;namespace ml4 { class Program {static void Main(string[] args) {double [,] a = new double[3, 4];double[,] b - new double[4, 3];double[,] c = new double[3, 3]; int ı,j,k ; double s;Console .Write ( "*■** A ve B matrislerinin

hasili***\n\n");Console.Write("a matrisinin

elementlerini daxil edin: \r.\n") ;

for (i = 0; i < 3; i++)

272 Məhərrəmov Z. T,, Vəliyev H.P.

Console.Write(i + "-ci setir elementlərinidaxil edin:\n");

for (j = 0; j < 4; j++) a[i, j] = Convert.ToDouble(

Console.ReadLine());}Console.Write("\n\nb matrisinin

elementlerini daxil edin:\n\n"); for (i = 0; i < 4; i++) {Console.Write(i + "-ci setir

elementlerini daxil edin:\n"); for (j = 0; j < 3; j++)

b[i, j] = Convert.ToDouble( Console.ReadLine());

} for (k = 0; k < 3; k++) {

for (i =0; i < 3; i++) {

s = 0 ;for (j = 0; j < 4; j++)

s= s + a[i, j] * b[j, k] ; c [ i, k ] = s ;

}}Console.Write("\n\n\n*** C=A*B matrisi

****:\n\n");for (i = 0; i < 3; i++) {for (j =0; j < 3; j++)Console.Write (c [i, j]+"\t");

Console.WriteLine();)

Console.Read(); } } )

Yeddinci fəsil. Ədədi üsul alqoritmləri 273

'1 2 3 4 ' '12 34 5 6

A= 5 6 7 8 və B=7 8 9

9 10 11 12\ / 10 11 12matrisləri üçün proqramın icrasının nəticəsi şəkil 7.4-də göstərilmişdir.

I ’• C:\lkprs\l Inp\CCC\mT4\m14\.,_

1*** fi ue B matris lerinin hasili***

Ka matrisinin elementlerini daxil edin:

B-ci setir 1 !3

elementlerini daxil edin:

L-ci setir

1

elementlerini daxil edin:

!-ci setir elementlerini daxil edin:

101112

|b matrisinin elementlerini daxil edin

0-ci setir

11

elementlerini daxil edin:

t-ci setir elementlerini daxil edin:4

!-ci setir elementlerini daxil edin:

3-ci setir elementlerini daxil edin:

l

Şəkil 7.4. Matrislərin vurulması

274 Məhərrəmov Z. T., Vəliyev H.P.

7.3. Cəbri və transendent tənliklərin həll üsulları

Yalnız cəbri funksiyalardan ibarət tənliklərə - cəbri, cəbri və transendent funksiyalardan ibarət tənliklərə isə transendent tənliklər deyilir. Hər iki tənliyi ümumi halda

/(x) = 0 (7.1)kimi yazmaq olar.

(7.1) tənliyinin təqribi həlli iki mərhələdən ibarətdir:1. Köklərin ayrılması, yəni elə dar intervalını

tapmaq tələb olunur ki. bu intervalda tənliyin yalnız və yalnız bir kökü olsun.

2. Köklərin dəqiqləşdirilməsi, yəni verilmiş dəqiqliklə kökün tapılması.

7.3.1. Yarıya bölmə üsulu

Bu üsula bəzən dixotomiya üsulu da deyirlər. Tutaq ki, f(x)=0 tənliyi verilmişdir və f(x) funksiyası [a,b] parçasındakəsilməzdir və f(a)-f(b)<0. Tənliyin kökünü tapmaq üçün

[u,Z?] parçasım yarıya bölərəka + b

a,------2

vəa + b---- .o

2

parçalarını alırıq. q- ——— qəbul edək. Əgər /(<^) = 0

olarsa, bu nöqtə axtarılan kökdür /(£)*0 olduqda isə kökün hansı parçada olduğunu təyin edirik. Bunun üçün

./ d a + b\ d a + b'] ,./(«)■./!və 7^— hasillərinin işarəsini

yoxlayırıq. Hansı parça üçün bu hasil mənfıdirsə, həmin parçanı yenidən yarıya bölürük və s.

Bu üsulu tam başa düşmək konkret misala baxaq.

Misal, x2 -3 = 0 tənliyini həll edək.

Yeddinci fəsil. Ədədi üsul alqoritndəri 275

Deməli, f(x) = x2 - 3.Bu tənliyin həlli [1, 2] parçasındadır, çünki /(1) =

—2, /(2) = 1, /(1) ■ f (2) < 0. Ona görə də [1, 2] parçasını yarıya bölək:

(1; 1,5) və (1,5; 2), f(l ,5)=-Q,75;/(l)-f (1,5) >0; /(1,5) 7(2) < 0.

Deməli tənliyin kökü (1,5; 2) intervahndadır. Bu intervalı yenidən yarıya bölək:

(7,5; 1,75) və (1,75; 2) / (1,75) = 0,0625;

f (1,5) • / (1,75) = -0.75 ■ 0,0625 < 0/ (1,75) 7 (2) = 0,0625 • 1 > 0

İndi (1,5; 1,75) intervalım yarıya bölürük və s.Yarıya bölmə üsulunun C# dilində proqramını belə

tərtib edə bilərik:using System;namespace Trans_Dixotomiya{class Program{static double f;static void Func (double x) (f=5*Math.Sin(2*x) - Math.Sqrt(1-x);

}static void Main(string[] args) { double a, b, e, c, x;a= -6;b= 1;Console.WriteLine("\n Yariya

bolme usulu:\n");Console.WriteLine("Deqiqliyı daxıl

edin:");Console.Write("e=");e=Convert.ToDouble(Console.ReadLine()); c= (a+b)/2;

276 Məhərrəmov Z. T., Vəliyev H.P.

while (Math.Abs(b - a) > e) (Func(a); double fl = f;

Func(c); double cl = f;if (fl * cl < 0) b = c; else

a = c;c = (a + b) / 2 ;

}x= (a + b) / 2;Console.WriteLine("\nTenliyin

koku:\nx={0,8:f4}", x);Func(x);Console.WriteLine("\nf (x) funksiyasinin

x noqtesinde qiymeti:");Console.WriteLine("f({0,7:f4})={1,8:E4}"

, x, f) ;Console.ReadLine(); } } }

Proqramda 5 -sin2x — y/1 — x — 0 tənliyi həll edilmişdir. Proqram icra olunduqda həllin hansı dəqiqliklə hesablanması (e dəyişəni) daxil edilməlidir. e=0.00001 halı üçün tənliyin həlli şəkil 7.5-də göstərilmişdir.

■_j F:\ZA KIR\VSA\Tran^_Dıxotn miya\Tran '_Oj.. I J I 1****^^^!

Variya bolne usulu:

leqiqliyi daxil edin: =0,00001

'enliyin koku::= -1,7395

<x> funksiyasinin x noqtesinde qiymeti:<-l,7395 > =-8,4344E-0D6

* L " ~ trt I______________ >■ ■Şəkil 7.5. Yarıya bölmə üsulu ilə tənliyin həllinin

nəticəsi

Yeddinci fəsil. Ədədi üsul alqoritmləri 277

Yarıya bölmə üsulu yüksək effektivliyə malik deyil, amma iterasiyaların sayı artdıqda köklərin kifayət qədər dəqiq tapılmasını təmin edir. N sayda iterasiyadan sonra intervalın uzunluğu 2N dəfə azalır.

7.3.2. İterasiya üsulu

Tənliklərin ən əhəmiyyətli ədədi həll üsullarından biri iterasiya üsuludur. Bu üsulun mahiyyəti belədir. Tutaq ki, (7.1) tənliyi verilmişdir və onu həll etmək tələb olunur. (7.1) tənliyini onunla eyni güclü olan

x = <x) (7.2)tənliyi şəklinə gətirək. Hər hansı bir üsul ilə tənliyin kobud x0 kökünü tapaq və onu (7.2) tənliyinin sağ tərəfinə qoyaq:

x = p(x0) (7.3)(7.3) bərabərliyinin sağ tərəfinə x0 əvəzinə xx qoyaraq

x2 = (p(xf) alırıq. Bu prosesi təkrarlayaraqxn = ç’CXn^), n = 1,2,... (7.4)

ədədlər ardıcıllığını alacağıq.İterasiya prosesi

|xn 11 — şərti ödənənə kimi davam etdirilir.

İsbat edilmişdir ki, xe[a,h] üçün |ç>(x)'|< 1 şərti ödəndikdə iterasiya prosesi yığılır.

(p(x) funksiyasını aşağıdakı üsulla tapmaq tövsiyə edilir. Tutaq ki, /'(x) > 0 t/xe[a, b]. Əgər bu belə deyilsə, onda (7.1) tənliyini

-/(x) = 0şəklində yazırıq. Bu tənliyin hər iki tərəfini - X (X>0) ədədinə vuraq və hər iki tərəfə x əlavə edək:

x = x — A/(x) = ç»(x).Z sabiti aşağıdakı şərtdən tapılır:

278 Məhərrəmov Z.T., Vəliyev H.P.

1 max |/'(x)|'

xe [a,ö]‘

X sabitinin bu qiymətiXi = ^i-ı ~ A/(x) = ç?(x)

düsturu ilə iterasiya prosesinin yığılmasına zəmanət verir.

Misal. İterasiya üsulu ilə x3 = 1 — 2% tənliyini [ö,/] parçasında 8-0,01 dəqiqliyi ilə həll etməli.

Bu tənlikdən x məchulunu aşkar şəkildə tapaq:1

x = -(1 -x3) = <p(x).

Yığılma şərtini yoxlayaq:

3 3q>(x)' = --x2, ^(0) = 0, ç?'(l) = --.

Göründüyü kimi |^(x)'|< 1 şərti ödənmir və ona görə də alınmış düstur ilə iterasiya prosesi yığılmayacaq və tənliyin köklərini dəqiqləşdirmək mümkün olmayacaq.

Yuxarıdakı üsulla iterasiya prosesi üçün düstur tapaq: /(x) = x3 + 2x - 1 = 0, /'(x) = 3x2 + 2, /'(x) > 0.

/'(x)-in ən böyük qiyməti x=l nöqtəsindədir, yəni:

, max |/'(x)| =/'(1) = 3 42 + 2 = 5.

Deməli, A = | = 0,2. Onda iterasiya prosesi üçün

aşağıdakı düsturu alacağıq:

x, = Xi_! — O^Cxf.! + 2xi_i — 1), i = 1,2,...

Başlanğıc yaxınlaşma kimi x0 = 0,5 (parçanın orta qiyməti) qəbul edək. Onda:

Yeddinci fəsil. Ədədi üsul alqoritndəri 279

= x0 - 0,2(xq + 2x0 - 1)= 0,5 - 0,2(0,53 + 2-0,5 - 1) = 0,475.

İterasiya prosesinin başa çatması şərtini yoxlayaq:

|X1 - x0| = |0,475 - 0,51 = 0,025 > s.

Şərt ödənmədiyinə görə hesablamanı davam etdiririk:

x2 = *ı - 0,2(x3 + 2%! - 1) == 0,475 - 0,2(0,4753 + 2 -0,475 - 1) == 0,463566,

|x2 - Xıl = 10,463566 - 0,4751 = 0,011434 > e.

Beləliklə, iterasiya prosesinin başa çatma şərti ödənənə kimi bu qayda ilə hesablamalar davam etdirilir.

İterasiya üsulunun C# dilində proqramını tərtib edək.

using System;namespace Trans_Iterasiya{class ProgramI

static double f;static void Func(double x) // funksiya(

f= x-0.2+(x*x*x + 2*x-l);

static voıd Mam (string [ ] args) {const int max_ıter= 100; // iteras

// maksimal sayı

double x,x0,eps;Console.Write(" iterasiya

280 Məhərrəmov Z. T., Vəliyev H.P.

usulu:\n"); Console.Write("\nBashlangic qiymeti

daxil edin x=");x= Convert.ToDouble(Console.ReadLine()); Console.Write("Deqiqliyi daxil edin

eps=");eps=Convert.ToDouble(

Console.ReadLine ());Console.WriteLine("\n");string s = new stringf’-', 40); int i= 0;

do {

x 0 = x ; Func(xO); x = f ; i++;Func(x);Console.WriteLine (s) ;Console.WriteLine("iterasiya {0,3):

x={1,10:f6) ", i, x);Console.Write("\ndeqiqlik={0,10:f6},"

, Math.Abs(x - xO));Console.Write ( " F(x)={0,10:f6)",

(x*x*x+2*x-l));Console.WriteLine("\n");

)while ( (Math.Abs(x-xO)>=eps)&& (i<

max_iter));Console.WriteLine();if (Math.Abs(x-xO)<=eps||(i<max_iter)) Console . WriteLine ("Tenliym koku:

x={0,10:f6}", x);elseConsole.WriteLine("CAVAB TAPILMADI!!!

{0,3) sayda iterasiyaya prosesi yigilmadi",max_iter) ;

Yeddinci fəsil. Ədədi üsul alqoritmləri 281

Console . Read () ■;} })

Proqramın nəticəsi şəkil 7.6-da göstərilmişdir.

!_’■ F:\ZAKIRWSA\Trans-]terasiya\Tran<:-Iteras...L_^_L®_J^^^^^I

Şəkil 7.6. İterasiya üsulu ilə tənliyin həllinin nəticələri

7.3.3. Nyuton üsulu

Tutaq ki, /(%) =0 tənliyi verilmişdir, onun [a. ö] parçasında kökləri ayrılmışdır və funksiyanın /'(x) birinci və f"(x) ikinci tərtib törəmələri verilmiş parçada işarələrini

sabit saxlamaqla kəsilməzdir.Nyuton üsulunun həndəsi mənası y=f(x) əyrisinin bu

əyriyə çəkilən toxunanla əvəz edilməsindən ibarətdir. Ona görə də bu üsula toxunanlar üsulu da deyirlər.

282 Məhərrəmov Z. T., Vəliyev H.P.

Məlumdur ki. Bo nöqtəsindən keçən toxunanın tənliyi belə olur:

y-w) = m-(x-&)

y=0 qəbul edib, x = xT üçün alırıq:

Xj — b — r'wBu halda tənliyin kökü [a,%ı] parçasında

axtarılmalıdır. Nyuton üsulunu bu parçaya tətbiq etmək üçün Sj [Xj; /(%])] nöqtəsindən əyriyə toxunan çəkirik. Onda

alınır və bu prosesi davam etdirsək, Nyuton üsulunun ümumi düsturunu alarıq:

_ /C*n) _ n 1 ən-0,1,2,...

Burada n - iterasiyaların sıra nömrəsidir.Hesablama prosesi |xn+1 — xn\ < e olana qədər davam

etdirilir. Burada, fverilmiş dəqiqlikdir.f(x )Əgər t = , n' qəbul etsək, onda t = x„+1 — xn f hn)

alarıq. Ona görə də hesablama prosesinin dayandırılması üçün |t| < e şərtini yoxlamaq kifayətdir.

Üsulu tətbiq etdikdə x0 başlanğıc yaxınlaşmasına qiymət vermək lazımdır.

Misal., x2 — 3 = 0 tənliyini həll edək.

Yuxarıda qeyd etdik ki. bu tənliyin həlli [1,2] parçasındadır. Başlanğıc yaxınlaşma kimi x0 = 1 qəbul edək.

Yeddinci fəsil. Ədədi üsul alqoritmləri 283

Məlumdur ki, /(x) = xz — 3, /'(x) = 2x. £ = 10-3 qəbul edək.

Onda:l.x0 = 1;2- Xı = x0 - = 1 - = 2; |t| = 1 > 10-3;ə /(*ı) n 22—3 7 । । 1 .. -3. x2 = Xı —7-— = 2-------- = -; t = - = 0,25 >z 1 22 4 1 1 4

10~3;

4. x3 = r 72 f'(x2) 4

Və S.x3 — 1 — 2x tənliyinin timsalında Nyuton üsulunun C#

dilində proqramını tərtib edək:

using System;namespace Trans_Nyuton {class Program

static double F,FT;

static voıd Func(double x) {F=x*x*x+2*x-l; // Funksiya

)

static void FuncT(double x) (FT=3*x*x+2; // Funksiyanın törəməsi

}

static voıd Main(string[] args) (

double xO,xl,b,e,t;

284 Mahərrətnov Z.T., Vəliyev H.P.

int i;const int max_ıter = 100; // iteras.

// maksimal sayıConsole.Write(" Nyuton

usulu:\n"); Console.Write("\nBashlangic qiymetı

daxil edin x=");

xO - Convert.ToDouble(Console.ReadLine() ) ;

Console.Write("Deqiqliyi daxil edin eps=");

e = Convert.ToDouble( Console.ReadLine());

Console.WriteLine("\n");string s = new stringf'-', 38);

xl = xO;i= 0;

do(b= x 1;i + +;Func(b); double F1 = F;FuncT(b); double FT1 = FT;t = F1 / FT1;xl= b - t;Func(xl);Console.WriteLine (s);Console.WriteLine("iterasiya {0,3}:

x={1,10:f6}", i, xl);Console.Write("\ndeqiqlik={0,10:f6),",

Math.Abs(t));Console.Write(" F(x)={0,10:f6}", F);Console.WriteLine("\n");

Yeddinci fəsil. Ədədi üsul alqoritnıləri 285

while ((Math.Abs(t)>=e)&&(i<max_iter) ) ; Console.WriteLine() ;

if ((Math.Abs(t)<=e)||(i<max_iter))Console.WriteLine("Tenliyin koku:

x={0,10:f 6}", xl) ;else Console.WriteLine("CAVABTAPILMADI!!! {0,3} sayda iterasiyaya

proses yigilmadi", max_iter);

Console.Read();}} }

Proqramın nəticəsi şəkil 7.7-də göstərilmişdir.

Şəkil 7.7. Nyuton üsulu ilə tənliyin həllinin nəticələri

Nyuton üsulu ilə iterasiya üsulunu müqayisə etdikdə görürük ki, eyni bir tənlik üçün eyni başlanğıc şərtləri

286 Məhərrəmov Z.T., Vəliyev H.P.

daxilində Nyuton iterasiya prosesi daha sürətlə yığılır və həll daha dəqiq alınır. Dəqiqlik artırıldıqda bu fərq daha kəskin olur.

7.4. Xətti cəbri tənliklər sisteminin həll üsulları

Xətti cəbri tənliklər sisteminin həll üsulları iki əsas qrupa bölünür:

1. Dəqiq üsullar. Buraya aşağıdakı üsullar aiddir:• Kramer üsulu;• Qauss üsulu;• Baş elementlər üsulu;• Kvadrat köklər (Xoleski) üsulu və s.

2. İterasiya üsulları. Buraya aşağıdakı üsullar aiddir:• İterasiya üsulu;• Zeydel üsulu;• Relaksasiya üsulu və s.

Birinci qrup üsulların dəqiq üsullar adlandırılması şərtidir, belə ki, bu üsulları kompüterdə realizə etdikdə hökmən yuvarlaqlaşdırma aparıldığından nəticə də təqribi olacaqdır, lakin üsulların özləri tamamilə dəqiq üsulllardır. Deməli, birinci qrup üsullarda xəta mənbəyi ədədlərin yuvarlaqlaşdırılmasındadır. İkinci qrup üsullarda isə xəta mənbəyi həm yuvarlaqlaşdırma, həm də üsulun özünün dəqiq olmamasıdır.

Kompüterdə Kramer üsulunu çox az hallarda istifadə edirlər, çünki məchulların sayı artdıqca determinantın ölçüsü böyüyür, bunun da nəticəsində yaddaş həcmi və hesablama vaxtı artır. Kompüterdə əsasən Qauss üsulu və iterasiya üsulları tətbiq edilir.

'I ənliklərin sayı məchulların sayına bərabər olan halda xətti cəbri tənliklər sistemi (XCTS) aşağıdakı kimi yazılır:

Yeddinci fəsil. Ədədi üsul alqoritmləri 287

«11*1 + «12*2 +- + al„x„ = a2ixl+a22x2+... + a2nxn=b2

an{x} + a„2x2 + ... + a„„x„ =bn

(7.5) tənliyini qısa formada belə də yaza bilərik:

X aı/x/ = b, ,i = 1,2,...,« (7.6)/-I

(7.5) XCTS -ni matris şəklində isə belə yaza bilərik:

AX=B. (7.7)

Burada:

«11

XCTS-ni ixtiyari üsulla həl! etdikdə bu tənliklər üçün Kramer teoremi doğru olmalıdır. Bu teoremi isbatsız olaraq xatırlayaq: əgər A matrisinin determinantı sıfırdan fərqlidirsə, onda XCTS-nin yeganə həlli vardır.

Ona görə də istənilən üsulu tətbiq etdikdə XCTS-nin baş determinantının sıfırdan fərqli olduğunu yoxlamaq lazımdır.

XCTS-nin həlli üçün ən geniş yayılan Qauss üsulu bəzən çox ciddi səhvlərə gətirə bilər. Bu o halda olur ki, sistem pis şərtlənmiş sistem olsun. Pis şərtlənmiş sistem elə sistemə deyilir ki, sistemin baş determinantının modulu matrisin hər hansı norması ilə müqayisədə kiçik olsun.

288 Məhərrəmov Z. T., Vəliyev H.P.

Matrisin norması isə matrisin sətir və ya sütun əmsallarının modullarının cəminin ən böyüyü ola bilər.

7.4.1. Qauss üsulu

Qauss üsulu XCTS-nin həlli üçün ən universal üsuldur. Kramer üsulundan fərqli olaraq, o nəinki yalnız yeganə həlli olan sistemlər üçün, həm də həllər çoxluğu sonsuz olan sistemlər üçün yararlıdır. Burada üç variant mümkündür.

I. Sistemin yeganə həlli var (sistemin baş determinantı sıfra bərabər deyil);

2. Sistemin sonsuz sayda həlli var;3. Sistemin həlli yoxdur, sistem uyuşmazdır.Qauss üsulu dəqiq üsullara aiddir və tənliklər

sisteminin (genişlənmiş matrisin) üçbucaqlı (və ya diaqonal) şəklinə gətirilməsinə əsaslanmışdır. Belə gətirmə sistemin tənliklərini (genişlənmiş matrisin sətirlərini) müvafiq sabit əmsallara vurduqdan sonra onların toplanması və ya çıxılması yolu ilə əldə edilir.

Üsulun alqoritmi iki mərhələdən ibarətdir. Birinci mərhələdə məchullar tənlikdən ardıcıl olaraq yox edilir (üsulun düzünə gedişi). Bu zaman baş diaqonaldan aşağıdakı elementlər sifra bərabər olur:

Bu. aşağıdakı ekvivalent çevirmələrin köməyi ilə edilə bilər:

1. Matrisin sətirlərinin yerlərini dəyişməklə;

Yeddinci fəsil. Ədədi üsul alqoritmləri 289

2. Əgər matrisdə eyni (və ya mütənasib) sətirlər varsa, birindən başqa, onların hamısını silməklə;

3. Sətri istənilən ədədə vurmaq və ya bölməklə;4. Sıfırlardan ibarət sətirləri silməklə;5. Sıfırdan fərqli ədədə vurulmuş sətri sətrə əlavə

etməklə.Konkret olaraq sistemin birinci tənliyindən

məchulunu tapırıq:

X1 ~ (am+l a12x2 ------ ainxn)/aU-

Bu yalnız o vaxt mümkündür ki, an/0 olsun. Əks təqdirdə sistemin tənliklərinin yerlərini dəyişdirmək lazımdır. Bu düstura əsasən sistemin genişləndirilmiş matrisinin birinci sətrinin hər bir elementini diaqonal elementinə bölmək lazımdır:

a[^ = aL) — a^a^, i = 2,3,...,n; j = 1,2, ...,n + 1.

Birinci məchulunun bütün tənliklərdən yox edilməsi nəticəsində çevrilmiş matrisin birinci sütununun bütün elementləri, = 1 elementindən başqa, stfra bərabər olacaq.

Sistemin ikinci tənliyindən x2 məchulunu tapaq və qalan tənliklərdən onu yox edək və s. Nəticədə yuxarı üçbucaqlı matrisli sistemi alacağıq ki, onun baş diaqonaldan aşağıdakı elementləri sıfra bərabər olacaqdir.

Ümumiyyətlə, xk məchullarının və sistemin genişlən­miş matrisinin elementlərinin hesablanması üçün ifadə belə olacaqdır:

(ak,n+ı akj 'xj}

xk =---------------------------- ------------------- ---------------- akk

290 Məhərrəmov Z. T., Vəliyev H.P.

(m+l) akj „On+l) _ (m) (m) _(m)akj — (m)< aij utj utk 'ukj ■

Xətti tənliklər sisteminin həllinin ikinci mərhələsi üsulun tərsinə gediş adlanır və xn məchulundan başlayaraq x1-ə qədər bütün Xk məchullarının yuxarıda göstərilən düstura görə ardıcıl təyinindən ibarətdir.

Nəticələrin dəqiqliyi matrisin çevrilməsi vaxtı hesabi əməliyyatların aparılmasının dəqiqliyi ilə təyin edilir. Diaqonal elementinə bölmə vaxtı xətanın azaldılması üçün tənliklərin yerlərini elə dəyişdirmək tövsiyə edilir ki, baxılan sütunun bütün elementlərindən modula görə ən böyüyü diaqonala qoyulsun. Belə prosedur baş elementin seçilməsi adlanır.

Misal.xt - 4x2 - 2x3 - -33xt + x2 + x3 =5

.3%! - 5x2 ~ 6xı =

tənliklər sistemi verilmişdir və onu Qauss üsulu ilə həll etmək tələb olunur.

Əvvəlcə genişləndirilmiş matrisi yazaq:

/1 -4 - 2\ /-3\ I 3 1 1 I ( 5 I \3 — 5 — 6/ 9/

İndi çevirmələrlə məşğul olaq. Qeyd etmişdik ki. bizə üçbucaqlı şəklində matris alınaq lazımdır. 1-ci sətri 3-ə vuraq. 2-ci sətri (-l)-ə vuraq. 2-ci sətri l-ciyə əlavə etməklə alırıq:

/0 - 13 - 7\ /—14\3 1 1 ( 5 |

\ 3 - 5 - 6 / \ -9 /

Yeddinci fəsil. Ədədi üsul alqoritmləri 291

Sonra 3-cü sətri (-l)-ə vuraq. 3-cü sətri 2-ciyə əlavə edək:

/0 - 13 - 7\ /—14\(o 6 7 ) •( 14 ).\3 - 5 - 6/ \ —9 /

1-ci sətri 6-ya vuraq. 2-ci sətri 13-ə vuraq. 2-ci sətri I- ciyə əlavə edək:

/0 0 49\ /98\| 0 6 7 ) ( 14 ).\3 — 5 — 6/ \—9/

Sistem lazım olan şəklə gətirildi. İndi məchulları tapmaq qaldı:

x3 = — = 2, 5 49

14 — 7x3 14-7-2x2=——2^—=.°, O o

—9 + 5%2 + 6X3 —9 + 5 -0 + 6 -2x< = - - - = 1.

Bu sistemin yeganə həlli vardır.

XCTS-in həlli üçün Qauss üsulunun C# dilində tərtib edilmiş proqramının mətni belədir:

using System;

namespace QAUSS

class Program{static void Main(string[] args)

292 Məhərrəmov Z. T., Vəliyev H.P.

double[,] a = new double [10, 10];double[,] al = new double[10, 10];double [] b = new double [10];double[] bl = new double[10];double [] x = new double[10];int n, i, j, k;double r, g;

n = 3;a[0,0]=6.25; a[0,l]=-1.0; a[0,2]= 0.5; a[l,0]=-1.0; a[1,1]= 5.0; a[1,2]= 2.12; a[2,0]= 0.5; a[2,l]= 2.12;a[2,2] = 3.6; b[0] = 7.5; b[l] = -8.68; b[2] = -0.24;

Console.WriteLine("\nA matrisi (Esas matris): ");

for (i =0; i < n; i++)(for (j = 0; j < n; j++){Console.Write("{0,5:f2}\t",

a [ i, j ] ) ;al[i, j ] = a [i, j ] ;

}Console.WriteLine();

Console.WriteLine();Console.WriteLine("B matrisi (Tenliyin

sol terefi): ");

for (i = 0; i < n; i++) Console.WriteLine("{0,6:f2)", b[i]);

// DÜZÜNƏ GEDİŞ

Yeddinci fəsil. Ədədi üsul alqoritmləri 293

for (k = 0; k < n; k++) {

for (j = k+ 1; j < n; j++)

r = a [ j , k] / a [ k, k];for (i = k; i < n; i + +){

a [ j , i] = a [ j , i] _ r * a[k, i]; }b [ j ] = b [ j ] - r * b[k] ;

}

// TƏRSİNƏ GEDİŞfor (k = n - 1; k >= 0; k--) {

r = 0 ;for (j = k + 1; j < n; j++){

g = a [k, j ] * x [ j ] ;r = r + g ;

}x[k] = (b [k] - r) / a[k, k] ;

Console.WriteLine("\n------------------ ") ;Console.WriteLine("\nQauss usulu ile

tenliyin helli:");

for (i = 0; i < n; i++){Console.WriteLine(" x{0} ={1,6:f2}",

i+1, x[i]);

Console.WriteLine("\n------------------Console.WriteLine("\nB-ye (sag

294 Məhərrəmov Z.T., Vəliyev H.P.

tereflere) uyğunluğun yoxlanmasi:");Console.WriteLine();

for (i =0; i < n; i++){

for (j = 0; j < n; j++) bl[i] = bl[i) + al[i, j] * x[j];

Console.WriteLine(" {0,5:f2}",bl [i]);

Console.ReadLine () ; } } }

Proqramın nəticəsi şəkil 7.8-də göstərilmişdir.

■ j F:\ZAKIR\VSA\QAUSS\QAUSS\bln\Debug\QA... I I I

R matrisi CEsas6,25

-1,00 0,50

-1,005,00 2,12

matris): 0,50 2,12 3,60

0B natrisi (Tenliyin sol terefi):

7,50 -8,68 -0,24

Qauss usulu ile tenliyin lıelli: xl = 0,80 x2 = -2,00 x3 = 1,00

B-ye <sag tereflere} uyğunluğun yoxlanmasi:

7,50 : -8,68 -0,24

rrr

Şəkil 7.8. Qaııss üsulu ilə sistemin həllinin nəticələri

Yeddinci fəsil. Ədədi üsul alqoritmləri 295

7.4.2. Xoleski üsuhı

Əgər sistemin matrisi simmetrik və baş determinantı müsbətdirsə, onda sistemin həlli üçün Xoleski (Cholesky) və ya kvadrat köklər adlanan üsulu tətbiq edirlər.

Üsulun əsasını A matrisinin xüsusi LU-ayrılışı alqoritmi təşkil edir, bunun nəticəsində o A = LLr şəklinə gətirilir. Nəticədə sistemin həlli üçbucaqlı matrisdən ibarət iki sistemin ardıcıl həllinə gətirilir:

Ly = b və Ltx = y.

L matrisinin əmsallarını tapmaq üçün L matrisinin məchul əmsalları A matrisinin uyğun elementlərinə bərabərləşdirilir. Sonra tələb olunan əmsallar aşağıdakı düsturlar üzrə ardıcıllıqla tapılır:

/, „ = ü/ck ~ iki ~ ^k.k-1'

atk ~ ~ ^2^2 hk-Jk,k-ı

i = k + 1,

/2m,m —1 •

296 Məhərrəmov Z.T., Vəliyev H.P.

Misal. Aşağıda verilmiş XCTS-nin Xoleski üsulu ilə həll edək:

6,25%! — x2 + 0,5x3 = 7,5—%! + 5x2 + 2,12x3 = -8,68

.0,5%! + 2,12x2 + 3,6x3 =—0,24.

Yuxarıdakı düsturlarla ardıcıl olaraq tapırıq:

,----- ,------- g2i 1lil = = V'6.25 = 2,5; /21 = — = — = -0,4,

d'jı 0,5 I "Z 1--------------— ~| = TT’ — ə'2; I22 = I a22 ~ ^21 = ~ 0,16 =

111 N= 2,2,a32 — I31I21 2,12 — 0,2(—0,4) _

32 ~ /22 ~ 2,2G3 ~ .Iaz2 ~ ^31 — ^32 ~ -\/3<6 ~ 0,2z — l2 = 1,6.

Onda L matrisi belə olacaqdır:

2,5 0-0,4 2,20,2 1

0 \0 ‘

1,6/

Bu matrisə uyğun sistem belə olur:

2,5yx = 7,5-0,4yi + 2,2y2 = ~8>68

0,2yı + y2 + l,6y3 = —0,24.

Bu sistemi həll edərək yı,yz,y3 tapırıq. Sonra isə bu sistemə uyğun matrisi transponirə etməklə ]Jx = y şəklində tənliklər sistemini tərtib edirik:

Yeddincifasil. Ədadi üsul alqoritmlari 297

2,5 Xj - 0,4x2 + 0,2x3 — 32 ,2x2 + x3 = —3,4

1,6x3 = 1-6.

Bu sistemdən isə axtarılan həlli tapırıq: xx = 0.8, x2 = —2, x3 = 1.

XCTS-in həlli üçün Xoleski üsulunun C# dilində tərtib edilmiş proqramının mətni belədir:

using System;

namespace XOLESKY {class Program

// n*n ölçülü matris// n+l-ci sütun XCTS-in sol tərəfini // köçürmək üçün istifadə edilir

static double[,] A = new double[4, 5];static double[] B = new double[4]; static int n;

//Xoleski üsulustatic void Holetsky(double [,] Al,

double [ ] Bİ, int n) (int i, j, t;double [,] c = new double[4, 5];double [,] L = new double[4, 5];double[] y = new double [4];double sum;

for (i = 1; i <= n; i++) for (j = 1; j <= n 4- 1; j4-*) {

c i i , j ] = 0 ;L [ i , j ] = 0 ;

298 Məhərrəmov Z.T., Vəliyev H.P,

y[i] 0;

// Matrisin transponirə edilmiş matrisə// vurulmasıfor (i = 1; i <= n; i++)

for (j = 1; j <= n; j++)

sum = 0.0;for (t = 1; t <= n; t++)sum= Al[t, j] * Al[t, i] + sum;c[i, j] = sum;

)

// Sağ tərəfin transponirə edilmiş // matrisə vurulması

for (i = 1; i <= n; ı + + )for (j = 1; j <= n; j++)

y[i] = ai[j, i] * Bl[j] + y[iJ;for (ı = 1; i <= n; i++)

for (j = 1; j <= n; j++)

Al[i, j ] = c[i, j];Bİ[i] = y [i] ;

)for (i ~ 1; i <= n; i + + ) (for (j = 1; j <= i; j++)

sum = 0;for (t = 1; t <= j - 1; t++)

sum= sum + L[i, t] * L[j, tl ;if (i != j)

L[i, j]=(Al[i,j]-sum)/L[j,jl;else

L [ i, i]=Math.Sqrt(Al[ı,i]-sum)' }

Yeddinci fəsil. Ədədi üsul alqoritnıləri 299

for (i = 1; i <= n; i++)L[i, n + 1]= B1 [ i ] ;

Bİ[1]= L[l, n + 1] / L[l, 1] ;

for (i = 2; i<=n; i + +) //I

for (j = 1; j <= i - 1; j++)L[i,n+1]= [i, n+1]-L[i, j]*B1[jj ;

B1 [ i ] = L[i, n + 1] / L [ i, i ] ;

for (i = 1; i <= n; i++){for (j = i + 1; j <= n; j++){

L [ i, j] = L[j, i];L[j, İ] = 0;

ıL [ i, n + 1 ] = B1 [ i ] ;!

B1 ■ n ] = L [ n, n + 1 ] / L [ n, n ] ;

for (i = n - 1; i >= 1; i--){

for (j = i + 1; j <= n; j++)L[i , n-1]=L[i , n+1j-L[i,j]*B1 [ j] ;

Bİ[i]= L[i, n + 1] / L[i, i];

static voıd Main(string[] args) {// Matrislərin 0 indeksli// elementlərini istifadə etmirik: n=3;A[l,l]=6.25; A[l,2]=-1.0; A[l,3]=0.5;

A [ 1,4]=0.0;A[2,l]=-1.0; A[2,2]=5.0; A[2,3]=2.12;

300 Məhərrəmov Z.T.t Vəliyev H.P.

A[2,4]=0.C;A[3,l]=0.5; A[3,2]=2.12; A[3,3]=3.6;

A[3,4]=0.G;B[l] = 7.5; B[2] = -8.68; B[3J = -0.24; Console.WriteLine("\nVerilmish XCTS: ") ; Print_matr(A, B, n);Console.WriteLine("\nXoleski üsulu ile

sistemin helli:");Holetsky(A, B, n); Print_vectr(B, n) ;

Console.ReadLine();)

// Əsas matrisin ekrana çıxarılması static void Print_matr(double[,] Al,

double[] Bİ, int N) { int ı, j;fcr (i = 1; i <= n; i + +) {for (j = 1; j <= n; j++) Console.Write("{0,6:f2} ",

Al [i, j] );Console.Write("{0,6:f2} ", Bl[i]);

Console.WriteLine(); } }

// Sağ tərəfin ekrana çıxarılması static void Print_vectr(double[] Bİ,

int N){int j ;for (j = 1; j <= n; j++)Console.WriteLine("x{0) ={1,6:f2) ",

j, Bİ ij ] ) ;Console.WriteLine();}} }

Yeddinci fəsil. Ədədi üsul alqoritntiəri 301

Proqramın nəticəsi şəkil 7.9-da göstərilmişdir.

■ • F:\ZAIQR\VSA\XOLESKY\XOI_ESK... '

Uerilmish XCTS: 6,25 -1,00 0,50 7,50

-1,00 5,00 2,12 -8,680,50 2,12 3,60 -0,24

Xoleski metodu ile sistemin helli: xl - 0,80 x2 “ -2,00 x3 » 1,00

Şəkil 7.9. Xoleski üsulu ilə sistemin həllininnəticələri

Proqramın giriş parametrləri aşağıdakılardır:n - sistemin ölçüsü (məchulların sayı);Al - n*(n+l) ölçülü sistemin əmsallarından ibarət

matrisdir, n+l-ci sütun hesablamanı sadələşdirmək məqsədi ilə XCTS-in sağ tərəfini köçürmək üçündür;

Bİ - sistemin sərbəst hədləridir.Çıxış parametri isə Bİ - sistemin həllidir (Bİ üsul

çağrılana kimi tənliyin sağ tərəfləridir).Qauss üsulu ilə Xoleski üsulunun dərin əlaqələri vardır.

Əgər sistemin matrisi simmetrikdirsə və müsbət təyin olunmuşdursa, onda xətt cəbri tənliklər sisteminin həll etmək üçün Xoleski üsulu Qauss üsulundan üstün hesab edilir. Belə ki, XCTS-ni Xoleski üsulu ilə həll etdikdə hesablamaya sərf edilən vaxt iki dəfə azalır. Xoleski üsulunun digər şərtsiz üstünlüyü onun zəmanətli dayanıqlığındadır. Hesablama əməliyyatlarının sayına görə hər iki üsulun mürəkkəbliyi

3 7 2eynidir və belə əməliyyatların sayı n = ” + Jn -n

3bərabərdir.

302 Məhərrəmov Z.T., Vəliyev H.P.

7.4.3. İterasiya üsulu

(7.5) XCTS-ni iterasiya üsulu ilə həll edək. Bunun üçün diaqonal elementlərini ^0 (z = 1,2,...,«) hesab edib.

birinci tənlikdən X, -i. 2-ci tənlikdən -V, -ni, və s. tapaq:

r - *" an1 „ ann-l vXn-

ünn Unn ann

işarə edərək (7.8) sistemini belə yazaq:

A'ı - A +a-|2a-2 +o'I3x3 + ... + alnx„x2 -/32+a2lx2+a23x3+... + a2nx„

■ (7-9)

X" a„]X] a„2X2 V ■..+U„ n_jXll_}

Burada. an = 0, z = 1,2,...,/?.(7.9) sistemini matris formasında yazaq:

X = p + aX (7.10)

Burada:

Yeddinci fəsil. Ədədi üsul alqoritmləri 303

(7.10) sistemini ardıcıl yaxınlaşma üsulu (iterasiya) ilə həll etmək üçün məchullara başlanğıc qiyməti vermək (sıfırına yaxınlaşma) lazımdır. Başlanğıc yaxınlaşma kimi (7.10) sisteminin sərbəst hədlərini qəbul edək, yəni: Xw = 0. Är,lll-ı (7.10)-da yazaraq 1-ci iterasiyada məchul­ları hesablayırıq, yəni:

A'(l’ = /? + <zY,0)

Sonra 2-ci yaxınlaşmada məchulları hesablayırıq:

XM = ft + aX{']

Beləliklə, XCTS-i üçün ümumi halda aşağıdakı düsturu yaza bilərik:

X(k+'} = /3 + aXw . (7.11)

Qeyd edək ki, bütün iterasiya üsullarında başlanğıc yaxınlaşma kimi sərbəst hədlərin qəbul edilməsi məcburi deyildir və ixtiyari qiymətlər götürmək olar. Yığılan iterasiya prosesləri səhvləri öz-özünə düzəltmək qabiliyyətinə malikdir. Hər hansı bir iterasiyada buraxılan səhv son nəticəyə təsir göstərmir, o sanki yeni başlanğıc qiymət kimi qəbul edilir.

Misal. Aşağıdakı tənliklər sistemini iterasiya üsulu ilə həll edək:

304 Məhərrəmov Z.T., Vəliyev H.P.

1 Ox, + x2 + xyb = 12 < 2xj+10x2+x3 = 13

2X] + 2x2 + 10x3 = 14.

Hər bir tənliyi uyğun olaraq xt, x2 və x3 görə həll edək:

x, = 1,2 -0,lx2 -0,lx3 x2 = l,3-0,2x, -0,lx3

x3 =l,4-0,2Xj -0,2x2

x^°'= 1,2; x2°’= 1,3 və x30)=l,4 qəbul edək və bu qiymətləri verilmiş tənlikdə yerinə yazaq:

Xj(l) = 1,2-0,1 1,3-0,1 1,4 = 0,93

x?) = 1,3-0,2-1,2-0,1 1,4 = 0,92

x?’ = 1,4 -0,2 1,2 -0,2 1,3 = 0,9.

İkinci iterasiyanı hesablayaq:

xf2) = 1,2 - 0,1 • 0,92 - 0,1 • 0,9 = 1,018

xj2) = 1,3 - 0,2 • 0,93 - 0,1 • 0,9 = 1,024

x<2) = 1,4 - 0,2 • 0,93 - 0,2 • 0,92 = 1,03və s.

Hesablama prosesi iki qonşu iterasiyada alınmış köklərin fərqi verilmiş dəqiqlikdən kiçik və ya ona bərabər olana qədər davam etdirilir.

İterasiya üsulunun C# dilində tərtib edilmiş proqramın mətni belədir:

using System;

Yeddinci fəsil. Ədədi üsul alqoritmləri 305

nanespace XCTS_Iterasiya (class Program

static void Main(string [ ] args)

double[] b = new dcuble[5];double [] beta = new double[5];double [ ] x_curr = new double [5]; double[] x_prev = new double[5]; double[] x_tmp = new double[5]; double [,] a = new double[5, 5]; const int n = 3;const double e = 0.00001;int i, j, k, max;double [ j sum = new double[5];double suml, sum2;

a[0,0]=6.25; a[0,l]=-1.0; a [0,2]= .5;a [1,0]=-1.0; a[1,1]= 5.0; a[1,2]= 2.12; a[2,0]= 0.5; a[2,1]= 2.12;a[2,2]= 3.6;b[0] = 7.5; b[1] = -8.68; b[2] = -0.24;

suml = 0; sum2 =0; k = 0;

for (i = 0; i < n; i + +) beta [i] = b[i] / a [i, i];

do

k++;if (k != 1)

for (i = 0; i < n; i++) x_prev[i] = x_tmp[i];

for (ı = 0; i < n; i + +) {suml = 0;for (j = 0; j < i ; j + +)

306 Məhərrəmov Z.T., Vəliyev H.P.

suml = suml + a[i, j] * x_prev[j];s um2 = O;

for (j = i + 1; j < n; j++)sum2 = sum2 + a[i, j] * x_prev[j];

x_curr[i] = (b[i]-suml-sum2)/a[i,i J; }

for (i = 0; i < n; i + +) x_tmp[i] = x_curr[i];

max = 1;

for (i = 1; i < n - 1; i + +) if (Math.Abs(x_curr[max] - x_prev[max]) <Math . Abs (x_curr [ i + 1 ] -x__prev [ i+ 1 ] ) )

max = i + 1;

while (Math.Abs(x_curr[max] - x_prev[max]) > e);

Console . Wr i teLine ("\nlteras iya usulu üe tenliyin helli:\n");

for (i = 0; i < n; i++) Console.WriteLine(”x{0} = {l,5:f3}",

i+1, x_curr[i]);

Console.WriteLine("\nlterasiyalarin sayi=" + k);

Console.ReadLine();}}}

Yeddinci fəsil. Ədədi üsul alqoritmləri 307

Proqramın nəticəsi şəkil 7.10-da göstərilmişdir.

.12 F:\ZAKIR\VSA\XTCS_Ite ra5İyaÖöCTc7L=IM^^^I

iterasiya usulu ile tenliyin belli:

Kİ = 0,800 k2 = -2,000 k3 = 1,000

Iterasiyalarin sayi-21

Şəkil 7.10. İterasiya üsulu ilə sistemin həllinin nəticələri

7.4.4. Zeydel üsulu

Bu üsul iterasiya üsulunun modifikasiyasıdır. Zeydel üsulunun əsas ideyası ondan ibarətdir ki, X, məchulunun hesablanmasında (£+/)-ci iterasiyada X{ X2,..., Xl_l məchullarının (k+l) -ci iterasiyada artıq hesablanmış qiymətləri istifadə edilir. Bu üsulu (7.9) gətirilmiş sistemindən başlayaraq tətbiq edək (bu mərhələyədək aparılan əməliyyatlar burada da öz gücündə qalır).

(7.9) sistemini belə yazaq:

X, = A + E a»x> Ə = u,...,n . (7.12),/=ı

(k+l)-c\ iterasiya üçün (7.12) sisteminə əsasən Zeydel iterasiya düsturunu belə yaza bilərik:

-^~-Mə!12!Z2inov z. T., Vəliyev H.P.

/=> '

X\k^ = p2+auX\k^^ a2jX^\ Ä: = 0,1,2,...

Misal. Aşağıdakı tənliklər sistemini Zeydel üsulu ilə həll edək:

10x,+x2+x3 = 12

2x, + 10x2+x3 =13

2x1+2x2 + 10x3 = 14.

Tənlikləri x1?x2 və x3 -ə görə həll edək:

%! = l,2-0,lx2 -O,1x3

x2 = 1,3 - 0,2x, - 0,lx3 x3 = 1,4 - 0,2X] - 0,2x2 .

xf0) = 1,2; x’0) = 1,3; x30) = 1,4 qəbul edək. Birinci iterasiya:

x,(1) = 1,2 -0,1 -1,3 -0,1 -1,4 = 0,93

= 1.3 - 0,2 • 0,93 - 0,1 ■ 1,4 = 0,974

x‘» = 1.4 - 0,2 • 0.93 - 0,2 ■ 0,974 = 1,0192.

Yeddinci fəsil. Ədədi üsul alqoritmləri 309

İkinci iterasiya:

xf2) = 1,2 - 0.1 ■ 0,974 - 0,1 • 1,0192 = 1,00068

x?’ = 1,3 - 0,2 • 1.00068 - 0,1 ■ 1.0192 = 0.998

x,(2) = 1,4 - 0,2 • 1.00068 - 0,2 • 0.998 = 1,00026

2- |Ö2I| + 1^23i = 2 +1 = 3.

Yığılma şərti ja22| > |a21 + |O|3j- deməli J0 > 3.

və s.

7.4.4.1, İterasiya prosesinin yığılması

Bu və ya digər məsələni kompüterdə həll etdikdə iterasiya prosesinin yeganə həllə yığılmasının tədqiqi ən vacib məsələdir. Əgər iterasiya prosesi yığılmazsa (dağılandırsa), onda sonsuz dövretmə başlayacaqdır. Bu halı əvvəlcədən görmək lazımdır. İterasiya prosesinin yığılmasını iki hal üçün araşdırmaq olar. Birinci halda, XCTS (7.5) şəklində verildikdə, iterasiya prosesinin yığılması şərti belədir:

M (7.13)

Həll etdiyimiz misal üçün bu şərti yoxlayaq:

aH - 10; a27 = 10; a,. - 10,|ÜI2İ +|ÖI3İ = i + 1 = 2.

Yığılma şərti |zz, J > [a12| 4-|«l3|. deməli 10 >2.

310 Məhərrəmov Z. T., Vəliyev H.P.

3-|a„| + N = 2 + 2 = 4.

Yığılma şərti |a33| >|cr3l| + |a32|, deməli 10 >4.(7.13) şərti ödəndiyi üçün həll etdiyimiz sistem üçün

iterasiya prosesi yeganə həllə yığılacaqdır.İkinci halda (7.5) XCTS-ni (7.8) şəklinə gətirdikdən

sonra iterasiya prosesinin yığılan olmasını yoxlamaq olar. (7.8) sistemi üçün iterasiya prosesi o vaxt yığılacaqdır ki,

nE |tzy | < 1, i = 7=1

və ya

E kH1’ j

/=1

şərtlərindən biri ödənsin.Həll etdiyimiz misal üçün bu şərtləri yoxlayaq.

z=l:

|a, ı|+laı 21 + |«u| = o+0,1+0,1 = o,2 < ı.z = 2:

|«211 + )«22| + |a23| = 0,2 + 0 + 0,1 = 0,3 < 1.

z = 3:

|«3 !İ +1«321 + |a33| = 0,2 + 0,2 + 0 = 0,4 < 1.

2.7 = 1:

|ozıı|+|rz2]| + |(z3|| = 0 + 0,2 + 0,2 — 0,4<l. 7=2:

|a12| +|«22| + |a32| = 0,1 + 0 + 0,2 = 0,3 < 1.

Yeddinci fəsil. Ədədi üsul alqoritmləri 311

J=3:

|a, 3| + |a23| + |a33| = 0,1 + 0,1 + 0 = 0,2 < 1.

İterasiya prosesinin dayandırılması şərti. İterasiya prosesi o zaman dayandırılır ki, məchulların iki qonşu iterasiyadakı qiymətlərinin mütləq qiymətcə fərqi verilmiş dəqiqlikdən kiçik və ya ona bərabər olsun, yəni

7.4.4.2. Zeydel üsulunun alqoritmi

Zeydel üsulunun C# dilində tərtib edilmiş proqramin mətni belədir;

using System;namespace Zeydel{class Program (static voıd Main(string[] args) {

const int n = 3;const double e = 0.00001; int i, j, t, iter;double suml, s;

double[,] a = new double[n, n]; double[,] c = new double[n, n]; double[] sl = new double[n]; double[] x = new double[n]; double [] xO = new double[n]; double[] d = new double[n]; double[] b = new double[n];

312 Məhərramov Z. T., Valiyev H.P.

double [ ] z = new double[n];

a [ 0, 0 ] = 6.25; a[0,1]= -1.0; a[0,2]= 0.5; a[l,0]= -1.0; a[l,l] = 5.0; a[l,2]=2.12; a[2,0]= 0.5; a[2,1]= 2.12; a[2,2]=3.6; b[0] = 7.5; b[l] = -8.68; b[2] = -0.24;

for (i = 0; i < n; i++)for (j = 0; j < n; j++) (

if (i == j) c[i, j] = 0;else c[i, j] = -a[i, j]/a[i, i];

}for (i = .0; i < n; i + +) d[i] = b[i] / a [ i, i];

// Yığılmanın yoxlanması for (i = 0; i < n; i++) {suml = 0;for (j = 0; j < n; j ++)

suml = suml + c[i, j];s1[i] = suml;

}suml = s1 [ 1];for (i = 0; i < n; i++)

if (sl[i] > suml) suml = sl[i];

if (Math.Abs(suml) < 1){// Yoxlamanın sonu

for (i =0; i < n; i++) x0[i] for (i = 0; i < n; i++) {

s = 0 ;for (j = 0; j < n; j++)

s = s + c[i, j] * x0[j];x [ i ] = s ;

d[i] ;

Yeddinci fəsil. Ədədi üsul alqoritnıləri 313

for (i = 0; i<n; i++) x [i]=x[i]+d[i];

iter = 0; do{iter++;for (i = 0; i < n; i++){x0[i] = x[i];z [i] = xO[i];

} for (i = 0; i < n; i++) {

s = 0;for (j=0; j<n; j++) s=s+c[i,j]*z[j];x [ i ] = s + d [ i ] ;z [ i ] = x [ i ] ;

}t = 0;for (i = 0; i < n; i++)

if (Math. Abs (x [i]-xO [i] ) <e) t=t+l;}while (t != n);

Console.WriteLine("\nZeydel usulu ile tenliyin helli:\n");

for (i = 0; i < n; i++) Console.WriteLine("x { 0 } = {l,6:f2}",

i+1, x[i]);

Console.WriteLine();Console.WriteLine("Iterasiyalarin sayi =

" + iter);} else Console.WriteLine("Iterasiya

yigilmir");

314 Məhərrəmov Z.T., Vəliyev H.P.

Console.Read();}} }Proqramın nəticəsi şəkil 7.1 1-də göstərilmişdir.

,1 j F:\ZAKIR\VSA\ZeydeI\Zeydel\... I 1=1 I ~-l

leydel usulu ile tenliyin belli:

:1 = 0,80:2 = -2,003 = 1,00

Iterasiyalarin sayi = 11

rrr

Şəkil 7.11. Zeydel üsulu ilə sistemin həllinin nəticələri

İterasiya üsulu ilə Zeydel üsulunun həllərinin nəticələrini müqayisə etdikdə görürük ki. eyni bir tənliklər sistemini eyni dəqiqliklə həll etdikdə Zeydel üsulunda iterasiyaların sayı təxminən iki dəfə az olur.

FƏSİL

REKURSİVALQORİTMLƏR

Rekursiya çox güclü proqramlaşdırma metodudur. O problemi o qədər kiçik ölçülü məsələlərə parçalayır ki, sonda onların həlli sadə əməliyyatlar yığımından ibarət olur.

Əgər metod (funksiya, prosedur) özü özünə müraciət edirsə, onda rekursiya baş verir. İki növ rekursiya bar: birbaşa və dolayı.

Birbaşa rekursiya bilavasitə özünə müraciət edir. Məsələn:

static long faktorial (int i) 1if(i==l) returni;return i*faktorial(i-1);

}

Dolayı rekursiyada isə birinci metod ikinci metodu, ikinci metod isə öz növbəsində birinci metodu çağırır, məsələn:

static int birinci (int i) (

316 Məhərrəmov Z.T., Vəliyev H.P.

ikinci (i-1);

static int ırinci (int i) {birinci (num%2))

8.1. Faktorialın rekursiv hesablanması

N tam ədədinin faktorialı /V! kimi yazılır. Mənfi ədədin faktoriaiı təyin edilməyib. 0! isə vahidə bərabərdir.

Faktorialın hesablanması düsturu belədir:/V! = /V * (/V — 1) * (/V — 2) * ... * 2 * 1.

Bu funksiya çox böyük sürətlə artan funksiyadır.Faktorialı rekursiyanın köməyi ilə belə müəyyənləşdir­

mək olar:0! = 1,

W! = /V* (W- 1)!, bütün tam N > 0 üçün.Buna uyğun rekursiv metodu belə tərtib edə bilərik:

static long faktorial(int i) i

if (i <- 0) return 1;else

return i * faktorial(i - 1); )

Burada, əvvəlcə N < 0 şərti yoxlanır. Əslində mənfi ədədlərin faktorialı məlum deyil, bu şərt sığortalanmaq üçün yazılmışdır. Əgər metod yalnız N = 0 şərtini yoxlasaydı, onda rekursiya sonsuz davam edərdi. Proqrama N < 0 qiyməti daxil edildikdə metod bizə 1 qiyməti qaytaracaqdır. Əks halda metod daxil edilən ədədin faktorialından ibarət qiymət qaytaracaqdır. Burada iki amil zəmanət verir ki,

Səkkizinci fəsil. Rekursiv alqoritmlər 317

rekursiv metod hökmən dayanacaqdır: birincisi, hər növbəti addımda i dəyişəninin qiyməti 1 vahid azalır. İkincisi, i dəyişəninin qiyməti sıfırla məhdudlaşmışdır. Onun qiyməti 0-a bərabər olduqda metod rekursiv olaraq dayanacaqdır, i < 0 şərti əsas şərt və ya dayandırma şərti adlanır. Hər müraciət zamanı sistem qiymətləri stekdə saxlayır, rekursiv metodlara həddən artıq müraciət olunduqda stekin dolub- daşması baş verə bilər.

Mürəkkəbliyin təhlili. Faktorialın hesablanması alqoritmində yalnız bir parametr vacibdir ki, o da faktorialı hesablanacaq ədəddir. Bildiyimiz kimi, alqoritmin mürəkkəbliyinin təhlilində, adətən, mürəkkəblik məsələnin ölçüsü və ya giriş parametrlərinin sayından asılı funksiya kimi təyin olunur. Bu mənada, baxdığımız alqoritm üçün mürəkkəblik bir az qəribə görünə bilər. Ona görə də bir parametrdən asılı alqoritmlər, adətən, giriş parametrlərinin sayı nöqteyi-nəzərindən yox, giriş parametrlərinin saxlanması üçün zəruri olan bitlərin sayı nöqteyi-nəzərindən təhlil edilir. Bu üsul baxılan məsələni çox da əyani təsvir etmir. Bundan başqa, kompüter nəzəri olaraq N giriş ədədini log2 /V sayda bitlərdə saxlayır. Əslində isə hər bir ədəd onun tipindən asılı olaraq müəyyən sayda bitlərlə təsvir olunur. Məsələn, C# dilində long tipli müsbət tam ədəd 1 və ya 9223372036854775807 ədədinə bərabər olsa belə, 64 bit yer tutacaqdır. Ona görə də belə alqoritmlərin mürəkkəbliyi giriş qiymətinə görə yox, onun ölçüsünə görə təhlil edilməlidir. Giriş verilənlərinin ölçüsünə görə qiymət­ləndirmədə N = 2m düsturundan istifadə etmək olar. Burada, M-N ədədini yadda saxlamaq üçün lazım olan bitlərin sayıdır. Əgər N giriş kəmiyyətinə görə mürəkkəblik O(/V2) -na bərabərdirsə, onda M parametrinə görə mürəkkəblik belə hesablana bilər:

O((2m)2) = O(22*M) = O((22)M) = O(4M).

318 Məhərrəmov Z. T., Vəliyev H.P.

Faktorialın hesablanması alqoritmində metod N,N — 1,N — 2 və s. qiymətləri üçün N = 0 olana qədər çağrılır və rekursiya başa çatır. Əgər başlanğıc qiymət N olarsa, onda metod N+l dəfə çağrılır, ona görə də onun mürəkkəbliyi O(/V) olur. M parametrinə görə isə mürəkkəblik O(2M) olur.

0(W) funksiyası çox yavaş artır, ona görə də adama elə gəlir ki, bu alqoritm çox məhsuldardır. Əslində isə bu nəzəri olaraq belədir. Bu metod stek dolduqda və ya kompüter çox böyük N üçün faktorialı hesablaya bilmədikdə səhv verir. Məhsuldarlığı artırmaq üçün double (Delphi-də extended) və ya istənilən yüksək dəqiqlikli tiplərdən istifadə etmək olar.

8.2. Ən böyük ortaq bölənin rekursiv hesablanması

Ən böyük ortaq böləni (ƏBOB) tapmaq üçün biz birinci fəsildə Evklid alqoritmini öyrəndik. İndi isə ƏBOB-un başqa alqoritmlə hesablanmasına baxaq. XVIII əsrdə böyük riyaziyyatçı Eyler çox maraqlı bir faktı aşkar etmişdir: əgər B ədədi A ədədinə tam bölünərsə, onda

ƏBOB(A,B) = A.

Əks halda isə

ƏBOB(A, B) = ƏBOBÇB mod A, A).

Bu faktı ƏBOB-u daha tez hesablamaq üçün istifadə etmək olar. Məsələn:

Ə£?0F(9,12) = ƏF0B(12 mod 9,9) = ƏBOB(3,9) = 3.

Əgər A ədədi B ədədinə tam bölünmürsə, onda 1 < B mod A < A olduğundan hər bir addımda müqayisə olunan

Səkkizinci fəsil. Rekursiv alqoritnılər 319

ədədlər kiçilir və nəhayət sonda 7-ə bərabər olur. Hər bir B ədədi 7-ə tam bölündüyündən rekursiya da başa çatır.

Eylerin kəşfi aşağıdakı kifayət qədər sadə rekursiv alqoritmi yaratmağa imkan verdi:

static long ABOB(long A, long B) {

if (B % A == 0) return A;else return ABOB(B % A, A);

}

Main metodunda bu metoda müraciət etməklə şəkil8.1-də göstərilmiş cavabı almaq olar.

■3 F:\ZAKIR\VSA\A BOB\ABOE\bin\Debu g\A BO B.exel ° I

6854779886, 8923372836854775804) -6iBOB rekursiv metoduna muracietirin sayi k=34

| < L I►

Şəkil 8.1. ƏBOB-un rekursiv hesablanması

Mürəkkəbliyin təhlili. Alqoritmin mürəkkəbliyini təhlil etmək üçün A ədədinin hansı sürətlə kiçilməsini müəyyən etmək lazımdır. İsbat edilmişdir ki, ABOB metodu hər dəfə çağrıldıqda A parametri ən azı 2 dəfə kiçilir.

Tutaq ki, A parametrinin ilkin qiyməti N-dir. ABOB metodunu 2 dəfə çağırdıqdan sonra A parametrinin qiyməti ən çoxu N/2-ə qədər kiçiləcəkdir. 4 dəfə çağrıldıqdan sonra bu qiymət ((/V/2))2 = /V/4-dən çox olmayacaqdır. 6 dəfə çağrıldıqdan sonra bu qiymət maksimum Ç7V/4)/2 = 7V/8 olacaq. Ümumiyyətlə, 2-k dəfə çağrıldıqdan sonra A parametrinin qiyməti maksimum N/2k olacaqdır. Alqoritm A=1 olduqda dayandığı üçün, o N/2k = 1 olana qədər öz işini davam etdirəcəkdir. Bu N = 2k və ya k = log2 N olduqda baş verir. Alqoritm 2-k addıma yerinə yetirildiyi

320 Məhərrəmov Z.T., Vəliyev H.P.

üçün, o 2-log2N addımdan çox olmayaraq dayanacaqdır. Sabit vuruğu atsaq, alqoritmin mürəkkəbliyi üçün 0(logN') funksiyasını alarıq. Yəni, alqoritmin yerinə yetirilmə vaxtı OÇlogN) olacaqdır. Mürəkkəbliyi OÇlogN) olan alqoritmlər, adətən, çox tez yerinə yetirilir. ƏBOB alqoritmi də müstəsna deyil. Məsələn, 9223372036854775806 və 8223372036854775804 ədədlərinin ƏBOB-unun 6-ya bərabər olduğunu hesablamaq üçün metod cəmi 34 dəfə çağrıİmişdir. C# dilində long tipinin yuxarı sərhəddini aşdıqda bu alqoritm yararlı olmayacaqdır.

8.3. Fibonaççi ədədlərinin rekursiv hesablanması

Fibonaççi ədədləri tam natural ədədlərdir və elə tam ədədlər ardıcıllığıdır ki, hər növbəti ədəd özündən əvvəlki iki ədədin cəminə bərabərdir, yəni:

Fo = 0,Fı = l,Fn = Fn-t + Fn-2-

Onun bir neçə ilk hədləri bunlardır:

0,1,1,2,3,5,8,13,21,34,55,...

Fibonaççi ədədlərinin yaradılmasının rekursiv alqoritmi belədir:

static long Fib(long n){

if (n <= 1) return n;elsereturn Fib(n-1)+Fib(n-2);

Səkkizinci fəsil. Rekursiv alqoritnılər 321

Main metodunda bu metoda müraciət etməklə şəkil 8.2-də göstərilmiş cavabı almaq olar.

IJ F:\ZAKIR\VSA\Fibonachı\Fibonachı\bin\Debug\Fibonach'ı.eıe

Şəkil 8.2. Fibonaççi ədədlərinin rekursiv hesablanması

Alqoritmin mürəkkəbliyi. Bu alqoritmin təhlili qeyri- adidir. Əvvəlcə n < 1 şərtinin neçə dəfə yerinə yetirildiyini, sonra isə Fib metoduna neçə dəfə müraciət olunduğunu müəyyən etmək lazımdır. Tutaq ki, daxil edilən ədəd N-dir. Onda N < 1 olduqda metod əsas şərtə çatır və rekursiya tələb olunmur. N > 1 olduqda isə metod Fib(N-l) və Fib(N-2) funksiyalarını rekursiv hesablayır və öz işini başa çatdırır. Deməli, metod öz işini N-l və N-2 qiymətlərində funksiyanı hesablamaqla başa vurur. Buradan isə belə nəticəyə gəlmək olar ki. addımların ümumi sayı Fib(N+l) olacaq. Metod rekursiyaya Fib(N+l)-l dəfə müraciət edir. Onda addımların sayı ilə rekursiyaya müraciətlərin sayını birləşdirsək, alarıq ki, alqoritmin mürəkkəbliyi 2Fib(n) — 1 ifadəsindən böyükdür. Bu isə o deməkdir ki, alqoritmin mürəkkəbliyi OÇFib(n)') ilə ifadə olunur.

Fibonaççi metodunun artma sürətini müəyyən etmək üçün

Fib(M) > /f~2

düsturundan istifadə edilir. Burada /? təxminən 1,6 -ya bərabər olan sabitdir. Onda mürəkkəblik üstlüfunksiyası ilə xarakterizə oluna bilər. Bütün digər funksiyalar kimi, bu funksiya polinomial funksiyalardan daha sürətlə,

322 Məhərrəmov Z. T., Vəliyev H.P.

faktorial funksiyalarından isə daha ləng böyüyür. Yerinə yetirilmə vaxtı çox tez artdığı üçün, ilkin verilənlərin böyük qiymətlərində bu alqoritm kifayət qədər yavaş işləyir, hətta o qədər ləng işləyir ki. n > 45 üçün Fib(n) metodu ilə Fibonaççi ədədlərini praktiki olaraq hesablamaq mümkün olmur (bu, hal long tipini double tipi ilə əvəz etdikdə də təkrarlanır).

8.4. Rekursiyanın çatışmazlıqları

Rekursiya böyük məsələlərin hissələrə bölünməsi üçün çox güclü metoddur, amma onun tətbiqi bəzi hallarda təhlükəli ola bilər. Ən aşkar müşahidə edilən təhlükələrdən biri rekursiyanın sonsuz dövretməsidir. Əgər alqoritm düzgün qurulmazsa, onda funksiya əsas şərti buraxa bilər ki, bunun da nəticəsində sonsuz dövretmə başlaya bilər. Faktorialın hesablanması üçün aşağıdakı rekursiv metoda baxaq:

static long faktorial(int i) {

return i * faktorial(i - 1); }

Bu metodda rekursiyanın sona çatması şərti yoxlanmır, ona görə də o sonsuz olaraq özü özünü çağıracaqdır. Həm də bu hal daxil ediləcək qiymətdən asılı olmadan baş verəcək.

Rekursiyanın digər təhlükəsi yaddaşdan səmərəsiz istifadədir. Hər dəfə alt proqramı çağırdıqda sistem yeni metodun lokal dəyişənləri üçün yaddaş sahəsi ayırır. Rekursiv müraciətlərin mürəkkəb ardıcıllığını emal etmək üçün dəyişənlərin yerləşdirilməsi və yaddaşın azad olması üçün kompüterə böyük həcmdə resurslar tələb olunur. Hətta, əgər proqram yaddaşın bütün stekini zəbt etməsə də, dəyişənlərin idarə edilməsinə həddən çox vaxt sərf edəcək.

Səkkizinci fəsil. Rekursiv alqoritmlər 323

Digər çatışmazlıq rekursiyanın əsaslandırılmamış tətbiq edilməsidir. Rekursiyanın tətbiqi məsələnin həll edilməsi üçün həmişə ən yaxşı üsul deyil. Faktorialın, ƏBOB-un və Fibonaççi ədədlərinin hesablanması üçün yuxarıda tərtib etdiyimiz rekursiv metodlara əslində ehtiyac yoxdur, bu məsələlər rekursiyadan istifadə edilmədən də çox asanlıqla həll edilə bilər.

Digər tərəfdən, Fibonaççi ədədlərinin hesablanması alqoritmini rekursiya dağıdır. Fib(N)- hesablamaq üçün alqoritm əvvəlcə Fib(N-l)-i və Fib(N-2)-ni hesablayır. Lakin, Fib(N-l)-i hesablamaq üçün alqoritm Fib(N-2) və Fib(N-3)-ü hesablamalıdır. Göründüyü kimi, bu halda Fib (N-2) funksiyası 2 dəfə hesablanır.

Əvvəlki təhlillər göstərdi ki, Fib(N)-nin bütün hesablanması prosesində Fib(O) və Fib(l) funksiyaları Fib(N+l) dəfə hesablanır. Fib (45) =1134903170 olduğundan Fib (44)-ün hesablanması üçün faktiki olaraq proqram Fib(0) və Fib (1)-i 1134903170 dəfə hesablayır. Fibonaççi ədədlərinin rekursiv hesablanması alqoritmi bu aralıq qiymətlərinin dəfələrlə yenidən hesablanmasına çox böyük vaxt itirir (yeri gəlmişkən, Fib (45) üçün taymerlə ölçülmüş vaxt təqribən I dəqiqə 10 saniyə, rekursiyanın sayı isə k=1836311902 oldu). Bundan başqa, bu alqoritm N>4 5 halında tamamilə işləmir.

Fibonaççi ədədlərinin hesablanması üçün adi alqoritm- dən istifadə etməklə metod yaradaq:

static double Fib__Adi(int n){double[] F = new double[n+1];F[0] = O.Of;F[1J = l.Of;for (int i = 2; i <= n; i++)

(F[i) = F[i - 1] + F[i - 2];

324 Məhərrəmov Z.T., Vəliyev H.P.

)return F [,n] ;

}

Bu proqramla n<1476 üçün Fibonaççi ədədləri çox böyük sürətlə hesablanır (yeri gəlmişkən, Fib_Adi (1476) = 1.30 698 92 2 37 63 4E + 3 0 8). n>1476 halında metod infinity qiyməti qaytarır, çünki alınmış nəticə double tipinin yuxarı sərhəddini aşır.

Lakin bütün bunlar o nəticəyə gətirməməlidir ki, rekursiyadan istifadə etmək, ümumiyyətlə, lazım deyildir. Elə məsələlər var ki, onları rekursiyadan istifadə etmədən həll etmək ya çox çətin, ya da heç mümkün olmur. Məsələn, Hilbert və Serpinski əyrilərinin rekursiyasız çəkilməsi kifayət qədər anlaşılmaz və mürəkkəb olduğu halda, rekursiyanın tətbiqi ilə asanlıqla həll edilir.

ƏDƏBİYYAT

1. fleuTen II., flenTejı X. KaK nporpaMMwpoBaTb Ha Visual C# 2012. 5-e H3A. - CEI6.: nprrep, 2014. - 864 c.

2. JIa6op B. B. Cn lllapn: CosnaHwe npnno>KeHnw juih Windows. - Mh.: XapBecT, 2003. - 384 c.

3. Zakir Məhərrəmov, Zəfər Cəfərov. Visual C#. LAP LAMBERT Academic Publishing,201 9,- 472 pages.

4. MaKKOHHemı A Harına a.nropnTMOB. BBonHbiHKypc. MocKBa: TexHoccpepa, 2002. -304 c.

5. CwMOHOBa E.B. CTpyKTypbi aaHHbix b C#. BacTb I. JlHHeÜHbie /iHHaMMHecKMe CTpyKTypbi: vhcğ. nocoöwe / Cawapa: Ph/xaTenbCTBo CawapcKoro yHWBepcHTCTa, 2018.

6. CHMOHOBa E.B. CrpyKTypbi /jaHHbix b C#. HacTb 11. HejınHeföHbie 4HHaMHHecKMe CTpyKTypbi: yueö. rıocoöne /Cawapa: H3AaTejibCTBO CaMapcKoro yHUBepcwTeTa, 2018.

7. KypHocoB M.E, Eep.nn3OB Jf.M. AjıropHTMbi u CTpyKTypbi oSpaöoTKW HHcJıopMauHH. - Hoboch6wpck: flapajınenb, 2019. - 21 1 c.

8. HaaapenKO, H.A. H AjıropHTMbi n CTpyKTypbi ziaHHbix: yHeÖHoe nocoĞne / Cavıapa: flEYTld, 2015,- 196 c.

9. HoxpriHa f'.JI. CTpyKTypbi u ajıropHTMbi oSpaöoTKn aanHbix. Kypc jıeKiuiH. / EKaTepwHÖypr: 2015. - 107 c.

10. floHajibfl Khvt. PIcKyccTBO nporpaMMwpoBaHMB. Tom 1. OcHOBiibie ajropwTMbi. /J,HajieKTWKa- BmibiiMC, 2018. - 722 c.

11. BrıpT H. AjıropHTMbi w CTpyKTypbi aaHHbix. M.; Mwp, 1989, —360 c.

12. Axo Ajib(])peA B.. XoriKporjiT /J>koh 3, YribMaH H>Kec|)(])pH J3. CTpyKTypbi aanribix h ajıropHTMbi. M.: UsaaTenbCKHH äom "Bn.nbfl.Me", 2003.—384 c.

326 Məhərrəmov Z. T. Vəliyev H.P.

13. Cthbchc P. Delphi. ToTOBbie ajıropMTMbl /- M.: /JMK npecc ; CTI6.: HwTep, 2004. - 384 c.

14. Məhərrəmov Z.T. Pascal-dan Delphi-yə. Ali məktəb tələbələri üçün dərs vəsaiti. - Bakı: “Təhsil” NPM, 2014.-412 s.

15. EaKHenn 4>KyjiHaH M. OyH,naMeHTanbHbie ajıropwTMbl u CTpyıcrypbi ^aHHbix b Delphi. -CTI6: OOO «Z(naCo4)TlOn». 2003. - 560 c.

16. LUapbm C.H. Kypc BbiqwcnnTejibHbix MeTojıoB. HoBocwönpcK - 2018. - 604 c.

17. İsmayılov Ə. və b. Hesablama metodları və EHM- in tətbiqi. Bakı: Bakı Universiteti nəşriyyatı. 1991. - 236 s. (kiril əlifbası ilə).

18. Məhərrəmov Z.T. Alqoritm və onun təsvir üsullarıZ-Metodiki göstərişlər. Bakı: 2006. -30 səh.

Nəşriyyatın direktoru: Hüseyn HacıyevDizayn: Müşfiq HacıyevCildçi: Elmar Mikayılov

Çapa imzalanmış 25.05.2020-ci ilKağız formatı 70x1001/16, çap vərəqi 20

Sifariş 125, sayı 100

ADPU-nun mətbəəsi Bakı, Ü.Hacıbəyli küçəsi, 68

Tel: (+912) 493-74-10 Email: poliqrafıya@maiLru