Avastage JavaScripti andmestruktuuride vÔimsus. See pÔhjalik juhend uurib sisseehitatud Map'e ja Set'e ning kohandatud lahenduste loomise strateegiaid, pakkudes globaalsetele arendajatele tÔhusat andmehaldust.
JavaScript'i andmestruktuurid: Map'ide, Set'ide ja kohandatud implementatsioonide valdamine globaalsetele arendajatele
Tarkvaraarenduse dĂŒnaamilises maailmas on andmestruktuuride valdamine esmatĂ€htis. Need moodustavad tĂ”husate algoritmide ja hĂ€sti organiseeritud koodi aluse, mĂ”jutades otseselt rakenduse jĂ”udlust ja skaleeritavust. Globaalsete arendajate jaoks on nende kontseptsioonide mĂ”istmine ĂŒlioluline, et ehitada robustseid rakendusi, mis teenindavad mitmekesist kasutajaskonda ja tulevad toime erinevate andmekoormustega. See pĂ”hjalik juhend sĂŒveneb JavaScripti vĂ”imsatesse sisseehitatud andmestruktuuridesse, Map'idesse ja Set'idesse, ning seejĂ€rel uurib kaalukaid pĂ”hjuseid ja meetodeid oma kohandatud andmestruktuuride loomiseks.
Navigeerime lÀbi praktiliste nÀidete, reaalsete kasutusjuhtude ja rakendatavate teadmiste, tagades, et igasuguse taustaga arendajad saavad neid tööriistu tÀielikult Àra kasutada. Olenemata sellest, kas töötate idufirmas Berliinis, suures ettevÔttes Tokyos vÔi vabakutselise projektiga kliendile São Paulos, on siin kÀsitletud pÔhimÔtted universaalselt rakendatavad.
Andmestruktuuride tÀhtsus JavaScriptis
Enne konkreetsetesse JavaScripti implementatsioonidesse sukeldumist kĂ€sitleme lĂŒhidalt, miks andmestruktuurid on nii fundamentaalse tĂ€htsusega. Andmestruktuurid on spetsialiseeritud vormingud andmete organiseerimiseks, töötlemiseks, hankimiseks ja salvestamiseks. Andmestruktuuri valik mĂ”jutab oluliselt operatsioonide, nagu lisamine, kustutamine, otsimine ja sortimine, tĂ”husust.
JavaScriptis, mis on tuntud oma paindlikkuse ja laialdase kasutuse poolest nii esiotsa, taustaprogrammi (Node.js) kui ka mobiiliarenduses, on tÔhus andmetöötlus kriitilise tÀhtsusega. Halvasti valitud andmestruktuurid vÔivad pÔhjustada:
- JÔudluse kitsaskohad: Aeglased laadimisajad, mittereageerivad kasutajaliidesed ja ebatÔhus serveripoolne töötlemine.
- Suurenenud mĂ€lukasutus: SĂŒsteemi ressursside tarbetu kasutamine, mis toob kaasa suuremad tegevuskulud ja potentsiaalsed kokkujooksmised.
- Koodi keerukus: Raskused koodi hooldamisel ja silumisel keerulise andmehalduse loogika tÔttu.
Kuigi JavaScript pakub vÔimsaid abstraktsioone, annab see arendajatele ka tööriistad kÔrgelt optimeeritud lahenduste loomiseks. Selle sisseehitatud struktuuride ja kohandatud struktuuride mustrite mÔistmine on vÔti vilunud globaalseks arendajaks saamisel.
JavaScripti sisseehitatud jÔujaamad: Map'id ja Set'id
Pikka aega toetusid JavaScripti arendajad andmekogude haldamisel peamiselt tavalistele JavaScripti objektidele (sarnased sĂ”nastike vĂ”i rĂ€sikaartidega) ja massiividele. Kuigi need on mitmekĂŒlgsed, olid neil oma piirangud. Map'ide ja Set'ide kasutuselevĂ”tt ECMAScript 2015-s (ES6) tĂ€iustas oluliselt JavaScripti andmehaldusvĂ”imalusi, pakkudes spetsialiseeritumaid ja sageli ka jĂ”udlusvĂ”imelisemaid lahendusi.
1. JavaScripti Map'id
Map on vĂ”ti-vÀÀrtus paaride kogum, kus vĂ”tmed vĂ”ivad olla mis tahes andmetĂŒĂŒpi, sealhulgas objektid, funktsioonid ja primitiivid. See on oluline erinevus traditsioonilistest JavaScripti objektidest, kus vĂ”tmed konverteeritakse kaudselt stringideks vĂ”i sĂŒmboliteks.
Map'ide peamised omadused:
- Mis tahes tĂŒĂŒpi vĂ”ti: Erinevalt tavalistest objektidest, kus vĂ”tmed on tavaliselt stringid vĂ”i sĂŒmbolid, vĂ”ivad Map'i vĂ”tmed olla mis tahes vÀÀrtusega (objektid, primitiivid jne). See vĂ”imaldab keerukamaid ja nĂŒansseeritumaid andmesuhteid.
- JÀrjestatud iteratsioon: Map'i elemente itereeritakse nende lisamise jÀrjekorras. See ennustatavus on paljude rakenduste jaoks hindamatu vÀÀrtusega.
- Size omadus: Map'idel on `size` omadus, mis tagastab otse elementide arvu, mis on tĂ”husam kui nende loendamiseks vĂ”tmete vĂ”i vÀÀrtuste ĂŒle itereerimine.
- JĂ”udlus: VĂ”ti-vÀÀrtus paaride sagedase lisamise ja kustutamise puhul pakuvad Map'id ĂŒldiselt paremat jĂ”udlust kui tavalised objektid, eriti suure hulga kirjete puhul.
Levinud Map'i operatsioonid:
Uurime olulisemaid meetodeid Map'idega töötamiseks:
- `new Map([iterable])`: Loob uue Map'i. Map'i initsialiseerimiseks vÔib anda valikulise itereeritava vÔti-vÀÀrtus paaride kogumi.
- `map.set(key, value)`: Lisab vÔi uuendab elementi mÀÀratud vÔtme ja vÀÀrtusega. Tagastab Map'i objekti.
- `map.get(key)`: Tagastab mÀÀratud vÔtmega seotud vÀÀrtuse vÔi `undefined`, kui vÔtit ei leita.
- `map.has(key)`: Tagastab tÔevÀÀrtuse, mis nÀitab, kas Map'is on olemas mÀÀratud vÔtmega element.
- `map.delete(key)`: Eemaldab Map'ist mÀÀratud vÔtmega elemendi. Tagastab `true`, kui element eemaldati edukalt, vastasel juhul `false`.
- `map.clear()`: Eemaldab Map'ist kÔik elemendid.
- `map.size`: Tagastab elementide arvu Map'is.
Itereerimine Map'idega:
Map'id on itereeritavad, mis tĂ€hendab, et nende sisu lĂ€bimiseks saate kasutada konstruktsioone nagu `for...of` tsĂŒklid ja laotussĂŒntaksit (`...`).
- `map.keys()`: Tagastab iteraatori vÔtmete jaoks.
- `map.values()`: Tagastab iteraatori vÀÀrtuste jaoks.
- `map.entries()`: Tagastab iteraatori vÔti-vÀÀrtus paaride jaoks (kujul `[key, value]` massiivid).
- `map.forEach((value, key, map) => {})`: KĂ€ivitab antud funktsiooni iga vĂ”ti-vÀÀrtus paari kohta ĂŒks kord.
Map'i praktilised kasutusjuhud:
Map'id on uskumatult mitmekĂŒlgsed. Siin on mĂ”ned nĂ€ited:
- VahemÀlu (caching): Salvestage sageli kasutatavaid andmeid (nt API vastused, arvutatud vÀÀrtused) koos vastavate vÔtmetega.
- Andmete seostamine objektidega: Kasutage objekte endid vÔtmetena, et seostada nende objektidega metaandmeid vÔi lisavÀÀrtusi.
- Otsingute implementeerimine: ID-de tÔhus kaardistamine kasutajaobjektide, tooteandmete vÔi konfiguratsiooniseadetega.
- Sageduse loendamine: Nimekirjas olevate elementide esinemissageduse loendamine, kus element on vÔti ja selle arv on vÀÀrtus.
NÀide: API vastuste vahemÀllu salvestamine (globaalne perspektiiv)
Kujutage ette, et ehitate globaalset e-kaubanduse platvormi. VÔite hankida tooteandmeid erinevatest piirkondlikest API-dest. Nende vastuste vahemÀllu salvestamine vÔib jÔudlust drastiliselt parandada. Map'idega on see lihtne:
const apiCache = new Map();
async function getProductDetails(productId, region) {
const cacheKey = `${productId}-${region}`;
if (apiCache.has(cacheKey)) {
console.log(`VahemÀlutabamus vÔtmele ${cacheKey}`);
return apiCache.get(cacheKey);
}
console.log(`VahemÀlust möödalÀinud vÔtmele ${cacheKey}. Hangin API-st...`);
// Simuleerime regionaalsest API-st hankimist
const response = await fetch(`https://api.example.com/${region}/products/${productId}`);
const productData = await response.json();
// Salvestame vahemÀllu edaspidiseks kasutamiseks
apiCache.set(cacheKey, productData);
return productData;
}
// NĂ€ide kasutamisest erinevates regioonides:
getProductDetails('XYZ789', 'us-east-1'); // Hangib ja salvestab vahemÀllu
getProductDetails('XYZ789', 'eu-west-2'); // Hangib ja salvestab eraldi vahemÀllu
getProductDetails('XYZ789', 'us-east-1'); // VahemÀlutabamus!
2. JavaScripti Set'id
Set on unikaalsete vÀÀrtuste kogum. See vĂ”imaldab salvestada eristuvaid elemente, kĂ€sitledes duplikaate automaatselt. Nagu Map'ide puhul, vĂ”ivad ka Set'i elemendid olla mis tahes andmetĂŒĂŒpi.
Set'ide peamised omadused:
- Unikaalsed vÀÀrtused: Set'i kÔige iseloomulikum omadus on see, et see salvestab ainult unikaalseid vÀÀrtusi. Kui proovite lisada vÀÀrtust, mis on juba olemas, siis seda ignoreeritakse.
- JÀrjestatud iteratsioon: Set'i elemente itereeritakse nende lisamise jÀrjekorras.
- Size omadus: Sarnaselt Map'idele on Set'idel `size` omadus elementide arvu saamiseks.
- JĂ”udlus: Elemendi olemasolu kontrollimine (`has`) ning elementide lisamine/kustutamine on Set'ides ĂŒldiselt vĂ€ga tĂ”husad operatsioonid, sageli keskmise ajakeerukusega O(1).
Levinud Set'i operatsioonid:
- `new Set([iterable])`: Loob uue Set'i. Set'i initsialiseerimiseks elementidega vÔib anda valikulise itereeritava kogumi.
- `set.add(value)`: Lisab Set'i uue elemendi. Tagastab Set'i objekti.
- `set.has(value)`: Tagastab tÔevÀÀrtuse, mis nÀitab, kas Set'is on olemas mÀÀratud vÀÀrtusega element.
- `set.delete(value)`: Eemaldab Set'ist mÀÀratud vÀÀrtusega elemendi. Tagastab `true`, kui element eemaldati edukalt, vastasel juhul `false`.
- `set.clear()`: Eemaldab Set'ist kÔik elemendid.
- `set.size`: Tagastab elementide arvu Set'is.
Itereerimine Set'idega:
Set'id on samuti itereeritavad:
- `set.keys()`: Tagastab iteraatori vÀÀrtuste jaoks (kuna Set'is on vÔtmed ja vÀÀrtused samad).
- `set.values()`: Tagastab iteraatori vÀÀrtuste jaoks.
- `set.entries()`: Tagastab iteraatori vÀÀrtuste jaoks, kujul `[value, value]`.
- `set.forEach((value, key, set) => {})`: KĂ€ivitab antud funktsiooni iga elemendi kohta ĂŒks kord.
Set'i praktilised kasutusjuhud:
- Duplikaatide eemaldamine: Kiire ja tÔhus viis massiivist unikaalsete elementide nimekirja saamiseks.
- Liikmelisuse testimine: VĂ€ga kiiresti kontrollimine, kas element on kogumis olemas.
- Unikaalsete sĂŒndmuste jĂ€lgimine: Tagamine, et konkreetne sĂŒndmus logitakse vĂ”i töödeldakse ainult ĂŒks kord.
- Hulgaoperatsioonid: Kogumitega ĂŒhendi-, ĂŒhisosa- ja vaheoperatsioonide teostamine.
NĂ€ide: unikaalsete kasutajate leidmine globaalsest sĂŒndmuste logist
Kujutage ette globaalset veebirakendust, mis jÀlgib kasutajate tegevust. Teil vÔivad olla logid erinevatest serveritest vÔi teenustest, mis vÔivad sisaldada sama kasutaja tegevuse kohta duplikaatkirjeid. Set on ideaalne kÔigi osalenud unikaalsete kasutajate leidmiseks:
const userActivityLogs = [
{ userId: 'user123', action: 'login', timestamp: '2023-10-27T10:00:00Z', region: 'Asia' },
{ userId: 'user456', action: 'view', timestamp: '2023-10-27T10:05:00Z', region: 'Europe' },
{ userId: 'user123', action: 'click', timestamp: '2023-10-27T10:06:00Z', region: 'Asia' },
{ userId: 'user789', action: 'login', timestamp: '2023-10-27T10:08:00Z', region: 'North America' },
{ userId: 'user456', action: 'logout', timestamp: '2023-10-27T10:10:00Z', region: 'Europe' },
{ userId: 'user123', action: 'view', timestamp: '2023-10-27T10:12:00Z', region: 'Asia' } // Duplikaat user123 tegevus
];
const uniqueUserIds = new Set();
userActivityLogs.forEach(log => {
uniqueUserIds.add(log.userId);
});
console.log('Unikaalsed kasutaja ID-d:', Array.from(uniqueUserIds)); // Kasutades Array.from, et konverteerida Set tagasi massiiviks kuvamiseks
// VĂ€ljund: Unikaalsed kasutaja ID-d: [ 'user123', 'user456', 'user789' ]
// Teine nÀide: duplikaatide eemaldamine toote ID-de nimekirjast
const productIds = ['A101', 'B202', 'A101', 'C303', 'B202', 'D404'];
const uniqueProductIds = new Set(productIds);
console.log('Unikaalsed toote ID-d:', [...uniqueProductIds]); // Kasutades laotussĂŒntaksit
// VĂ€ljund: Unikaalsed toote ID-d: [ 'A101', 'B202', 'C303', 'D404' ]
Kui sisseehitatud struktuuridest ei piisa: kohandatud andmestruktuurid
Kuigi Map'id ja Set'id on vĂ”imsad, on need ĂŒldotstarbelised tööriistad. Teatud stsenaariumides, eriti keerukate algoritmide, vĂ€ga spetsiifiliste andmenĂ”uete vĂ”i jĂ”udluskriitiliste rakenduste puhul, peate vĂ”ib-olla implementeerima oma kohandatud andmestruktuure. Siin muutub oluliseks algoritmide ja arvutusliku keerukuse sĂŒgavam mĂ”istmine.
Miks luua kohandatud andmestruktuure?
- JĂ”udluse optimeerimine: Struktuuri kohandamine konkreetse probleemi jaoks vĂ”ib anda olulist jĂ”udluse kasvu vĂ”rreldes ĂŒldiste lahendustega. NĂ€iteks vĂ”ib spetsialiseeritud puustruktuur olla teatud otsingupĂ€ringute jaoks kiirem kui Map.
- MĂ€lutĂ”husus: Kohandatud struktuure saab kujundada nii, et need kasutaksid mĂ€lu tĂ€psemalt, vĂ€ltides ĂŒldotstarbeliste struktuuridega seotud lisakulusid.
- Spetsiifiline funktsionaalsus: Unikaalsete kÀitumisviiside vÔi piirangute implementeerimine, mida sisseehitatud struktuurid ei toeta (nt prioriteedijÀrjekord konkreetsete jÀrjestusreeglitega, suunatud servadega graaf).
- Hariduslikud eesmÀrgid: Fundamentaalsete andmestruktuuride (nagu magasinid, jÀrjekorrad, ahelloendid, puud) toimimise mÔistmine neid nullist implementeerides.
- Algoritmide implementeerimine: Paljud arenenud algoritmid on tihedalt seotud spetsiifiliste andmestruktuuridega (nt Dijkstra algoritm kasutab sageli miinimum-prioriteediga jÀrjekorda).
Levinud kohandatud andmestruktuurid JavaScriptis implementeerimiseks:
1. Ahelloendid
Ahelloend on lineaarne andmestruktuur, kus elemente ei salvestata kĂŒlgnevates mĂ€lukohtades. Selle asemel sisaldab iga element (sĂ”lm) andmeid ja viidet (vĂ”i linki) jĂ€rgmisele sĂ”lmele jĂ€rjestuses.
- TĂŒĂŒbid: Ăhesuunalised ahelloendid, Kahesuunalised ahelloendid, Ringahelloendid.
- Kasutusjuhud: Magasini ja jĂ€rjekorra implementeerimine, dĂŒnaamilise mĂ€lu haldamine, tagasivĂ”tmise/uuestitegemise funktsionaalsus.
- Keerukus: Lisamine/kustutamine alguses/lÔpus vÔib olla O(1), kuid otsimine on O(n).
Implementatsiooni visand: Ăhesuunaline ahelloend
Kasutame lihtsat klassipÔhist lÀhenemist, mis on JavaScriptis levinud.
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
// SÔlme lisamine lÔppu
add(data) {
const newNode = new Node(data);
if (!this.head) {
this.head = newNode;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
this.size++;
}
// SÔlme eemaldamine vÀÀrtuse jÀrgi
remove(data) {
if (!this.head) return false;
if (this.head.data === data) {
this.head = this.head.next;
this.size--;
return true;
}
let current = this.head;
while (current.next) {
if (current.next.data === data) {
current.next = current.next.next;
this.size--;
return true;
}
current = current.next;
}
return false;
}
// SÔlme leidmine vÀÀrtuse jÀrgi
find(data) {
let current = this.head;
while (current) {
if (current.data === data) {
return current;
}
current = current.next;
}
return null;
}
// Nimekirja printimine
print() {
let current = this.head;
let list = '';
while (current) {
list += current.data + ' -> ';
current = current.next;
}
console.log(list + 'null');
}
}
// Kasutus:
const myList = new LinkedList();
myList.add('Apple');
myList.add('Banana');
myList.add('Cherry');
myList.print(); // Apple -> Banana -> Cherry -> null
myList.remove('Banana');
myList.print(); // Apple -> Cherry -> null
console.log(myList.find('Apple')); // Node { data: 'Apple', next: Node { data: 'Cherry', next: null } }
console.log('Suurus:', myList.size); // Suurus: 2
2. Magasinid (Stacks)
Magasin on lineaarne andmestruktuur, mis jÀrgib pÔhimÔtet "viimasena sisse, esimesena vÀlja" (LIFO). MÔelge taldrikute virnale: lisate uue taldriku virna otsa ja eemaldate taldriku virna otsast.
- Operatsioonid: `push` (lisamine tippu), `pop` (eemaldamine tipust), `peek` (tipuelemendi vaatamine), `isEmpty`.
- Kasutusjuhud: Funktsioonide vÀljakutsete magasinid, avaldiste hindamine, tagasivÔtmisalgoritmid (backtracking).
- Keerukus: KÔik peamised operatsioonid on tavaliselt O(1).
Implementatsiooni visand: Magasin massiivi abil
JavaScripti massiiviga saab hÔlpsasti magasini jÀljendada.
class Stack {
constructor() {
this.items = [];
}
// Elemendi lisamine tippu
push(element) {
this.items.push(element);
}
// Tipuelemendi eemaldamine ja tagastamine
pop() {
if (this.isEmpty()) {
return "Underflow"; // VÔi vea viskamine
}
return this.items.pop();
}
// Tipuelemendi vaatamine ilma eemaldamata
peek() {
if (this.isEmpty()) {
return "Magasinis pole elemente";
}
return this.items[this.items.length - 1];
}
// Magasini tĂŒhjuse kontrollimine
isEmpty() {
return this.items.length === 0;
}
// Suuruse saamine
size() {
return this.items.length;
}
// Magasini printimine (tipust alla)
print() {
let str = "";
for (let i = this.items.length - 1; i >= 0; i--) {
str += this.items[i] + " ";
}
console.log(str.trim());
}
}
// Kasutus:
const myStack = new Stack();
myStack.push(10);
myStack.push(20);
myStack.push(30);
myStack.print(); // 30 20 10
console.log('Tipp:', myStack.peek()); // Tipp: 30
console.log('Pop:', myStack.pop()); // Pop: 30
myStack.print(); // 20 10
console.log('On tĂŒhi:', myStack.isEmpty()); // On tĂŒhi: false
3. JĂ€rjekorrad (Queues)
JÀrjekord on lineaarne andmestruktuur, mis jÀrgib pÔhimÔtet "esimesena sisse, esimesena vÀlja" (FIFO). Kujutage ette piletikassas ootavate inimeste jÀrjekorda: esimene inimene jÀrjekorras on esimene, keda teenindatakse.
- Operatsioonid: `enqueue` (lisamine lÔppu), `dequeue` (eemaldamine algusest), `front` (alguselemendi vaatamine), `isEmpty`.
- Kasutusjuhud: Ălesannete ajastamine, pĂ€ringute haldamine (nt prindijĂ€rjekorrad, veebiserveri pĂ€ringute jĂ€rjekorrad), laiutiotsing (BFS) graafides.
- Keerukus: Tavalise massiivi puhul vĂ”ib `dequeue` olla O(n) ĂŒmberindekseerimise tĂ”ttu. Optimeeritum implementatsioon (nt ahelloendi vĂ”i kahe magasini abil) saavutab O(1).
Implementatsiooni visand: JÀrjekord massiivi abil (jÔudluse kaalutlusega)
Kuigi `shift()` massiivil on O(n), on see kÔige otsekohesem viis pÔhinÀite jaoks. Tootmiskeskkonnas kaaluge ahelloendi vÔi tÀiustatud massiivipÔhise jÀrjekorra kasutamist.
class Queue {
constructor() {
this.items = [];
}
// Elemendi lisamine lÔppu
enqueue(element) {
this.items.push(element);
}
// Alguselemendi eemaldamine ja tagastamine
dequeue() {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.shift(); // O(n) operatsioon tavalistes massiivides
}
// Alguselemendi vaatamine ilma eemaldamata
front() {
if (this.isEmpty()) {
return "JĂ€rjekorras pole elemente";
}
return this.items[0];
}
// JĂ€rjekorra tĂŒhjuse kontrollimine
isEmpty() {
return this.items.length === 0;
}
// Suuruse saamine
size() {
return this.items.length;
}
// JÀrjekorra printimine (algusest lÔppu)
print() {
let str = "";
for (let i = 0; i < this.items.length; i++) {
str += this.items[i] + " ";
}
console.log(str.trim());
}
}
// Kasutus:
const myQueue = new Queue();
myQueue.enqueue('A');
myQueue.enqueue('B');
myQueue.enqueue('C');
myQueue.print(); // A B C
console.log('Esimene:', myQueue.front()); // Esimene: A
console.log('Dequeue:', myQueue.dequeue()); // Dequeue: A
myQueue.print(); // B C
console.log('On tĂŒhi:', myQueue.isEmpty()); // On tĂŒhi: false
4. Puud (Binaarsed otsingupuud - BST)
Puud on hierarhilised andmestruktuurid. Binaarne otsingupuu (BST) on puu tĂŒĂŒp, kus igal sĂ”lmel on maksimaalselt kaks last, mida nimetatakse vasakuks ja paremaks lapseks. Iga antud sĂ”lme puhul on kĂ”ik vÀÀrtused selle vasakus alampuus vĂ€iksemad kui sĂ”lme vÀÀrtus ja kĂ”ik vÀÀrtused selle paremas alampuus on suuremad.
- Operatsioonid: Lisamine, kustutamine, otsimine, lÀbimine (in-order, pre-order, post-order).
- Kasutusjuhud: TĂ”hus otsimine ja sortimine (tasakaalustatud puude puhul sageli parem kui O(n)), sĂŒmbolitabelite implementeerimine, andmebaaside indekseerimine.
- Keerukus: Tasakaalustatud BST puhul on otsimine, lisamine ja kustutamine O(log n). Viltuse puu puhul vÔivad need halveneda kuni O(n).
Implementatsiooni visand: Binaarne otsingupuu
See implementatsioon keskendub pÔhilisele lisamisele ja otsimisele.
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
// VÀÀrtuse lisamine BST-sse
insert(value) {
const newNode = new TreeNode(value);
if (!this.root) {
this.root = newNode;
return this;
}
let current = this.root;
while (true) {
if (value === current.value) return undefined; // VÔi kÀsitle duplikaate vastavalt vajadusele
if (value < current.value) {
if (!current.left) {
current.left = newNode;
return this;
}
current = current.left;
} else {
if (!current.right) {
current.right = newNode;
return this;
}
current = current.right;
}
}
}
// VÀÀrtuse otsimine BST-st
search(value) {
if (!this.root) return null;
let current = this.root;
while (current) {
if (value === current.value) return current;
if (value < current.value) {
current = current.left;
} else {
current = current.right;
}
}
return null; // Ei leitud
}
// In-order lÀbimine (tagastab sorteeritud nimekirja)
inOrderTraversal(node = this.root, result = []) {
if (node) {
this.inOrderTraversal(node.left, result);
result.push(node.value);
this.inOrderTraversal(node.right, result);
}
return result;
}
}
// Kasutus:
const bst = new BinarySearchTree();
bst.insert(10);
bst.insert(5);
bst.insert(15);
bst.insert(2);
bst.insert(7);
bst.insert(12);
bst.insert(18);
console.log('In-order lÀbimine:', bst.inOrderTraversal()); // [ 2, 5, 7, 10, 12, 15, 18 ]
console.log('Otsime 7:', bst.search(7)); // TreeNode { value: 7, left: null, right: null }
console.log('Otsime 100:', bst.search(100)); // null
5. Graafid
Graafid on mitmekĂŒlgne andmestruktuur, mis esindab objektide (tipud vĂ”i sĂ”lmed) hulka, kus iga tipupaar vĂ”ib olla ĂŒhendatud seosega (serv). Neid kasutatakse vĂ”rgustike modelleerimiseks.
- TĂŒĂŒbid: Suunatud vs. suunamata, Kaalutud vs. kaalumata.
- Esitusviisid: KĂŒlgnevusloend (kĂ”ige levinum JS-is), KĂŒlgnevusmaatriks.
- Operatsioonid: Tippude/servade lisamine/eemaldamine, lĂ€bimine (DFS, BFS), lĂŒhima tee leidmine.
- Kasutusjuhud: SotsiaalvĂ”rgustikud, kaardistamis-/navigatsioonisĂŒsteemid, soovitussĂŒsteemid, vĂ”rgutopoloogia.
- Keerukus: SÔltub suuresti esitusviisist ja operatsioonist.
Implementatsiooni visand: Graaf kĂŒlgnevusloendiga
KĂŒlgnevusloend kasutab Map'i (vĂ”i tavalist objekti), kus vĂ”tmed on tipud ja vÀÀrtused on nende kĂŒlgnevate tippude massiivid.
class Graph {
constructor() {
this.adjacencyList = new Map(); // Kasutame Map'i paremaks vÔtmete haldamiseks
}
// Tipu lisamine
addVertex(vertex) {
if (!this.adjacencyList.has(vertex)) {
this.adjacencyList.set(vertex, []);
}
}
// Serva lisamine (suunamata graafi jaoks)
addEdge(vertex1, vertex2) {
if (!this.adjacencyList.has(vertex1) || !this.adjacencyList.has(vertex2)) {
throw new Error("Ăks vĂ”i mĂ”lemad tipud puuduvad.");
}
this.adjacencyList.get(vertex1).push(vertex2);
this.adjacencyList.get(vertex2).push(vertex1); // Suunamata graafi jaoks
}
// Serva eemaldamine
removeEdge(vertex1, vertex2) {
if (!this.adjacencyList.has(vertex1) || !this.adjacencyList.has(vertex2)) {
return false;
}
this.adjacencyList.set(vertex1, this.adjacencyList.get(vertex1).filter(v => v !== vertex2));
this.adjacencyList.set(vertex2, this.adjacencyList.get(vertex2).filter(v => v !== vertex1));
return true;
}
// Tipu ja kÔigi selle servade eemaldamine
removeVertex(vertex) {
if (!this.adjacencyList.has(vertex)) {
return false;
}
while (this.adjacencyList.get(vertex).length) {
const adjacentVertex = this.adjacencyList.get(vertex).pop();
this.removeEdge(vertex, adjacentVertex);
}
this.adjacencyList.delete(vertex);
return true;
}
// Baastase sĂŒgavutiotsing (DFS) lĂ€bimine
dfs(startVertex, visited = new Set(), result = []) {
if (!this.adjacencyList.has(startVertex)) return null;
visited.add(startVertex);
result.push(startVertex);
this.adjacencyList.get(startVertex).forEach(neighbor => {
if (!visited.has(neighbor)) {
this.dfs(neighbor, visited, result);
}
});
return result;
}
}
// Kasutus (nt globaalsete linnade vaheliste lennumarsruutide esitamine):
const flightNetwork = new Graph();
flightNetwork.addVertex('New York');
flightNetwork.addVertex('London');
flightNetwork.addVertex('Tokyo');
flightNetwork.addVertex('Sydney');
flightNetwork.addVertex('Rio de Janeiro');
flightNetwork.addEdge('New York', 'London');
flightNetwork.addEdge('New York', 'Tokyo');
flightNetwork.addEdge('London', 'Tokyo');
flightNetwork.addEdge('London', 'Rio de Janeiro');
flightNetwork.addEdge('Tokyo', 'Sydney');
console.log('LennuvÔrgustiku DFS New Yorgist:', flightNetwork.dfs('New York'));
// NÀidisvÀljund: [ 'New York', 'London', 'Tokyo', 'Sydney', 'Rio de Janeiro' ] (jÀrjekord vÔib Set'i iteratsioonist sÔltuvalt varieeruda)
// flightNetwork.removeEdge('New York', 'London');
// flightNetwork.removeVertex('Tokyo');
Ăige lĂ€henemise valimine
Otsustades, kas kasutada sisseehitatud Map'i/Set'i vÔi implementeerida kohandatud struktuur, kaaluge jÀrgmist:
- Probleemi keerukus: Lihtsate kogumite ja otsingute jaoks on Map'id ja Set'id tavaliselt piisavad ja sageli jÔudlusvÔimelisemad tÀnu natiivsetele optimeerimistele.
- JÔudlusvajadused: Kui teie rakendus nÔuab teatud operatsioonide jaoks ÀÀrmist jÔudlust (nt konstantse ajaga lisamine ja kustutamine, logaritmiline otsing), vÔib olla vajalik kohandatud struktuur.
- ĂppimiskĂ”ver: Kohandatud struktuuride implementeerimine nĂ”uab head arusaama algoritmidest ja andmestruktuuride pĂ”himĂ”tetest. Enamiku tavaliste ĂŒlesannete jaoks on sisseehitatud funktsioonide kasutamine produktiivsem.
- Hooldatavus: HÀsti dokumenteeritud ja testitud kohandatud struktuurid vÔivad olla hooldatavad, kuid keerulised struktuurid vÔivad lisada mÀrkimisvÀÀrset hoolduskoormust.
Globaalse arenduse kaalutlused
Globaalsel areenil töötavate arendajatena on mitu andmestruktuuridega seotud tegurit, mida tasub tÀhele panna:
- Skaleeritavus: Kuidas kĂ€itub teie valitud andmestruktuur andmemahu eksponentsiaalsel kasvamisel? See on ĂŒlioluline rakenduste jaoks, mis teenindavad miljoneid kasutajaid ĂŒle maailma. Sisseehitatud struktuurid nagu Map'id ja Set'id on ĂŒldiselt hĂ€sti optimeeritud skaleeritavuse jaoks, kuid kohandatud struktuurid tuleb sellega arvestades kujundada.
- Rahvusvahelistamine (i18n) ja lokaliseerimine (l10n): Andmed vÔivad pÀrineda erinevast keelelisest ja kultuurilisest taustast. MÔelge, kuidas teie andmestruktuurid kÀsitlevad erinevaid mÀrgistikke, sortimisreegleid ja andmevorminguid. NÀiteks kasutajanimede salvestamisel vÔib Map'ide kasutamine objektidega vÔtmetena olla robustsem kui lihtsate string-vÔtmete kasutamine.
- Ajavööndid ja kuupÀeva/kellaaja kÀsitlemine: Aja-tundlike andmete salvestamine ja pÀrimine erinevates ajavööndites nÔuab hoolikat kaalumist. Kuigi see pole rangelt andmestruktuuri probleem, sÔltub kuupÀevaobjektide tÔhus hankimine ja manipuleerimine sageli sellest, kuidas neid salvestatakse (nt Map'ides, mis on indekseeritud ajatemplite vÔi UTC vÀÀrtuste jÀrgi).
- JÔudlus erinevates piirkondades: VÔrgu latentsus ja serverite asukohad vÔivad mÔjutada tajutavat jÔudlust. TÔhus andmete hankimine ja töötlemine serveris (kasutades sobivaid struktuure) ja kliendi poolel vÔib neid probleeme leevendada.
- Meeskonnatöö: Mitmekesistes, hajutatud meeskondades töötades on selge dokumentatsioon ja ĂŒhine arusaam kasutatavatest andmestruktuuridest elutĂ€htsad. Standardsete struktuuride nagu Map'id ja Set'id implementeerimine soodustab lihtsamat sisseelamist ja koostööd.
KokkuvÔte
JavaScripti Map'id ja Set'id pakuvad vĂ”imsaid, tĂ”husaid ja elegantseid lahendusi paljudele levinud andmehaldusĂŒlesannetele. Need pakuvad paremaid vĂ”imalusi kui vanemad meetodid ja on iga kaasaegse JavaScripti arendaja jaoks olulised tööriistad.
Siiski ulatub andmestruktuuride maailm kaugemale nendest sisseehitatud tĂŒĂŒpidest. Keeruliste probleemide, jĂ”udluse kitsaskohtade vĂ”i spetsialiseeritud nĂ”uete korral on kohandatud andmestruktuuride, nagu ahelloendid, magasinid, jĂ€rjekorrad, puud ja graafid, implementeerimine rahuldust pakkuv ja sageli vajalik ettevĂ”tmine. See sĂŒvendab teie arusaama arvutuslikust tĂ”hususest ja probleemide lahendamisest.
Globaalsete arendajatena annab nende tööriistade omaksvÔtmine ja nende mÔju mÔistmine skaleeritavusele, jÔudlusele ja rahvusvahelistamisele teile vÔimekuse ehitada keerukaid, robustseid ja suure jÔudlusega rakendusi, mis suudavad maailmaareenil edu saavutada. JÀtkake avastamist, implementeerimist ja optimeerimist!