6. Siyahı haqqında bizə məlumat verin
Siyahı, siyahı adlanan obyektlərin nizamlı strukturunu təmsil edən interfeysdir. Bu strukturun “hiyləsi” ondan ibarətdir ki , Siyahıya daxil olan elementlər indekslə, yəni Siyahının daxili identifikatoru ilə daxil edilə, dəyişdirilə və ya silinə bilər . Başqa sözlə, indeks: "siyahının əvvəlindən neçə element var" deməkdir. Birinci Siyahı elementinin indeksi 0, ikincinin indeksi 1 və s. Beləliklə, beşinci element siyahının əvvəlindən dörd element uzaqdadır. Yuxarıda qeyd edildiyi kimi, siyahıya maddələrin əlavə olunma ardıcıllığı vacibdir. Buna görə məlumat strukturu siyahı adlanır . Elementlərlə indekslə işləməyə yönəlmiş bu struktura xas olan metodları sadalayırıq:- get - elementi göstərilən mövqeyə qaytarır (indeks dəyərinə görə),
- sil - elementi göstərilən mövqedən çıxarır,
- set - göstərilən mövqedəki elementi metodda göstərilən elementlə əvəz edir.
- push - ötürülən elementi yığının yuxarı hissəsinə əlavə edir;
- peek - yığının yuxarı hissəsində olan elementi qaytarır;
- pop - həmçinin yığının yuxarı hissəsində olan elementi qaytarır, lakin onu çıxarır;
- empty - yığının boş olub olmadığını yoxlayır - doğru və ya yanlış - yalan ;
- axtarış - verilmiş element üçün yığını axtarır. Element tapılarsa, onun yığının yuxarı hissəsinə nisbətən sıra nömrəsi qaytarılır. Element tapılmazsa, -1 dəyəri qaytarılır.
7. Xəritə haqqında bizə məlumat verin
Yuxarıda qeyd edildiyi kimi, Xəritə interfeyslərin və onların həyata keçirilməsinin ayrıca strukturuna malik kolleksiyadır. Bu ayrıdır, çünki burada dəyərlər bir-bir deyil, "açar-dəyər" cütlüyündə saxlanılır. Əsas xəritə üsulları :- put(K düyməsi, V dəyəri) - Xəritəyə element əlavə etmək;
- get(Obyekt açarı) - açarla dəyəri axtarın;
- containKey(Obyekt açarı) — Xəritədə bu açarın mövcudluğunu yoxlayır;
- containValue(Obyekt dəyəri) - Xəritədə bu dəyərin mövcudluğunu yoxlayır;
- sil(Obyekt açarı) - dəyərin açarı ilə silinməsi.
- HashMap - dəyərləri təsadüfi qaydada saxlamaq üçün nəzərdə tutulmuşdur, lakin xəritə elementlərini tez bir zamanda axtarmağa imkan verir. Null açar sözündən istifadə edərək açarı təyin etməyə imkan verir , lakin bir dəfədən çox deyil, çünki eyni düymələri olan cütlər üst-üstə yazılır. Əsas şərt açarların unikallığıdır: dəyərlər təkrarlana bilər (bir neçə sıfır dəyər ola bilər).
- LinkedHashMap, dəyərləri əlavə olunduğu ardıcıllıqla saxlayan HashMap-ın analoqudur . Müvafiq olaraq, LinkedList kimi , onun başlığı var - ikiqat əlaqəli siyahının başı. Başlandıqda, o, özünə işarə edir.
LinkedHashMap həmçinin iterator istifadə edildikdə elementlərə necə daxil olacağını müəyyən edən accessOrder-ə malikdir . accessOrder yanlışdırsa , giriş elementlərin daxil edildiyi ardıcıllıqla həyata keçiriləcək. Əgər doğrudursa, elementlər son əldə edilmiş qaydada olacaq (sonuncu əldə edilmiş element sonunda yerləşdiriləcək).
- TreeMap elementləri əsas dəyərlərə görə çeşidləyən Xəritədir . TreeSet -ə bənzəyir , lakin əsas dəyərlərə əsaslanan cütlər üçün. TreeMap çeşidləmə qaydalarını təyin etmək üçün düymələr Müqayisəli interfeysi həyata keçirməlidir . Əks halda, Açar yönümlü Müqayisəçi ( TreeMap konstruktorunda göstərilən ), TreeSet olmalıdır - içərisində TreeMap obyekti ilə həyata keçirilir və əslində bütün sehrlər orada baş verir.
Qırmızı-qara ağaclardan istifadə edərək TreeMap-da çeşidləmə haqqında daha çox TreeMap-in xüsusiyyətləri haqqında məqalədə oxuya bilərsiniz .
- Hashtable HashMap- a bənzəyir , lakin nullların açar və ya dəyər kimi saxlanmasına icazə vermir . O, çox yivli nöqteyi-nəzərdən diqqətlə sinxronlaşdırılır, bu da öz növbəsində çox yivli nöqteyi-nəzərdən təhlükəsiz olması deməkdir. Ancaq bu tətbiq köhnəlmişdir və yavaşdır, buna görə də indi az-çox yeni layihələrdə Hashtable-ı görməyəcəksiniz .
8. ArrayList və LinkedList. Hansının istifadəsinə üstünlük verilir?
Bu sual, bəlkə də məlumat strukturlarında ən populyardır və özü ilə bəzi tələlər daşıyır. Cavab verməzdən əvvəl gəlin bu məlumat strukturları haqqında daha çox öyrənək. ArrayList List interfeysini həyata keçirir və lazım olduqda genişləndirilən daxili massivdə işləyir. Daxili massiv tamamilə doldurulduqda və yeni element daxil edilməli olduqda, ölçüsü (oldSize * 1.5) +1 olan yeni massiv yaradılır. Bundan sonra köhnə massivdəki bütün məlumatlar yeni + yeni elementə kopyalanır və köhnəsi zibil toplayıcı tərəfindən silinəcəkdir . Əlavə etmə metodu massivin sonuncu boş xanasına element əlavə edir. Yəni orada artıq 3 elementimiz varsa, o, növbəti elementi 4-cü xanaya əlavə edəcək. Əsas metodların icrasına keçək:- get(int index) - massivdəki elementi indekslə götürmək O(1) -də ən sürətlidir ;
- add(Object obj) - daxili massivdə yeni element üçün kifayət qədər yer varsa, o zaman normal daxiletmə ilə O(1) vaxt sərf olunacaq , çünki əlavə son xanaya yönəldilmişdir.
Əgər yeni massiv yaratmalı və içindəkiləri ona köçürməli olsaq, onda bizim vaxtımız O(n) massivindəki elementlərin sayı ilə düz mütənasib olacaqdır ;
- remove(int index) - elementi, məsələn, ortadan çıxararkən biz O(n/2) vaxtını alacağıq, çünki elementləri onun sağ tərəfinə bir xana geri köçürməli olacağıq. Müvafiq olaraq, siyahının əvvəlindən silinirsə, onda O(n), sonundan - O(1);
- add(int index, Object obj) - silməyə bənzər bir vəziyyət: ortasına əlavə edərkən, sağdakı bir xanadakı elementləri irəli aparmalı olacağıq, buna görə də vaxt O(n/2). Təbii ki, əvvəldən - O(n), sondan - O(1);
- set(int index, Object obj) - burada vəziyyət fərqlidir, çünki sadəcə istədiyiniz elementi tapmaq və qalanını köçürmədən onun üzərinə yazmaq lazımdır, ona görə də O(1).
- get(int index) - siyahının ortasında olan elementi axtararkən, istədiyiniz element tapılana qədər bütün elementləri sıra ilə axtarmağa başlayır. Məntiqi olaraq, axtarış O(n/2) götürməlidir , lakin LinkedList-in də quyruğu var, ona görə də axtarış hər iki tərəfdən eyni vaxtda aparılır. Müvafiq olaraq, vaxt O(n/4) -ə endirilir .
Əgər element siyahının əvvəlinə və ya sonuna yaxındırsa, onda vaxt O(1) olacaq ;
- əlavə et(Object obj) - yeni element əlavə edərkən, “quyruq” elementində əlavə edilmiş növbəti elementə keçid olacaq və yenisi bu əvvəlki elementə keçid alacaq və yeni “quyruq” olacaq. Müvafiq olaraq, vaxt O(1) olacaq ;
- remove(int index) - get(int index) metoduna bənzər məntiq . Siyahının ortasından elementi silmək üçün əvvəlcə onu tapmaq lazımdır. Bu, yenə O(n/4) dir , halbuki silinmənin özü əslində heç nə götürmür, çünki o, yalnız qonşu obyektlərin göstəricisini dəyişir (onlar bir-birinə istinad etməyə başlayırlar). Əgər element əvvəlində və ya sonundadırsa, onda yenidən - O(1) ;
- add(int index, Object obj) və set(int index, Object obj) - metodlar əldə etmək üçün eyni vaxt mürəkkəbliyinə malik olacaq(int index) , çünki çox vaxt elementin axtarışına sərf olunur. Buna görə də, siyahının ortası üçün - O(n/4) , başlanğıc üçün - O(1).
Əməliyyat | ArrayList | LinkedList |
---|---|---|
Index get (index) ilə alın | O(1) | Ortada O(n/4) |
Yeni element əlavə et (obj) |
O(1) Əgər massivi kopyalamaq lazımdırsa, onda - O(n) |
O(1) |
Elementi silin (int indeksi) |
Əvvəldən - O(n) Ortadan - O(n/2) Sondan - O(1) |
Ortada - O(n/4) sonunda və ya əvvəlində - O(n) |
Element əlavə et (int indeksi, Obyekt obyekti) |
Əvvələ qayıt - O(n) Ortaya - O(n/2) Sona qədər - O(1) |
Ortada - O(n/4) sonunda və ya əvvəlində - O(n) |
Element dəstini dəyişdirin (indeks, obj) | O(1) |
Ortada - O(n/4) sonunda və ya əvvəlində - O(n) |
- ən çox görülən əməliyyat elementin axtarışı, elementin üzərinə yazılmasıdırsa, ən yaxşı seçimdir;
- əməliyyat başlanğıc-ortada daxil etmə və silmədirsə, ən pis seçimdir, çünki elementlərin sağdakı yerdəyişmə əməliyyatları baş verəcəkdir.
- ən yaxşı seçim, əgər tez-tez əməliyyatımız başlanğıc-ortada daxil etmə və silmədirsə;
- ən ümumi əməliyyat axtarışdırsa, ən pis seçimdir.
9. HashMap-da elementlər necə saxlanılır?
HashMap kolleksiyası daxili massiv Node[] cədvəlini ehtiva edir , onun xanaları da buckets adlanır . Node ehtiva edir:- açar - açara keçid,
- dəyər - dəyərə istinad,
- hash - hash dəyəri,
- növbəti - növbəti Node üçün keçid .
- Açar null üçün yoxlanılır . Əgər null olarsa , onda açar cədvəl[0] xanasında saxlanılacaq , çünki null üçün hash kodu həmişə 0-dır.
- Açar null deyilsə , o zaman açar obyektin hashcode() metodu çağırılır və onun hash kodunu qaytaracaq. Bu hash kodu Node obyektinin saxlanacağı massiv xanasını müəyyən etmək üçün istifadə olunur.
- Sonra, bu heşkod heşkodu hesablayan daxili hash() metodunda yerləşdirilir , lakin cədvəl[] massivinin ölçüsü daxilində .
- Sonra, hash dəyərindən asılı olaraq, Node cədvəlin [] massivində xüsusi bir xanaya yerləşdirilir .
- Əgər cari Node elementini saxlamaq üçün istifadə edilən cədvəl[] xanası boş deyilsə, lakin artıq müəyyən elementə malikdirsə, onda Node elementləri sonuncu elementə çatana qədər növbəti dəyər üzərində təkrarlanır. Yəni, növbəti sahəsi null olan sahə .
Bu axtarış zamanı qorunan Node obyektinin açarı axtarılanların açarları ilə müqayisə edilir:
- uyğunluq tapılarsa, axtarış başa çatacaq və yeni Node uyğunluğun tapıldığı Düyün üzərinə yazacaq (yalnız onun dəyər sahəsi üzərinə yazılacaq );
- heç bir əsas uyğunluq tapılmadıqda, yeni Node bu siyahıda sonuncu olacaq və əvvəlkinin ona növbəti keçidi olacaq.
10. İteratoru izah edin
Yuxarıdakı Kolleksiya iyerarxiyasının xəritələşdirilməsi diaqramında Kolleksiya interfeysi bütün iyerarxiyanın başladığı yer idi, lakin praktikada bu, tam olaraq belə deyil. Kolleksiya , Iterator<E> interfeysini həyata keçirən obyekti qaytaran iterator() metodu ilə interfeysdən miras qalır . Iterator interfeysi belə görünür:
public interface Iterator <E>{
E next();
boolean hasNext();
void remove();
}
next() - bu metodu çağırmaqla növbəti elementi əldə edə bilərsiniz. hasNext() - növbəti elementin olub-olmadığını və kolleksiyanın sonuna çatılıb-çatılmadığını öyrənməyə imkan verir. Və hələ də elementlər olduqda hasNext() true qaytaracaq . Tipik olaraq, hasNext() növbəti() metodundan əvvəl çağırılır , çünki next() kolleksiyanın sonuna çatdıqda NoSuchElementException atacaq . remove() - Next() -ə sonuncu zənglə əldə edilmiş elementi silir . İteratorun məqsədi elementləri təkrarlamaqdır. Misal üçün:
Set<Integer> values = new TreeSet<>();
values.add(5);
values.add(3);
values.add(6);
values.add(8);
values.add(2);
values.add(4);
values.add(1);
values.add(7);
Iterator<Integer> iter = values.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
Əslində, hər bir döngə bir iteratordan istifadə edərək başlıq altında həyata keçirilir. Bu barədə daha ətraflı burada oxuya bilərsiniz . List öz iterator versiyasını təqdim edir, lakin daha soyuq və daha mürəkkəbdir - ListIterator . Bu interfeys İteratoru genişləndirir və əlavə üsullara malikdir:
- kolleksiyada əvvəlki element varsa, hasPrevious doğru, əks halda false qaytaracaq;
- əvvəlki cari elementi qaytarır və əvvəlkinə keçir; heç biri yoxdursa, onda NoSuchElementException atılır;
- add ötürülən obyekti next()- ə növbəti çağırışla qaytarılacaq elementdən əvvəl daxil edəcək ;
- set cari elementə ötürülən obyektə istinad təyin edir;
- nextIndex növbəti elementin indeksini qaytarır. Əgər belə bir şey yoxdursa, o zaman siyahının ölçüsü qaytarılır;
- əvvəlki İndeks əvvəlki elementin indeksini qaytarır. Əgər yoxdursa, onda -1 rəqəmi qaytarılır.
GO TO FULL VERSION