Ανίχνευση κυκλικών λιστών αναπαραγωγής σε JavaScript
Η εύρεση κύκλων ή επαναλήψεων είναι ένα κοινό πρόβλημα κατά την απάντηση σε ερωτήσεις κωδικοποίησης συνέντευξης, ιδιαίτερα σε αυτές που απαιτούν δομές δεδομένων όπως συνδεδεμένες λίστες. Αυτό το ζήτημα εμφανίζεται συνήθως σε λίστες αναπαραγωγής, όπου τα τραγούδια θα μπορούσαν να συνδέονται μεταξύ τους σε μια αλυσίδα αναφορών. Μια λίστα αναπαραγωγής λέγεται ότι είναι επαναλαμβανόμενη εάν ένα τραγούδι αναφέρεται σε προηγούμενο τραγούδι.
Ο στόχος αυτής της άσκησης κωδικοποίησης JavaScript είναι να γράψει μια συνάρτηση που καθορίζει εάν κάποια τραγούδια σε μια λίστα αναπαραγωγής επαναλαμβάνονται. Αυτό εξετάζει κάθε τραγούδι ένα προς ένα και βλέπει αν υπάρχει αναφορά που επιστρέφει σε προηγούμενο τραγούδι. Ακόμη και έμπειροι προγραμματιστές μπορεί να σκοντάψουν στις λεπτές λεπτομέρειες των αναφορών αντικειμένων και του ελέγχου βρόχου ενώ προσπαθούν να λύσουν αυτό το φαινομενικά απλό πρόβλημα στο JavaScript.
Συχνά, το πρόβλημα πηγάζει από τον τρόπο που εκφράζεται η λογική της επανάληψης, ιδιαίτερα από τον τρόπο χειρισμού των αναφορών μεταξύ αντικειμένων. Σε αυτήν την περίπτωση, η λύση εξαρτάται από την ικανότητά σας να κατανοήσετε πώς η JavaScript διαχειρίζεται τις αναφορές αντικειμένων μέσα σε βρόχους. Θα επικεντρωθούμε στον τρόπο κατάλληλης εκ νέου ανάθεσης και παρακολούθησης αυτών των παραπομπών σε μια λίστα αναπαραγωγής καθώς εξετάζουμε τη λύση.
Θα αναλύσουμε το ζήτημα λεπτομερώς, θα εξετάσουμε τις ελλείψεις της υπάρχουσας λύσης και θα προσφέρουμε μια εφαρμόσιμη λύση σε αυτό το επαναλαμβανόμενο εμπόδιο της λίστας αναπαραγωγής στη συζήτηση που ακολουθεί. Με αυτήν την επιδιόρθωση, η συνάρτηση θα μπορεί να αναγνωρίζει με ακρίβεια τις κυκλικές αναφορές σε μια λίστα αναπαραγωγής και να παράγει το επιδιωκόμενο αποτέλεσμα.
Εντολή | Παράδειγμα χρήσης |
---|---|
Set() | Το αντικείμενο JavaScript Set() χρησιμοποιείται για την αποθήκευση μοναδικών δεδομένων. Για να βοηθήσει στην αναγνώριση των κύκλων playlist, χρησιμοποιείται στο παράδειγμα για την παρακολούθηση τραγουδιών που προβάλλονται, διασφαλίζοντας ότι δεν θα ξαναπαιχτεί κανένα τραγούδι. |
has() | Το αντικείμενο Set() έχει τη συνάρτηση has(). Ελέγχει εάν ένα συγκεκριμένο στοιχείο υπάρχει στο σύνολο. Εδώ, ελέγχει εάν ένα τραγούδι έχει ήδη ακουστεί, υποδεικνύοντας ότι η λίστα αναπαραγωγής επαναλαμβάνεται. |
add() | Το αντικείμενο Set() έχει τη συνάρτηση has(). Ελέγχει εάν ένα δεδομένο στοιχείο υπάρχει στο σύνολο. Εδώ, ελέγχει εάν ένα τραγούδι έχει ήδη ακουστεί, υποδεικνύοντας ότι η λίστα αναπαραγωγής επαναλαμβάνεται. |
two-pointer technique | Αυτή η μέθοδος, η οποία μερικές φορές αναφέρεται ως αλγόριθμος ανίχνευσης κύκλου Floyd-Warshall, πλοηγείται στη λίστα αναπαραγωγής χρησιμοποιώντας δύο δείκτες: αργό και γρήγορο. Για την αποτελεσματική ανίχνευση βρόχων, ο αργός δείκτης κινείται ένα βήμα ενώ ο γρήγορος δείκτης δύο βήματα. |
nextSong | Η κλάση Song έχει μια μοναδική ιδιότητα που ονομάζεται nextSong και αναφέρεται στο τραγούδι που ακολουθεί στη λίστα αναπαραγωγής. Επιτρέπει τη μίμηση μιας δομής συνδεδεμένης λίστας στην οποία κάθε τραγούδι παραπέμπει διαδοχικά σε κάθε άλλο τραγούδι. |
describe() | Η συνάρτηση describe() του πλαισίου δοκιμών Mocha χρησιμοποιείται για την οργάνωση σχετικών δοκιμών μονάδων. Χωρίζει τα τεστ σε λογικές κατηγορίες, όπως λίστες αναπαραγωγής που επαναλαμβάνονται και σε αυτές που δεν επαναλαμβάνονται. |
it() | Στο Mocha, ένας ορισμός δοκιμαστικής περίπτωσης ονομάζεται it(). Υποδεικνύει μια συγκεκριμένη περίπτωση που πρέπει να δοκιμαστεί, για να βεβαιωθείτε ότι η λειτουργία αναγνωρίζει κατάλληλα μια επαναλαμβανόμενη λίστα αναπαραγωγής. |
assert.strictEqual() | Αυτή η μέθοδος προέρχεται από τη λειτουργική μονάδα επιβεβαίωσης στο Node.js. Σε αυτήν την περίπτωση, επαληθεύει το προβλεπόμενο αποτέλεσμα της λειτουργίας επανάληψης της λίστας αναπαραγωγής προσδιορίζοντας εάν δύο τιμές είναι αυστηρά ίσες. |
Κατανόηση της ανίχνευσης κύκλου λίστας αναπαραγωγής σε JavaScript
Το πρώτο σενάριο που προσφέρεται χρησιμοποιεί μια προσέγγιση συνδεδεμένης λίστας για τον εντοπισμό τραγουδιών που επαναλαμβάνονται σε μια λίστα αναπαραγωγής θεωρώντας κάθε τραγούδι ως κόμβο. Η δομή κλάσης της JavaScript χρησιμοποιείται για την κατασκευή α Τραγούδι αντικείμενο που μιμείται τη ροή μιας λίστας αναπαραγωγής από κομμάτι σε κομμάτι, αποθηκεύοντας το όνομα του τραγουδιού και μια αναφορά στο επόμενο τραγούδι. Το κύριο συστατικό της λύσης παρακολουθεί μουσική που έχετε συναντήσει στο παρελθόν χρησιμοποιώντας α Σειρά. Χρησιμοποιούμε έναν βρόχο while για να επαναλάβουμε τα τραγούδια, ελέγχοντας αν το τρέχον τραγούδι έχει ακουστεί στο παρελθόν. Εάν ναι, υποδεικνύουμε ότι η λίστα αναπαραγωγής επαναλαμβάνεται επιστρέφοντας true.
Ο αλγόριθμος ανίχνευσης κύκλου του Floyd, που συνήθως αναφέρεται ως τεχνική των δύο σημείων, χρησιμοποιείται με τον δεύτερο τρόπο. Χρησιμοποιώντας αυτήν τη μέθοδο, δύο δείκτες μετακινούνται στη λίστα αναπαραγωγής με ξεχωριστές ταχύτητες: ο ένας παραλείπει δύο τραγούδια και προχωρά ένα τραγούδι κάθε φορά. Αυτοί οι δείκτες θα συναντηθούν τελικά εάν υπάρχει ένας κύκλος, υποδεικνύοντας ότι η λίστα αναπαραγωγής επαναλαμβάνεται. Επειδή δεν απαιτείται η αποθήκευση των τραγουδιών που εμφανίζονται, αυτή η μέθοδος είναι πιο αποδοτική από άποψη χώρου και επομένως είναι καλύτερη επιλογή για μεγαλύτερες λίστες αναπαραγωγής.
Αυτές οι λύσεις δείχνουν επίσης πώς να δημιουργείτε συνδεδεμένες λίστες σε JavaScript επειδή το επόμενο Τραγούδι συνδέσεις ιδιοκτησίας το καθένα Τραγούδι αντίρρηση σε άλλον. Η ανίχνευση κύκλου στο πρώτο σενάριο εκμεταλλεύεται μια δομή συνόλου. Επειδή τα σετ εξασφαλίζουν μοναδικότητα, μπορούμε να προσδιορίσουμε αμέσως αν ένα τραγούδι έχει ήδη παιχτεί μόλις προστεθεί στο σετ. Αυτό κάνει τα σετ ιδιαίτερα χρήσιμα. Αυτό μας βοηθά να αναγνωρίσουμε πότε ξεκινά ένας κύκλος και μας εμποδίζει να παγιδευτούμε σε έναν ατελείωτο βρόχο.
Τέλος, οι δοκιμές μονάδας που περιλαμβάνονται και για τις δύο στρατηγικές εγγυώνται ότι η λύση είναι ακριβής σε διάφορες ρυθμίσεις. Για να ελέγξουμε τον κώδικά μας, χρησιμοποιήσαμε το πλαίσιο δοκιμών Mocha. Το Node.js διεκδικώ Η μονάδα χρησιμοποιείται για να επιβεβαιώσει ότι οι έξοδοι είναι οι αναμενόμενες και της Mocha περιγράφω και το Οι συναρτήσεις χρησιμοποιούνται για τη λογική δομή των δοκιμών. Οι δοκιμές μονάδων διαδραματίζουν κρίσιμο ρόλο στη διαδικασία ανάπτυξης, καθώς επικυρώνουν ότι η λειτουργία λειτουργεί όπως αναμένεται τόσο για επαναλαμβανόμενες όσο και για μη επαναλαμβανόμενες λίστες αναπαραγωγής, παρέχοντας βεβαιότητα για την ανθεκτικότητα της λύσης.
Ανίχνευση επαναλαμβανόμενων τραγουδιών σε λίστα αναπαραγωγής με JavaScript
Αντικειμενοστραφής προγραμματισμός σε JavaScript με βρόχους while
class Song {
constructor(name) {
this.name = name;
this.nextSong = null;
}
/
* @return {boolean} true if the playlist is repeating, false if not.
*/
isRepeatingPlaylist() {
let seenSongs = new Set();
let current = this;
while (current) {
if (seenSongs.has(current)) {
return true; // Playlist is repeating
}
seenSongs.add(current);
current = current.nextSong;
}
return false; // Playlist is not repeating
}
}
// Testing the solution
let first = new Song("Hello");
let second = new Song("Eye of the Tiger");
let third = new Song("Third");
first.nextSong = second;
second.nextSong = third;
third.nextSong = first; // Creates a loop
console.log(first.isRepeatingPlaylist()); // true
Εναλλακτική προσέγγιση: Χρήση δύο δεικτών για ανίχνευση κύκλου
Ανίχνευση κύκλου συνδεδεμένης λίστας με τον αλγόριθμο Floyd-Warshall
class Song {
constructor(name) {
this.name = name;
this.nextSong = null;
}
/
* @return {boolean} true if the playlist is repeating, false if not.
*/
isRepeatingPlaylist() {
let slow = this;
let fast = this;
while (fast !== null && fast.nextSong !== null) {
slow = slow.nextSong; // move slow pointer by 1 step
fast = fast.nextSong.nextSong; // move fast pointer by 2 steps
if (slow === fast) {
return true; // Loop detected
}
}
return false; // No loop
}
}
// Testing the solution
let first = new Song("Hello");
let second = new Song("Eye of the Tiger");
let third = new Song("Third");
first.nextSong = second;
second.nextSong = third;
third.nextSong = first; // Creates a loop
console.log(first.isRepeatingPlaylist()); // true
Δοκιμή μονάδας για ανίχνευση βρόχου λίστας αναπαραγωγής
Δοκιμή της συνάρτησης isRepeatingPlaylist με το Node.js και το Mocha
const assert = require('assert');
describe('isRepeatingPlaylist', function () {
it('should return true for a repeating playlist', function () {
let first = new Song('Song A');
let second = new Song('Song B');
let third = new Song('Song C');
first.nextSong = second;
second.nextSong = third;
third.nextSong = first; // Creates a loop
assert.strictEqual(first.isRepeatingPlaylist(), true);
});
it('should return false for a non-repeating playlist', function () {
let first = new Song('Song A');
let second = new Song('Song B');
let third = new Song('Song C');
first.nextSong = second;
second.nextSong = third;
assert.strictEqual(first.isRepeatingPlaylist(), false);
});
});
Προηγμένες τεχνικές ανίχνευσης βρόχου λίστας αναπαραγωγής σε JavaScript
Κατανόηση της θεμελιώδους δομής ενός playlist από την άποψη του συνδεδεμένες λίστες είναι ένα ενδιαφέρον μέρος της ανίχνευσης βρόχου playlist. Κάθε τραγούδι σε μια μη επαναλαμβανόμενη λίστα αναπαραγωγής συνδέεται με το προηγούμενο, έως ότου δεν υπάρχουν άλλες αναφορές σε αυτό το τραγούδι και η λίστα τελειώνει. Ξεκινάμε έναν κύκλο όταν ένα τραγούδι παραπέμπει σε προηγούμενο, επομένως κατά μία έννοια η λίστα είναι "άπειρη". Η εύρεση αυτού του είδους των κύκλων είναι σημαντική όχι μόνο για λίστες αναπαραγωγής αλλά και για αλγόριθμους κατανομής μνήμης και δρομολόγησης.
Αυτοί οι κύκλοι μπορούν να ανιχνευθούν αποτελεσματικά σε JavaScript χρησιμοποιώντας τεχνικές και δομές δείκτη όπως η Σειρά. Επειδή διασφαλίζει τη μοναδικότητα και αποτρέπει την επανεξέταση των τραγουδιών χωρίς να ξεκινήσει ένας κύκλος, το Σειρά είναι ιδιαίτερα χρήσιμο. Αντίθετα, η προσέγγιση δύο σημείων Floyd-Warshall είναι μια λύση βελτιστοποιημένη για το διάστημα, στην οποία δύο κινούμενες αναφορές ή δείκτες έχουν διαφορετικές ταχύτητες. Αν ενωθούν, βρίσκεται ένα μοτίβο.
Κάνοντας αυτούς τους αλγόριθμους πιο αποτελεσματικούς, είναι δυνατό να εξεταστούν γρήγορα λίστες αναπαραγωγής που περιέχουν χιλιάδες τραγούδια. Η τεχνική των δύο σημείων είναι τέλεια για καταστάσεις όπου η χρήση της μνήμης είναι ένα πρόβλημα, επειδή έχει πολυπλοκότητα χρόνου O(n) και πολυπλοκότητα χώρου O(1). Επιπλέον, οι λύσεις μας επαληθεύονται ότι λειτουργούν σωστά χρησιμοποιώντας δοκιμές μονάδων, όπως αυτές που γίνονται με Mocha, οι οποίες ανιχνεύουν λίστες αναπαραγωγής με επαναφορά και χωρίς επαναφορά σε διάφορες ρυθμίσεις.
Συνήθεις ερωτήσεις σχετικά με τον εντοπισμό κύκλου λίστας αναπαραγωγής
- Τι είναι ένας κύκλος σε μια λίστα αναπαραγωγής;
- Όταν ένα τραγούδι στη λίστα αναπαραγωγής αναφέρεται σε ένα προηγούμενο τραγούδι, δημιουργείται μια ακολουθία βρόχου γνωστή ως κύκλος.
- Πώς η τεχνική των δύο πόντων ανιχνεύει έναν κύκλο;
- Ένας γρήγορος δείκτης κινείται δύο βήματα και ένας αργός δείκτης κινείται ένα βήμα τη φορά χρησιμοποιώντας την τεχνική των δύο σημείων. Εάν ενωθούν, υπάρχει ένας βρόχος.
- Γιατί είναι α Set χρησιμοποιείται για ανίχνευση κύκλου;
- Σε ένα Set, αποθηκεύονται διακριτές τιμές. Είναι χρήσιμο να κρατάτε σημειώσεις της μουσικής που ακούτε. Ένας βρόχος αναγνωρίζεται εάν μια μουσική αναπαράγεται ξανά.
- Μπορώ να χρησιμοποιήσω αυτόν τον αλγόριθμο για άλλες εφαρμογές;
- Πράγματι, πολλή δουλειά γίνεται στον εντοπισμό βρόχων σε συνδεδεμένες λίστες, στη διαχείριση μνήμης και στη δρομολόγηση δικτύου χρησιμοποιώντας την τεχνική ανίχνευσης κύκλου.
- Γιατί χρησιμοποιούμε while βρόχους στη διέλευση της λίστας αναπαραγωγής;
- Μπορούμε επαναληπτικά να περάσουμε από τη λίστα αναπαραγωγής χρησιμοποιώντας το while βρόχο μέχρι να βρούμε έναν κύκλο ή να φτάσουμε στο τέλος της λίστας.
Τελικές σκέψεις για τον εντοπισμό επαναλαμβανόμενων λιστών αναπαραγωγής
Μπορεί να είναι δύσκολο να προσδιοριστούν οι κύκλοι σε μια λίστα αναπαραγωγής, ιδιαίτερα κατά την πλοήγηση στη διαχείριση αναφοράς αντικειμένων της JavaScript. Ωστόσο, μπορούμε να χειριστούμε αποτελεσματικά αυτό το ζήτημα και να βελτιώσουμε τον κώδικά μας χρησιμοποιώντας τεχνικές όπως η εφαρμογή της τεχνικής των δύο σημείων ή η παρακολούθηση αναφορών τραγουδιών με ένα σύνολο.
Η γνώση του τρόπου λειτουργίας αυτών των τεχνικών θα σας βοηθήσει να λύσετε τα προβλήματα πιο αποτελεσματικά, είτε το αντιμετωπίζετε για μια συνέντευξη κωδικοποίησης είτε για πρακτικές χρήσεις. Χρησιμοποιώντας αποτελεσματικές δομές όπως Σειρά και η κατανόηση του τρόπου με τον οποίο οι δείκτες βοηθούν στην ανίχνευση κύκλου είναι τα κύρια μαθήματα που πρέπει να αντληθούν.
Πόροι και αναφορές για ανίχνευση κύκλου λίστας αναπαραγωγής
- Η έμπνευση για τους αλγόριθμους ανίχνευσης του κύκλου λίστας αναπαραγωγής αντλήθηκε από κοινά προβλήματα και τεχνικές συνδεδεμένης λίστας, όπως ο αλγόριθμος Floyd-Warshall. Μάθετε περισσότερα σχετικά με τις συνδεδεμένες λίστες και τον εντοπισμό κύκλων σε αυτόν τον περιεκτικό πόρο: Ανίχνευση κύκλου στη Wikipedia .
- Ένας άλλος εξαιρετικός πόρος που χρησιμοποιείται είναι η τεκμηρίωση JavaScript για αντικείμενα Set, τα οποία διαδραματίζουν βασικό ρόλο στην προσέγγιση της πρώτης λύσης: Ορισμός JavaScript στο MDN .
- Για πιο λεπτομερείς τεχνικές δοκιμών σε JavaScript, η επίσημη τεκμηρίωση του Mocha ήταν μια βασική πηγή για την κατανόηση της δομής και των ισχυρισμών των δοκιμών: Πλαίσιο δοκιμών μόκας .
- Εξερευνήστε αυτόν τον οδηγό για την τεχνική των δύο σημείων, η οποία χρησιμοποιείται συχνά για προβλήματα ανίχνευσης κύκλου και είναι μία από τις αποτελεσματικές μεθόδους που χρησιμοποιούνται εδώ: Ανίχνευση βρόχου σε μια συνδεδεμένη λίστα .