[Powered by Google Translate] [Walkthrough - Σετ Πρόβλημα 6]
[Zamyla Chan - Πανεπιστήμιο του Χάρβαρντ]
[Αυτό είναι CS50. - CS50.TV]
>> Γεια σας, όλοι, και καλωσορίζουμε στο Walkthrough 6: Huff'n Puff.
Σε Σφολιάτα Huff'n τι κάνουμε πρόκειται να κάνουμε με ένα αρχείο συμπιεσμένο Huffman
και στη συνέχεια, ξεφυσώντας το back up, αποσυμπίεση έτσι,
έτσι ώστε να μπορούμε να μεταφράσει από την 0s και 1s ότι ο χρήστης στέλνει μας
και να το μετατρέψει πίσω στο αρχικό κείμενο.
Pset 6 θα είναι αρκετά δροσερό, επειδή θα πάμε να δούμε μερικά από τα εργαλεία
που χρησιμοποιούνται σε PSET 4 και 5 και PSET είδος του συνδυασμού τους σε 1 πολύ πετυχημένος έννοια
όταν έρχεστε να το σκεφτώ.
>> Επίσης, αναμφισβήτητα, PSET 4 και 5 ήταν οι πιο δύσκολες psets που είχε να προσφέρει.
Έτσι, από τώρα, έχουμε αυτό το 1 ακόμα PSET σε C,
και στη συνέχεια, μετά από αυτό είμαστε για να web προγραμματισμό.
Έτσι, τον εαυτό σας συγχαρώ για να πάρει πάνω από την καμπούρα πιο δύσκολες σε CS50.
>> Προχωρώντας για Puff Huff'n, εργαλειοθήκη μας για αυτό το PSET πρόκειται να Huffman δέντρα,
έτσι η κατανόηση όχι μόνο πώς δυαδική εργασία δέντρα, αλλά και συγκεκριμένα δέντρα Huffman,
πώς είστε κατασκευαστεί.
Και μετά θα πάμε να έχουν μια πολύ κώδικα της διανομής σε αυτό το PSET,
και θα έρθει να δούμε ότι στην πραγματικότητα μερικά από τα κώδικα
ίσως να μην είναι σε θέση να κατανοούν πλήρως ακόμα,
και έτσι αυτά θα είναι τα αρχεία. γ, αλλά στη συνέχεια τα συνοδευτικά. h αρχεία τους
θα μας δώσει αρκετή κατανόηση ότι χρειαζόμαστε να ξέρουμε πώς λειτουργούν αυτές οι λειτουργίες
ή τουλάχιστον ό, τι υποτίθεται ότι πρέπει να κάνουμε - εισόδους και εξόδους τους -
ακόμα και αν δεν γνωρίζουμε τι συμβαίνει στο μαύρο κουτί
ή δεν καταλαβαίνουν τι συμβαίνει στο μαύρο κουτί μέσα.
Και τελικά, ως συνήθως, έχουμε να κάνουμε με νέες δομές δεδομένων,
συγκεκριμένους τύπους κόμβων που δείχνουν ορισμένα πράγματα,
και έτσι έχοντας εδώ ένα στυλό και χαρτί, όχι μόνο για τη διαδικασία σχεδιασμού
και όταν προσπαθείτε να καταλάβω πώς PSET σας θα πρέπει να εργαστούν
αλλά και κατά τη διάρκεια του debugging.
Μπορείτε να έχετε μαζί GDB στυλό και το χαρτί σας, ενώ παίρνετε κάτω ποιες είναι οι αξίες,
όπου τα βέλη σας δείχνουν, και τέτοια πράγματα.
>> Πρώτα ας ρίξουμε μια ματιά σε Huffman δέντρα.
Huffman δέντρα είναι δυαδικά δέντρα, πράγμα που σημαίνει ότι κάθε κόμβος έχει μόνο 2 παιδιά.
Στην Huffman δέντρα το χαρακτηριστικό στοιχείο είναι ότι οι συχνότερες τιμές
αντιπροσωπεύονται από τα λιγότερα κομμάτια.
Είδαμε στα παραδείγματα διάλεξη του κώδικα Μορς, που το είδος των ενοποιημένων μερικά γράμματα.
Αν προσπαθείτε να μεταφράσει ένα Α ή Ε, για παράδειγμα,
είστε μετάφραση ότι συχνά, έτσι ώστε αντί να χρειάζεται να χρησιμοποιήσει το σύνολο των bits
διατεθεί για το συνηθισμένο τύπο δεδομένων, μπορείτε να συμπιέσετε τα κάτω σε λιγότερους,
και τότε τα γράμματα που εκπροσωπούνται λιγότερο συχνά εκπροσωπούνται πλέον με bits
επειδή μπορείτε να αντέξετε οικονομικά ότι όταν ζυγίζουν από τις συχνότητες που εμφανίζονται αυτά τα γράμματα.
Έχουμε την ίδια ιδέα εδώ στην Huffman δέντρα
όπου έχουμε κάνει μια αλυσίδα, ένα είδος μονοπάτι για να φτάσουμε στην ορισμένους χαρακτήρες.
Και τότε οι χαρακτήρες που έχουν τη μεγαλύτερη συχνότητα
πρόκειται να εκπροσωπείται με τις λιγότερες bits.
>> Ο τρόπος που θα κατασκευάσει ένα δέντρο Huffman
είναι με την τοποθέτηση όλων των χαρακτήρων που εμφανίζονται στο κείμενο
και τον υπολογισμό των συχνοτήτων τους, πόσο συχνά εμφανίζονται.
Αυτό θα μπορούσε να είναι είτε ένα αριθμό που δείχνει πόσες φορές εμφανίζονται οι επιστολές
ή ίσως ένα ποσοστό από το σύνολο των χαρακτήρων πόσα καθένα εμφανίζεται.
Και έτσι αυτό που κάνετε είναι, αφού έχετε όλα αυτά που χάραξε,
τότε θα δούμε για τις 2 χαμηλότερες συχνότητες και στη συνέχεια να ενταχθούν ως αδέλφια
όπου τότε ο κόμβος γονέας έχει μία συχνότητα η οποία είναι το άθροισμα των 2 παιδιά της.
Και τότε, κατά συνθήκη, να πω ότι η αριστερά κόμβο,
ακολουθείτε ότι ακολουθώντας το 0 υποκατάστημα,
και στη συνέχεια, το δεξιότερο είναι ο κόμβος 1 κατάστημα.
Όπως είδαμε σε κώδικα Μορς, ο ένας gotcha ήταν ότι αν είχε μόνο ένα ηχητικό σήμα και το μπιπ
ήταν διφορούμενη.
Θα μπορούσε να είναι είτε 1 γράμμα ή θα μπορούσε να είναι μια ακολουθία από 2 γράμματα.
Και έτσι τι κάνει Huffman δέντρα είναι επειδή από τη φύση των χαρακτήρων
ή μας τελικό πραγματικούς χαρακτήρες είναι οι τελευταίοι κόμβοι στο υποκατάστημα -
αναφερόμαστε σε αυτούς ως φύλλα - λόγω του ότι δεν μπορεί να υπάρξει καμία αμφιβολία
σύμφωνα με την οποία επιστολή που προσπαθείτε να κωδικοποιούν με τη σειρά των bits
γιατί πουθενά κατά μήκος των bits που αντιπροσωπεύουν το 1 γράμμα
θα συναντήσετε ένα άλλο ολόκληρο επιστολή, και δεν θα υπάρξει καμία σύγχυση εκεί.
Αλλά θα πάμε σε παραδείγματα που εσείς μπορείτε πραγματικά να δείτε ότι
αντί να μας λέει απλά ότι αυτό είναι αλήθεια.
>> Ας δούμε ένα απλό παράδειγμα ενός δέντρου Huffman.
Έχω εδώ μια σειρά που είναι 12 χαρακτήρες.
Έχω 4 Όπως, 6 Β, και 2 Cs.
Πρώτο βήμα μου θα είναι να μετρήσει.
Πόσες φορές δεν εμφανίζεται ένα; Φαίνεται 4 φορές στη σειρά.
Β εμφανίζεται 6 φορές, και C εμφανίζεται 2 φορές.
Φυσικά, θα πάω να πω ότι είμαι με τη χρήση Β πιο συχνά,
έτσι θέλω να εκπροσωπώ Β με το μικρότερο αριθμό bits, ο μικρότερος αριθμός από 0 και 1.
Και τότε είμαι επίσης πρόκειται να περιμένουμε C να απαιτήσει το πιο ποσό των 0 και 1, καθώς και.
Πρώτη αυτό που έκανα εδώ εγώ τους τοποθετούνται σε αύξουσα σειρά όσον αφορά τη συχνότητα.
Βλέπουμε ότι η C και η Α, αυτά είναι 2 χαμηλότερες συχνότητες μας.
Δημιουργούμε έναν κόμβο γονέα, και ότι ο κόμβος γονέας δεν έχει επιστολή που συνδέονται με αυτό,
αλλά έχει μία συχνότητα, η οποία είναι το άθροισμα.
Το άθροισμα καθίσταται 2 + 4, η οποία είναι 6.
Στη συνέχεια ακολουθούμε το αριστερό σκέλος.
Αν ήμασταν σε αυτόν τον κόμβο 6, τότε θα ακολουθήσει 0 έως φτάσετε στο Γ
και στη συνέχεια 1 για να φτάσετε στο Α.
Έτσι τώρα έχουμε 2 κόμβους.
Έχουμε την τιμή 6 και στη συνέχεια, έχουμε επίσης ένα άλλο κόμβο με την τιμή 6.
Και έτσι τα 2 δεν είναι μόνο το 2 χαμηλότερη αλλά και μόνο το 2 που έχουν απομείνει,
έτσι ώστε να ενταχθούν αυτά από άλλο γονέα, με το άθροισμα είναι 12.
Έτσι, εδώ έχουμε Huffman δέντρο μας
όπου για να πάρει στο Β, η οποία θα ήταν απλά το bit 1
και στη συνέχεια να πάρει στο Α θα είχαμε 01 και στη συνέχεια με C 00.
Έτσι, εδώ βλέπουμε ότι βασικά είμαστε εκπροσωπούν αυτές χαρακτήρες είτε με 1 ή 2 bits
όπου το Β, όπως προβλέπεται, έχει το λιγότερο.
Και τότε είχαμε C αναμένεται να έχουν τη μεγαλύτερη, αλλά δεδομένου ότι είναι ένα τόσο μικρό δέντρο Huffman,
τότε το Α αντιπροσωπεύεται επίσης από 2 δυαδικά ψηφία, σε αντίθεση με κάπου στη μέση.
>> Ακριβώς για να πάει πάνω από ένα άλλο απλό παράδειγμα του δέντρου Huffman,
υποθέσουμε ότι έχετε τη συμβολοσειρά "Hello".
Αυτό που κάνετε είναι η πρώτη που θα πω πόσες φορές έχει εμφανιστεί H σε αυτό;
Η εμφανίζεται μία φορά και στη συνέχεια e εμφανίζεται μία φορά και στη συνέχεια έχουμε l εμφανίζεται δύο φορές
και o εμφανίζονται μία φορά.
Και έτσι στη συνέχεια, περιμένουμε ποιο γράμμα πρέπει να εκπροσωπείται από τον ελάχιστο αριθμό bit;
[Φοιτητής] l. >> L. Ναι. l είναι δεξιά.
Περιμένουμε l που αντιπροσωπεύεται από τον ελάχιστο αριθμό bit
l επειδή χρησιμοποιείται πλέον στη συμβολοσειρά "Hello".
Τι Πάω να κάνουμε τώρα είναι να σύρει έξω αυτούς τους κόμβους.
Έχω 1, η οποία είναι Η, και ακολούθως άλλο 1, η οποία είναι ε, και στη συνέχεια ένα 1, το οποίο είναι o -
τώρα είμαι θέση τους, προκειμένου - και στη συνέχεια 2, το οποίο είναι l.
Τότε λέω ότι ο τρόπος μπορώ να οικοδομήσουμε ένα δέντρο Huffman είναι να βρείτε τις 2 κόμβοι με τις λιγότερες συχνότητες
και να τους αδέλφια δημιουργώντας ένα μητρικό κόμβο.
Εδώ έχουμε 3 κόμβους με τη χαμηλότερη συχνότητα. Είναι όλοι 1.
Έτσι, εδώ έχουμε επιλέξει ποια θα πάμε να συνδέσει πρώτα.
Ας πούμε ότι επιλέγουν το H και το e.
Το άθροισμα 1 + 1 είναι 2, αλλά αυτός ο κόμβος δεν έχει ένα γράμμα που συνδέονται με αυτό.
Κρατά μόνο την αξία.
Τώρα κοιτάμε τα επόμενα 2 χαμηλότερες συχνότητες.
Αυτό είναι 2 και 1. Αυτό θα μπορούσε να είναι μία από αυτές τις 2, αλλά Πάω να διαλέξει αυτή.
Το ποσό είναι 3.
Και τελικά, έχω μόνο 2 αριστερά, έτσι, τότε αυτό γίνεται 5.
Στη συνέχεια, εδώ, όπως ήταν αναμενόμενο, αν συμπληρώσετε την κωδικοποίηση για το ότι,
1s είναι πάντα η σωστή υποκατάστημα και 0s είναι το αριστερό.
Στη συνέχεια, έχουμε l εκπροσωπείται από μόλις 1 bit και στη συνέχεια το κατά 2 o
και στη συνέχεια το e από 2 και έπειτα το H πέφτει στο 3 bits.
Έτσι, μπορείτε να μεταδώσετε αυτό το μήνυμα "Hello" αντί του πραγματικά με τους χαρακτήρες
με μόλις 0s και 1s.
Ωστόσο, να θυμάστε ότι σε αρκετές περιπτώσεις είχαμε δεσμούς με συχνότητα μας.
Θα μπορούσαμε να είχαμε ενταχθεί είτε το Υ και το πρώτο ίσως o.
Ή τότε αργότερα, όταν είχαμε την l εκπροσωπείται από 2
καθώς και το ενωμένο μία που αντιπροσωπεύεται από 2, θα μπορούσαμε να είχαμε συνδέονται είτε ένα.
>> Και έτσι όταν στέλνετε το 0s και 1s, που στην πραγματικότητα δεν εγγυάται
ότι ο παραλήπτης μπορεί να διαβάσει πλήρως το μήνυμά σας δεξιά από το ρόπαλο
επειδή μπορεί να μην γνωρίζουν ποια απόφαση που κάνατε.
Έτσι, όταν έχουμε να κάνουμε με συμπίεση Huffman,
με κάποιο τρόπο πρέπει να πούμε στον παραλήπτη του μηνύματός μας πώς αποφασίσαμε -
Θα πρέπει να γνωρίζουν κάποια επιπλέον πληροφορία
εκτός από το μήνυμα συμπιεσμένο.
Πρέπει να καταλάβουμε τι το δέντρο μοιάζει πραγματικά σαν,
πώς θα γίνει πραγματικά αυτές τις αποφάσεις.
>> Εδώ κάναμε απλά παραδείγματα με βάση την πραγματική μέτρηση,
αλλά μερικές φορές μπορείτε επίσης να έχετε ένα δέντρο Huffman
με βάση τη συχνότητα με την οποία εμφανίζονται τα γράμματα, και είναι η ίδια ακριβώς διαδικασία.
Εδώ είμαι να εκφράζουν σε ποσοστά ή ένα κλάσμα,
και έτσι εδώ ακριβώς το ίδιο πράγμα.
Θεωρώ ότι τα 2 χαμηλότερα, άθροισμα τους, το χαμηλότερο επόμενα 2, τα συνοψίσω,
μέχρι να έχω μια πλήρη δέντρο.
Ακόμα κι αν θα μπορούσαμε να κάνουμε αυτό ή τον άλλο τρόπο, όταν έχουμε να κάνουμε με ποσοστά,
αυτό σημαίνει ότι είμαστε διαιρώντας τα πράγματα και ασχολείται με δεκαδικά ψηφία ή μάλλον επιπλέει
αν σκεφτόμαστε δομές δεδομένων του κεφαλιού.
Τι γνωρίζουμε για επιπλέει;
Τι είναι ένα κοινό πρόβλημα, όταν έχουμε να κάνουμε με άρματα;
[Φοιτητής] Ανακριβείς αριθμητική. Ναι >>. Ανακρίβεια.
Λόγω της κινητής ανακρίβεια σημείο, γι 'αυτό PSET έτσι ώστε να βεβαιωθείτε ότι
ότι δεν θα χάσουν κανένα αξίες, τότε είμαστε πραγματικά πρόκειται να ασχολείται με την καταμέτρηση.
Έτσι, αν ήταν να σκεφτούμε έναν κόμβο Huffman, αν κοιτάξουμε πίσω στη δομή εδώ,
αν κοιτάξει κανείς τα πράσινα έχει μια συχνότητα που συνδέονται με αυτό
καθώς και επισημαίνει σε έναν κόμβο προς τα αριστερά του, καθώς και ένα κόμβο προς τα δεξιά της.
Και τότε οι κόκκινες εκεί έχουν επίσης ένα χαρακτήρα που συνδέονται με αυτά.
Εμείς δεν πρόκειται να κάνουν ξεχωριστές αυτές για τους γονείς και στη συνέχεια των τελικών κόμβων,
οποία αναφερόμαστε ως φύλλα, αλλά μάλλον εκείνοι θα έχουν ακριβώς τις τιμές NULL.
Για κάθε κόμβο θα έχουμε ένα χαρακτήρα, το σύμβολο ότι ο κόμβος αντιπροσωπεύει,
τότε μια συχνότητα καθώς και ένα δείκτη προς τα αριστερά το παιδί της, καθώς και δεξί παιδί της.
Τα φύλλα, τα οποία είναι στο κάτω μέρος, θα έχουν επίσης κόμβο δείκτες
προς τα αριστερά και προς τα δεξιά τους, αλλά δεδομένου ότι οι τιμές δεν δείχνουν την πραγματική τους κόμβους,
τι θα τους αξία είναι; >> [Φοιτητής] NULL. >> NULL. Ακριβώς.
Εδώ είναι ένα παράδειγμα για το πώς μπορεί να εκπροσωπεί τη συχνότητα σε άρματα,
αλλά θα πάμε να ασχολούνται με αυτό με ακέραιους αριθμούς,
έτσι το μόνο που έκανα είναι να αλλάξετε τον τύπο δεδομένων που υπάρχουν.
>> Ας προχωρήσουμε σε λίγο περισσότερο από ένα σύνθετο παράδειγμα.
Τώρα, όμως, ότι έχουμε κάνει τις απλές, είναι ακριβώς η ίδια διαδικασία.
Μπορείτε να βρείτε τις 2 χαμηλότερες συχνότητες, αθροίζονται οι συχνότητες
και αυτή είναι η νέα συχνότητα του κόμβου γονέα σας,
η οποία επισημαίνει στη συνέχεια προς τα αριστερά του με το υποκατάστημα 0 και δεξιά με τον κλάδο 1.
Αν έχουμε τη συμβολοσειρά "Αυτό είναι CS50," τότε μετράνε πόσες φορές έχει αναφερθεί Τ,
h αναφέρθηκε, ί, s, γ, 5, 0.
Στη συνέχεια, αυτό που έκανα εδώ είναι με τα κόκκινα κόμβους που μόλις φυτευτεί,
Είπα ότι πάω για αυτούς τους χαρακτήρες τελικά στο κάτω μέρος του δέντρου μου.
Αυτοί πρόκειται να είναι όλων των φύλλων.
Στη συνέχεια, αυτό που έκανα εγώ είναι να Είδος από τη συχνότητα με αύξουσα σειρά,
και αυτό είναι στην πραγματικότητα ο τρόπος που ο κωδικός PSET κάνει
είναι ότι τα είδη με τη συχνότητα και στη συνέχεια αλφαβητικά.
Γι 'αυτό έχει τους αριθμούς πρώτα και στη συνέχεια αλφαβητικά με τη συχνότητα.
Τότε τι θα ήθελα να κάνω είναι ότι θα βρείτε το 2 χαμηλότερη. Αυτό είναι 0 και 5.
Θα ήθελα να συνοψίσω τους, και ότι είναι 2. Στη συνέχεια, θα ήθελα να συνεχίσει, να βρουν τα επόμενα 2 χαμηλότερη.
Αυτοί είναι οι δύο 1s, και στη συνέχεια εκείνες γίνει 2, καθώς και.
Τώρα ξέρω ότι το επόμενο βήμα μου θα πρέπει να ενώνει το μικρότερο αριθμό,
το οποίο είναι το Τ, το 1, και στη συνέχεια επιλέγοντας έναν από τους κόμβους που έχει 2 ως συχνότητα.
Έτσι, εδώ έχουμε 3 επιλογές.
Τι Πάω να κάνουμε για τη διαφάνεια είναι ακριβώς αναδιατάξετε τα οπτικά για εσάς
έτσι ώστε να μπορείτε να δείτε πώς να είμαι δημιουργία.
Τι ο κώδικας και ο κώδικας της διανομής σας πρόκειται να κάνει θα ήταν να ενταχθούν στην t ένα
με τον κόμβο 0 και 5.
Έτσι, στη συνέχεια, ότι τα ποσά έως 3, και στη συνέχεια θα συνεχίσει τη διαδικασία.
Το 2 και το 2 τώρα είναι το χαμηλότερο, έτσι τότε εκείνοι ποσό έως 4.
Ο καθένας ακολουθεί μέχρι σήμερα; Εντάξει.
Έπειτα, μετά ότι έχουμε το 3 και το 3 που πρέπει να προστεθούν,
έτσι είμαι και πάλι αλλαγή είναι ακριβώς έτσι ώστε να μπορείτε να δείτε οπτικά, έτσι ώστε να μην πάρει πάρα πολύ βρώμικο.
Στη συνέχεια έχουμε ένα 6, και στη συνέχεια τελικό βήμα μας είναι ότι τώρα έχουμε μόνο 2 κόμβοι
Συνοψίζοντας μπορούμε να τα καταστήσει τη ρίζα του δέντρου μας, η οποία είναι 10.
Και ο αριθμός 10 έχει νόημα, επειδή κάθε κόμβος αντιπροσωπεύεται,
αξία τους, τον αριθμό συχνότητά τους, ήταν το πόσες φορές εμφανίστηκαν στη σειρά,
και τότε έχουμε 5 χαρακτήρες σε σειρά μας, έτσι ώστε νόημα.
Αν κοιτάξουμε πάνω στο πώς θα κωδικοποιήσει στην πραγματικότητα,
όπως αναμενόταν, το i και το s, οι οποίες εμφανίζονται πιο συχνά
αντιπροσωπεύονται από το μικρότερο αριθμό από bits.
>> Να είστε προσεκτικοί εδώ.
Στην Huffman δέντρα η υπόθεση έχει σημασία στην πραγματικότητα.
Ένα κεφαλαίο γράμμα S είναι διαφορετική από ό, τι ένα πεζό s.
Αν είχαμε "Αυτό είναι CS50" με κεφαλαία γράμματα, τότε η s πεζά θα εμφανίζονται μόνο δύο φορές,
θα είναι ένας κόμβος με 2 ως αξία του, και στη συνέχεια κεφαλαίο γράμμα S θα είναι μόνον μία φορά.
Έτσι, τότε το δέντρο σας θα αλλάξει τις δομές, επειδή έχετε πραγματικά ένα επιπλέον φύλλο εδώ.
Όμως, το ποσό θα εξακολουθούσε να είναι 10.
Αυτό είναι ό, τι είμαστε στην πραγματικότητα θα πρέπει να καλέσετε το άθροισμα ελέγχου,
η προσθήκη όλων των μετρήσεων.
>> Τώρα που έχουμε καλύπτονται Huffman δέντρα, μπορούμε να βουτήξει Puff Huff'n, η PSET.
Εμείς πάμε για να ξεκινήσετε με ένα τμήμα των ερωτήσεων,
και αυτό πρόκειται να σας πάρει εξοικειωμένοι με δυαδικά δέντρα και πώς να λειτουργούν γύρω από αυτό:
αντλώντας κόμβους, δημιουργώντας τη δική σας typedef struct για έναν κόμβο,
και να δούμε πώς μπορείτε να εισαγάγετε σε ένα δυαδικό δέντρο, ένα που είναι ταξινομημένο,
διασχίζει, και τέτοια πράγματα.
Αυτή η γνώση είναι σίγουρα πρόκειται να σας βοηθήσει όταν βουτιά στο τμήμα Puff Huff'n
του PSET.
Στη βασική έκδοση του PSET, καθήκον σας είναι να εφαρμόσει Puff,
και στην έκδοση χάκερ καθήκον σας είναι να εφαρμόσει Huff.
Τι Huff που κάνει είναι να παίρνει το κείμενο και στη συνέχεια να μεταφράζεται σε 0s και 1s,
έτσι ώστε η διαδικασία που κάναμε παραπάνω, όπου θα υπολογίζονται οι συχνότητες
και στη συνέχεια έκανε το δέντρο και στη συνέχεια είπε: «Πώς μπορώ να πάρω T;"
Τ αντιπροσωπεύεται από 100, τα πράγματα όπως ότι,
και στη συνέχεια θα λάβει Huff το κείμενο και στη συνέχεια έξοδος ότι δυαδικό.
Αλλά και επειδή ξέρουμε ότι θέλουμε να επιτρέψει παραλήπτη μας του μηνύματος
να αναδημιουργήσει ακριβώς το ίδιο δέντρο, περιλαμβάνει επίσης πληροφορίες σχετικά με τις μετρήσεις συχνότητας.
Στη συνέχεια, με Puff μας δίνεται ένα δυαδικό αρχείο του 0s και 1s
και δεδομένου επίσης τις πληροφορίες σχετικά με τις συχνότητες.
Έχουμε μεταφράσει όλα αυτά τα 0s και 1s πίσω στο αρχικό μήνυμα που ήταν,
έτσι είμαστε αποσυμπίεση αυτό.
Αν κάνεις το πρότυπο έκδοση, δεν χρειάζεται να εφαρμόσει Huff,
έτσι, τότε μπορείτε να χρησιμοποιήσετε μόνο την υλοποίηση του προσωπικού του Huff.
Υπάρχουν οδηγίες στο spec για το πώς να το κάνουμε αυτό.
Μπορείτε να εκτελέσετε την εφαρμογή προσωπικό του Huff πάνω σε ένα συγκεκριμένο αρχείο κειμένου
και στη συνέχεια να χρησιμοποιήσετε αυτό το έξοδο ως συμβολή σας για να Puff.
>> Όπως ανέφερα και πριν, έχουμε μια πολύ κώδικα διανομής για αυτό.
Πάω να αρχίσει να πηγαίνει μέσα από αυτό.
Πάω να περνούν το μεγαλύτερο μέρος του χρόνου για το. H αρχείων
επειδή τα αρχεία. γ, επειδή έχουμε την. ώρα
και ότι μας παρέχει με τα πρωτότυπα των λειτουργιών,
δεν είναι πλήρως πρέπει να καταλάβουμε ακριβώς -
Αν δεν καταλαβαίνετε τι συμβαίνει στα αρχεία. Γ, τότε μην ανησυχείτε πάρα πολύ,
αλλά σίγουρα να προσπαθήσουμε να ρίξουμε μια ματιά, διότι θα μπορούσε να δώσει κάποιες συμβουλές
και είναι χρήσιμο να συνηθίσουν στην ανάγνωση κώδικα των άλλων ανθρώπων.
>> Κοιτάζοντας huffile.h, στα σχόλια που δηλώνει ένα στρώμα αφαίρεσης Huffman για κωδικοποιημένα αρχεία.
Αν πάμε κάτω, θα δούμε ότι υπάρχει ένα μέγιστο 256 σύμβολα που μπορεί να χρειαστεί για κωδικούς.
Αυτό περιλαμβάνει όλα τα γράμματα του αλφαβήτου - κεφαλαία και πεζά -
και στη συνέχεια, τα σύμβολα και τους αριθμούς, κλπ.
Στη συνέχεια, εδώ έχουμε έναν μαγικό αριθμό που προσδιορίζει ένα Huffman-κωδικοποιημένο αρχείο.
Μέσα σε ένα κώδικα Huffman θα πάμε να έχουν ένα συγκεκριμένο αριθμό μαγεία
που συνδέονται με την κεφαλίδα.
Αυτό μπορεί να μοιάζει με ένα απλό τυχαίο αριθμό μαγεία,
αλλά αν το μεταφράζει πραγματικά σε ASCII, τότε ξόρκια πραγματικά έξω Huff.
Εδώ έχουμε ένα struct για Huffman-κωδικοποιημένο αρχείο.
Δεν υπάρχει όλα αυτά τα χαρακτηριστικά που σχετίζονται με ένα αρχείο Huff.
Στη συνέχεια, εδώ κάτω έχουμε την κεφαλίδα για ένα αρχείο Huff, έτσι το λέμε Huffeader
αντί της προσθήκης επιπλέον την ώρα γιατί ακούγεται το ίδιο έτσι κι αλλιώς.
Χαριτωμένο.
Έχουμε ένα μαγικό αριθμό που συνδέονται με αυτό.
Αν είναι ένα πραγματικό αρχείο Huff, πρόκειται να είναι ο αριθμός ψηλά, αυτό το μαγικό ένα.
Και στη συνέχεια θα έχει μια σειρά.
Έτσι, για κάθε σύμβολο, εκ των οποίων υπάρχουν 256,
πρόκειται να λίστα ό, τι η συχνότητα αυτών των συμβόλων είναι μέσα στο αρχείο Huff.
Και στη συνέχεια, τελικά, έχουμε ένα άθροισμα ελέγχου για τις συχνότητες,
η οποία θα πρέπει να είναι το άθροισμα αυτών των συχνοτήτων.
Έτσι, αυτό είναι ένα Huffeader είναι.
Στη συνέχεια, έχουμε κάποιες λειτουργίες που επιστρέφουν το επόμενο κομμάτι στο αρχείο Huff
καθώς και γράφει ένα κομμάτι στο αρχείο Huff, και στη συνέχεια, η λειτουργία αυτή εδώ, hfclose,
που κλείνει πραγματικά το αρχείο Huff.
Πριν, είχαμε να κάνουμε με ευθεία ακριβώς fclose,
αλλά όταν έχετε ένα αρχείο Huff, αντί να fclosing
τι είστε πραγματικά πρόκειται να κάνουμε είναι να hfclose και hfopen αυτό.
Αυτές είναι συγκεκριμένες λειτουργίες στα αρχεία Huff ότι θα πάμε να κάνουμε.
Στη συνέχεια, εδώ διαβάζουμε στην κεφαλίδα και στη συνέχεια να γράψει την κεφαλίδα.
>> Ακριβώς με την ανάγνωση του. Αρχείο h μπορούμε να το είδος του να πάρει μια αίσθηση για το τι ένα αρχείο Huff θα μπορούσε να είναι,
τι χαρακτηριστικά έχει, χωρίς να υπεισέλθω σε huffile.c,
η οποία, αν βουτήξετε μέσα, πρόκειται να είναι λίγο πιο περίπλοκη.
Έχει όλα τα I / O αρχείο εδώ ασχολούνται με δείκτες.
Εδώ βλέπουμε ότι όταν λέμε hfread, για παράδειγμα, είναι ακόμα ασχολούνται με fread.
Δεν είμαστε για να απαλλαγούμε από αυτές τις λειτουργίες εντελώς, αλλά θα στείλουμε εκείνα που πρέπει να ληφθεί μέριμνα
μέσα στο αρχείο Huff αντί να κάνει όλα από μόνοι μας.
Μπορείτε να αισθανθείτε ελεύθεροι να σαρώσετε μέσα από αυτό, αν είστε περίεργοι
και να πάει και το στρώμα φλούδα πίσω λίγο.
>> Το επόμενο αρχείο που θα πάμε να δούμε είναι tree.h.
Πριν από το Walkthrough σε διαφάνειες είπαμε ότι περιμένουμε ένα Huffman κόμβο
και κάναμε ένα typedef struct node.
Περιμένουμε να έχει ένα σύμβολο, μια συχνότητα, και στη συνέχεια 2 αστέρια κόμβο.
Σε αυτή την περίπτωση αυτό που κάνουμε είναι αυτό είναι ουσιαστικά η ίδια
εκτός αντί του κόμβου θα πάμε να τους αποκαλούν δέντρα.
Έχουμε μια λειτουργία που όταν σας καλούν να δέντρο επιστρέφει ένα δείκτη σας δέντρο.
Back to Ορθογράφος, όταν έκαναν ένα νέο κόμβο
είπατε κόμβο * νέα λέξη = malloc (sizeof) και τέτοια πράγματα.
Βασικά, mktree πρόκειται να ασχολείται με αυτό για σας.
Ομοίως, όταν θέλετε να αφαιρέσετε ένα δέντρο,
έτσι ώστε να είναι απελευθερώνοντας ουσιαστικά το δέντρο, όταν τελειώσετε με αυτό,
αντί ρητά καλώντας δωρεάν στο ότι, στην πραγματικότητα είστε ακριβώς πρόκειται να χρησιμοποιήσετε τη λειτουργία rmtree
όπου θα περάσει το δείκτη σε αυτό το δέντρο και στη συνέχεια tree.c θα φροντίσει αυτό για σας.
>> Προσβλέπουμε σε tree.c.
Περιμένουμε τις ίδιες λειτουργίες, εκτός για να δείτε την εφαρμογή, καθώς και.
Όπως ήταν αναμενόμενο, όταν σας καλούν mktree το mallocs το μέγεθος ενός δέντρου σε ένα δείκτη,
αρχικοποιεί όλες τις τιμές για την τιμή NULL, έτσι 0s ή τιμές NULL,
και στη συνέχεια επιστρέφει το δείκτη σε αυτό το δέντρο που μόλις malloc'd σας.
Εδώ όταν καλείτε αφαιρέσετε το δέντρο κάνει την πρώτη βέβαιος ότι δεν είστε διπλά απελευθέρωση.
Κάνει βέβαιος ότι έχετε πραγματικά ένα δέντρο που θέλετε να καταργήσετε.
Εδώ επειδή ένα δέντρο περιλαμβάνει επίσης τα παιδιά του,
τι είναι αυτό που κάνει είναι να ζητά αναδρομικά αφαιρέσετε δέντρο στο αριστερό κόμβο του δέντρου
καθώς και το σωστό κόμβο.
Πριν ελευθερώνει το γονέα, που χρειάζεται για να απελευθερώσει τα παιδιά, καθώς και.
Μητρική είναι επίσης εναλλάξιμες με ρίζα.
Η πρώτη μητρική, έτσι όπως την προ-προ-προ-προ-παππούς
ή δέντρο γιαγιά, πρέπει πρώτα να απελευθερωθούν τα κάτω τα επίπεδα πρώτα.
Έτσι διασχίζουν προς τα κάτω, χωρίς αυτούς, και στη συνέχεια να δημιουργήσετε αντίγραφα ασφαλείας, χωρίς αυτούς, κλπ.
Έτσι, αυτό είναι δέντρο.
>> Τώρα κοιτάμε δάσος.
Δάσος είναι όπου μπορείτε να τοποθετήσετε όλα τα δέντρα Huffman σας.
Είναι λέγοντας ότι θα πάμε για να έχουν κάτι που ονομάζεται ένα οικόπεδο
το οποίο περιέχει ένα δείκτη σε ένα δέντρο, καθώς και ένα δείκτη σε ένα οικόπεδο που ονομάζεται επόμενο.
Ποια είναι η διάρθρωση αυτού του είδους μοιάζει;
Είναι το είδος του λέει εκεί πέρα.
Δικαίωμα εδώ.
Μια συνδεδεμένη λίστα.
Βλέπουμε ότι όταν έχουμε ένα οικόπεδο είναι σαν μια συνδεδεμένη λίστα των οικοπέδων.
Ένα δάσος ορίζεται ως μια συνδεδεμένη λίστα των οικοπέδων,
και έτσι η δομή του δάσους είναι είμαστε ακριβώς πρόκειται να έχουν ένα δείκτη στην πρώτη οικόπεδο μας
και ότι το οικόπεδο έχει ένα δέντρο μέσα τους, ή μάλλον οδηγεί σε ένα δέντρο
και στη συνέχεια επισημαίνει στο επόμενο πλοκή, ούτω καθεξής και ούτω καθεξής.
Για να κάνετε ένα δάσος που ονομάζουμε mkforest.
Στη συνέχεια, έχουμε κάποιες πολύ χρήσιμες λειτουργίες εδώ.
Έχουμε πάρει όπου θα περάσει σε ένα δάσος και στη συνέχεια, η επιστρεφόμενη τιμή είναι μια * Δέντρο,
ένας δείκτης σε ένα δέντρο.
Ποια επιλογή θα κάνει είναι ότι θα πάει στο δάσος ότι είστε δείχνοντας
στη συνέχεια, αφαιρέστε ένα δέντρο με τη χαμηλότερη συχνότητα από το δάσος
και στη συνέχεια να σας δώσει το δείκτη σε αυτό το δέντρο.
Μόλις πάρει κλήση, το δέντρο δεν θα υπάρχουν στο δάσος πια,
αλλά η τιμή επιστροφής είναι ο δείκτης για το δέντρο.
Στη συνέχεια θα πρέπει φυτό.
Υπό την προϋπόθεση ότι θα περάσει σε ένα δείκτη σε ένα δέντρο που έχει μια μη-0 συχνότητα,
ποια μονάδα θα κάνουμε είναι θα πάρει το δάσος, να το δέντρο και φυτό που μέσα δέντρο του δάσους.
Εδώ έχουμε rmforest.
Παρόμοια με την απομάκρυνση δέντρο, το οποίο απελευθερώθηκε ουσιαστικά όλα τα δέντρα μας για μας,
αφαιρέσετε δάσος θα απελευθερώσει όλα όσα περιλαμβάνονται σε αυτό το δάσος.
>> Αν κοιτάξουμε σε forest.c, θα περιμένουμε να δούμε τουλάχιστον 1 rmtree εντολή εκεί,
επειδή στην ελεύθερη μνήμη στο δάσος, αν το δάσος έχει δέντρα σε αυτό,
τότε τελικά θα πάμε να πρέπει να καταργήσετε αυτά τα δέντρα πάρα πολύ.
Αν κοιτάξουμε σε forest.c, έχουμε mkforest μας, η οποία είναι τόσο περιμένουμε.
Εμείς malloc πράγματα.
Έχουμε προετοιμαστεί το πρώτο οικόπεδο στο δάσος, όπως NULL γιατί είναι άδειο για να αρχίσει με,
τότε βλέπουμε υφαδιάς, η οποία επιστρέφει το δέντρο με το μικρότερο βάρος, η χαμηλότερη συχνότητα,
και στη συνέχεια να παίρνει απαλλαγούμε από το συγκεκριμένο κόμβο που οδηγεί σε αυτό το δέντρο και το επόμενο,
έτσι ώστε να παίρνει ότι από τη συνδεδεμένη λίστα του δάσους.
Και τότε εδώ έχουμε εργοστάσιο, το οποίο εισάγει ένα δέντρο στη συνδεδεμένη λίστα.
Ποια είναι δάσος δεν κρατά πολύ καλά το ταξινομηθεί για μας.
Και τελικά, έχουμε rmforest και, όπως ήταν αναμενόμενο, έχουμε rmtree ονομάζεται εκεί.
>> Κοιτάζοντας τον κώδικα της διανομής μέχρι στιγμής, huffile.c ήταν πιθανώς κατά πολύ το πιο δύσκολο να κατανοήσουμε,
ενώ τα άλλα αρχεία που οι ίδιοι ήταν αρκετά απλό να ακολουθήσει.
Με τις γνώσεις μας και των δεικτών συνδεδεμένες λίστες και τέτοια,
ήμασταν σε θέση να ακολουθήσουν αρκετά καλά.
Αλλά το μόνο που χρειάζεται πραγματικά να βεβαιωθείτε ότι έχουμε κατανοήσει πλήρως είναι τα. H αρχείων
γιατί θα πρέπει να ζητούν αυτές τις λειτουργίες, που ασχολούνται με αυτές τις τιμές επιστροφής,
ώστε να βεβαιωθείτε ότι έχετε κατανοήσει πλήρως τι ενέργειες πρόκειται να εκτελεστεί
κάθε φορά που θα καλέσετε μία από αυτές τις λειτουργίες.
Αλλά στην πραγματικότητα μέσα από την κατανόηση ότι δεν είναι απολύτως απαραίτητο, γιατί έχουμε αυτούς. H αρχεία.
Έχουμε 2 ακόμη αρχεία που έχουν απομείνει στον κώδικα της διανομής μας.
>> Ας ρίξουμε μια ματιά σε χωματερή.
Dump από σχόλιο του εδώ παίρνει ένα Huffman-συμπιεσμένο αρχείο
και στη συνέχεια μεταφράζεται και απορρίπτει όλες του περιεχομένου της έξω.
Εδώ βλέπουμε ότι σας καλεί hfopen.
Αυτό είναι το είδος του κατοπτρισμού σε αρχείο εισόδου * = fopen,
και στη συνέχεια θα περάσει στην πληροφορία.
Είναι σχεδόν πανομοιότυπες, με εξαίρεση αντί για ένα αρχείο * είστε περνώντας σε ένα Huffile?
αντί της fopen είστε περνώντας hfopen.
Εδώ διαβάζουμε στην κεφαλίδα πρώτη, η οποία είναι είδος παρόμοιο με τον τρόπο που διαβάζουμε στην κεφαλίδα
για ένα αρχείο bitmap.
Αυτό που κάνουμε εδώ είναι ο έλεγχος για να δούμε αν οι πληροφορίες κεφαλίδας
περιέχει τον σωστό αριθμό μαγεία που δείχνει ότι πρόκειται για ένα πραγματικό αρχείο Huff,
τότε όλα αυτά τα ελέγχους για να βεβαιωθείτε ότι το αρχείο που είναι ανοιχτό ένα πραγματικό huffed αρχείο ή όχι.
Αυτό που κάνει είναι να εξάγει τις συχνότητες όλων των συμβόλων που μπορούμε να δούμε
εντός ενός τερματικού σε μία γραφική πίνακα.
Αυτό το μέρος πρόκειται να είναι χρήσιμα.
Έχει λίγο και διαβάζει σιγά-σιγά στη μεταβλητή λίγο και στη συνέχεια να εκτυπώνει.
Έτσι, αν ήταν να καλέσει την hth.bin χωματερή, η οποία είναι το αποτέλεσμα της huffing ένα αρχείο
χρησιμοποιώντας τη λύση του προσωπικού, θα έπαιρνα αυτό.
Είναι έξοδο όλων αυτών των χαρακτήρων και στη συνέχεια, βάζοντας τη συχνότητα με την οποία εμφανίζονται.
Αν κοιτάξουμε, οι περισσότεροι από αυτούς είναι 0s εκτός από αυτό: H, το οποίο εμφανίζεται δύο φορές,
Τ και στη συνέχεια, η οποία εμφανίζεται μία φορά.
Και τότε εδώ έχουμε το πραγματικό μήνυμα σε 0s και 1s.
Αν κοιτάξουμε hth.txt, η οποία είναι κατά πάσα πιθανότητα το αρχικό μήνυμα που huffed,
περιμένουμε να δούμε κάποια Hs και Ts εκεί.
Συγκεκριμένα, περιμένουμε να δούμε μόνο 1 και 2 Τ Hs.
Εδώ είμαστε σε hth.txt. Έχει πράγματι HTH.
Συμπεριλαμβάνεται εκεί, αν και δεν μπορούμε να το δούμε, είναι ένα χαρακτήρα νέας γραμμής.
Το αρχείο hth.bin Huff είναι κωδικοποιούν επίσης το χαρακτήρα νέας γραμμής, καθώς και.
Εδώ επειδή ξέρουμε ότι η σειρά είναι HTH και στη συνέχεια νέας γραμμής,
μπορούμε να δούμε ότι κατά πάσα πιθανότητα η H εκπροσωπείται από ένα μόνο 1
και στη συνέχεια το Τ είναι πιθανώς 01 και στη συνέχεια το επόμενο H είναι 1, καθώς
και στη συνέχεια, έχουμε μια νέα γραμμή υποδεικνύεται από δύο 0s.
Cool.
>> Και τελικά, επειδή έχουμε να κάνουμε με πολλαπλά. Και γ. Αρχεία h,
θα πάμε να έχουν ένα αρκετά πολύπλοκο επιχείρημα για τον compiler,
και έτσι εδώ έχουμε ένα Makefile που κάνει χωματερή για εσάς.
Αλλά στην πραγματικότητα, θα πρέπει να πάτε για να προβεί στη δική puff.c αρχείο σας.
Το Makefile κάνει πραγματικά δεν ασχολούνται με την παραγωγή puff.c για εσάς.
Φεύγουμε ότι μέχρι να μπορείτε να επεξεργαστείτε το Makefile.
Όταν εισάγετε μια εντολή, όπως κάνουν όλοι, για παράδειγμα, θα κάνει όλα αυτά για εσάς.
Μη διστάσετε να δούμε τα παραδείγματα του Makefile από το παρελθόν PSET
καθώς και να πάει μακριά από αυτό το σημείο για να δείτε πώς μπορείτε να είναι σε θέση να κάνει το αρχείο σας Puff
με την επεξεργασία αυτή Makefile.
Αυτό είναι γι 'αυτό τον κωδικό για τη διανομή μας.
>> Μόλις έχουμε πάρει μέσα από αυτό, τότε εδώ είναι ακριβώς μια άλλη υπενθύμιση
για το πώς θα πάμε να ασχολούνται με τους κόμβους Huffman.
Εμείς δεν πρόκειται να καλώντας τους κόμβους πια? Θα πάμε να τους καλεί τα δέντρα
όπου θα πάμε για να εκπροσωπεί τους σύμβολο με μια χαρα,
συχνότητά τους, ο αριθμός των περιστατικών, με έναν ακέραιο αριθμό.
Είμαστε χρησιμοποιώντας ότι επειδή είναι πιο ακριβή από ό, τι ένα πλωτήρα.
Και τότε έχουμε ένα άλλο δείκτη στο αριστερό παιδί, καθώς και το δικαίωμα του παιδιού.
Ένα δάσος, όπως είδαμε, είναι απλά μια συνδεδεμένη λίστα των δέντρων.
Τελικά, όταν είμαστε δημιουργία Huff αρχείο μας,
θέλουμε δάσος μας να περιέχει μόνο 1 δέντρο -
1 δέντρο, 1 ρίζα με πολλά παιδιά.
Νωρίτερα, όταν κάναμε ακριβώς Huffman δέντρα μας,
ξεκινήσαμε από την τοποθέτηση όλων των κόμβων στην οθόνη μας
και λέγοντας ότι θα πάμε να έχουν αυτούς τους κόμβους,
τελικά θα πάμε να είναι τα φύλλα, και αυτό είναι το σύμβολο τους, αυτή είναι η συχνότητά τους.
Το δάσος μας αν έχουμε μόλις 3 γράμματα, αυτό είναι ένα δάσος από 3 δέντρων.
Και τότε, όπως πάμε, όταν θα προστεθεί το πρώτο γονέα,
κάναμε ένα δάσος από 2 δέντρα.
Έχουμε διαγράψει 2 από αυτά τα παιδιά από το δάσος μας και στη συνέχεια το αντικατέστησε με έναν κόμβο γονέα
που είχε τα 2 κόμβοι ως παιδιά.
Και τελικά, το τελευταίο βήμα μας με την παραγωγή μας παράδειγμα με την As, Β, και Cs
θα ήταν να κάνει την τελική μητρική εταιρεία,
και έτσι στη συνέχεια, που θα φέρει συνολικό αριθμό των δέντρων μας στο δάσος με 1.
Μήπως όλοι να δούμε πώς θα ξεκινούν με πολλά δέντρα στο δάσος σας
και καταλήγουν με 1; Εντάξει. Cool.
>> Τι πρέπει να κάνουμε για Puff;
Αυτό που πρέπει να κάνουμε είναι να διασφαλίσουμε ότι, όπως πάντα, μας δίνουν το σωστό τύπο της εισόδου
έτσι ώστε να μπορεί να τρέξει πραγματικά το πρόγραμμα.
Στην περίπτωση αυτή, από όπου και αν πρόκειται να μας δοθεί μετά το πρώτο τους επιχείρημα της γραμμής εντολών
2 περισσότερα: το αρχείο που θέλουμε να αποσυμπιέσει και η έξοδος του αποσυμπιεσμένο αρχείο.
Αλλά από τη στιγμή μπορούμε να διασφαλίσουμε ότι θα μας περάσει στη σωστή ποσότητα των αξιών,
θέλουμε να εξασφαλίσουμε ότι η είσοδος είναι ένα αρχείο Huff ή όχι.
Και στη συνέχεια, όταν εγγυόμαστε ότι είναι ένα αρχείο Huff, τότε θέλουμε να οικοδομήσουμε δέντρο μας,
δημιουργήσει το δέντρο έτσι ώστε να ταιριάζει με το δέντρο ότι το άτομο που έστειλε το μήνυμα χτίστηκε.
Στη συνέχεια, μετά χτίζουμε το δέντρο, τότε μπορούμε να ασχοληθούμε με το 0s και 1s που πέρασε,
ακολουθούν τα κράτη κατά μήκος δέντρο μας, επειδή είναι πανομοιότυπα,
και κατόπιν να γράψετε αυτό το μήνυμα έξω, να ερμηνεύσει τα κομμάτια πίσω σε χαρακτήρες.
Και τότε, στο τέλος, επειδή έχουμε να κάνουμε με δείκτες εδώ,
Θέλουμε να διασφαλίσουμε ότι δεν έχουμε κανένα διαρροές μνήμης
και ότι τα πάντα δωρεάν.
>> Διασφάλιση της ορθής χρήσης είναι παλιό καπέλο για μας από τώρα.
Παίρνουμε σε μια είσοδο, η οποία πρόκειται να είναι το όνομα του αρχείου για να φουσκώσουν,
και στη συνέχεια ορίζουμε μια έξοδο,
έτσι το όνομα του αρχείου για το διογκωμένο εξόδου, που θα είναι το αρχείο κειμένου.
Αυτό είναι χρήση. Και τώρα θέλουμε να εξασφαλίσουμε ότι η είσοδος huffed ή όχι.
Σκεπτόμενος πίσω, υπήρχε κάτι στον κώδικα της διανομής που θα μπορούσε να μας βοηθήσει
με την κατανόηση εάν ένα αρχείο huffed ή όχι;
Υπήρχε πληροφορίες σχετικά με την huffile.c Huffeader.
Γνωρίζουμε ότι κάθε αρχείο έχει ένα Huff Huffeader που συνδέονται με αυτό με ένα μαγικό αριθμό
καθώς και μια σειρά από τις συχνότητες για κάθε σύμβολο
καθώς και ένα άθροισμα ελέγχου.
Γνωρίζουμε ότι, αλλά έλαβε επίσης μια ματιά στο dump.c,
στην οποία είχε την ανάγνωση σε ένα αρχείο Huff.
Και έτσι για να το κάνουμε αυτό, θα έπρεπε να ελέγξει αν όντως ήταν huffed ή όχι.
Έτσι, ίσως θα μπορούσαμε να χρησιμοποιήσουμε dump.c ως δομή για puff.c. μας
Επιστροφή στην PSET 4 όταν είχαμε την copy.c αρχείο που αντιγράφεται σε τριάδες RGB
και θα ερμηνεύεται ότι για Whodunit και μεγέθους,
ομοίως, τι θα μπορούσατε να κάνετε είναι να εκτελέσετε την εντολή ακριβώς όπως cp dump.c puff.c
και η χρήση ορισμένων από τον κωδικό εκεί.
Ωστόσο, δεν πρόκειται να είναι τόσο απλή μιας διαδικασίας
για τη μετάφραση dump.c σας σε puff.c,
αλλά τουλάχιστον σας δίνει κάπου για να ξεκινήσει
σχετικά με τον τρόπο εξασφαλίζεται ότι η είσοδος είναι στην πραγματικότητα ή όχι huffed
καθώς και μερικά άλλα πράγματα.
Έχουμε εξασφαλίσει την ορθή χρήση και εξασφαλίζεται ότι η είσοδος huffed.
Κάθε φορά που κάναμε ότι κάναμε σωστή έλεγχο σφαλμάτων μας,
επιστρέφοντας έτσι και το κλείσιμο της λειτουργίας αν κάποια βλάβη, αν υπάρχει κάποιο πρόβλημα.
>> Τώρα, αυτό που θέλουμε να κάνουμε είναι να οικοδομήσουμε την πραγματική δέντρο.
Αν κοιτάξουμε το δάσος, υπάρχουν 2 κύριες λειτουργίες
ότι θα πάμε να θέλουν να γίνουν πολύ εξοικειωμένοι με.
Υπάρχει η Boolean λειτουργία φυτό ότι τα φυτά μη-0 δέντρο μέσα στο δάσος συχνότητα μας.
Και έτσι εκεί θα περάσει σε ένα δείκτη σε ένα δάσος και ένα δείκτη σε ένα δέντρο.
Γρήγορη ερώτηση: Πόσα δάση θα έχετε όταν είστε οικοδόμηση ενός δέντρου Huffman;
Δάσος μας είναι σαν καμβά μας, έτσι δεν είναι;
Έτσι είμαστε μόνο πρόκειται να έχουν 1 δάσος, αλλά θα πάμε να έχουν πολλά δέντρα.
Έτσι προτού να καλέσετε φυτό, είστε κατά πάσα πιθανότητα πρόκειται να θέλουν να κάνουν δάσος σας.
Υπάρχει μια εντολή για ότι αν κοιτάξετε σε forest.h σχετικά με το πώς μπορείτε να κάνετε ένα δάσος.
Μπορείτε να φυτέψει ένα δέντρο. Ξέρουμε πώς να το κάνουμε αυτό.
Και τότε μπορείτε να επιλέξετε επίσης ένα δέντρο από το δάσος,
αφαιρώντας ένα δέντρο με το χαμηλότερο βάρος και σας δίνει το δείκτη σε αυτό.
Ανακαλώντας στη μνήμη όταν κάναμε εμείς οι ίδιοι τα παραδείγματα,
όταν είχαμε το τράβηγμα έξω, εμείς απλά προστέθηκε μόλις τις συνδέσεις.
Αλλά εδώ, αντί της προσθήκης μόνο τις συνδέσεις,
σκεφτούμε περισσότερο ως είστε αφαίρεση 2 των εν λόγω κόμβων και στη συνέχεια, αντικαθιστώντας το με ένα άλλο.
Για να εκφράσει ότι από την άποψη της να πάρει και τη φύτευση,
είστε picking 2 δέντρα και στη συνέχεια ένα άλλο δέντρο φύτευση
που έχει αυτά τα 2 δέντρα που πήρε ως παιδιά.
Για να οικοδομήσουμε δέντρο Huffman, μπορείτε να διαβάσετε τα σύμβολα και τις συχνότητες, προκειμένου
επειδή η Huffeader ότι δίνει σε εσάς,
σας δίνει μια σειρά από τις συχνότητες.
Έτσι, μπορείτε να προχωρήσετε και απλά αγνοούν οτιδήποτε με το 0 σε αυτό
γιατί δεν θέλουμε 256 φύλλα στο τέλος του.
Θέλουμε μόνο τον αριθμό των φύλλων που είναι χαρακτήρες
που ήδη χρησιμοποιούνται στο αρχείο.
Μπορείτε να διαβάζονται αυτών των συμβόλων, και κάθε ένα από αυτά τα σύμβολα που έχουν μη-0 συχνότητες,
αυτά πρόκειται να είναι δέντρα.
Τι μπορείτε να κάνετε είναι κάθε φορά που διάβασα σε ένα μη-0 σύμβολο συχνότητα,
μπορείτε να φυτέψετε εκείνο το δέντρο στο δάσος.
Μόλις φυτέψετε τα δέντρα στο δάσος, μπορείτε να συμμετάσχετε σε αυτά τα δέντρα ως αδέλφια,
έτσι πηγαίνει πίσω από τη φύτευση και να πάρει όπου θα πάρει 2 και, στη συνέχεια φυτών 1,
όπου το 1 φυτό που είναι η μητρική των 2 παιδιά που διάλεξε.
Έτσι, τότε το τελικό αποτέλεσμα σας πρόκειται να είναι ένα δέντρο σε δάσος σας.
Αυτό είναι το πώς θα οικοδομήσουμε το δέντρο σας.
>> Υπάρχουν πολλά πράγματα που θα μπορούσε να πάει στραβά εδώ
επειδή έχουμε να κάνουμε με την παραγωγή νέων δέντρων και ασχολούνται με δείκτες και τέτοια πράγματα.
Πριν, όταν είχαμε να κάνουμε με δείκτες,
κάθε φορά που malloc'd θέλαμε να βεβαιωθείτε ότι δεν επιστρέψει μας τιμή NULL δείκτη.
Έτσι, σε πολλά βήματα σε αυτή τη διαδικασία υπάρχουν θα είναι αρκετές περιπτώσεις
όπου το πρόγραμμά σας θα μπορούσε να αποτύχει.
Τι θέλετε να κάνετε είναι να θέλετε να βεβαιωθείτε ότι έχετε χειριστεί αυτά τα σφάλματα,
και στο spec λέει να τα χειριστεί με χάρη,
έτσι ήθελα να εκτυπώσετε ένα μήνυμα στον χρήστη λέγοντάς τους οποίους το πρόγραμμα θα πρέπει να σταματήσουν
και στη συνέχεια κλείστε το αμέσως.
Για να το κάνετε αυτό το λάθος χειρισμό, να θυμάστε ότι θέλετε να ελέγξετε
κάθε φορά που θα μπορούσε να υπάρξει μια αποτυχία.
Κάθε φορά που θέλετε να κάνετε ένα νέο δείκτη
θέλετε να βεβαιωθείτε ότι αυτό είναι επιτυχής.
Πριν από αυτό που χρησιμοποιείται για να κάνετε είναι να κάνετε ένα νέο δείκτη και το malloc,
και στη συνέχεια θα ελέγξει κατά πόσο ότι ο δείκτης είναι NULL.
Έτσι, υπάρχουν πρόκειται να είναι μερικές περιπτώσεις όπου το μόνο που μπορούμε να το κάνουμε,
αλλά μερικές φορές είστε πραγματικά καλώντας μια συνάρτηση
και εντός αυτής της λειτουργίας, αυτό είναι αυτό που κάνει το mallocing.
Σε αυτή την περίπτωση, αν κοιτάξουμε πίσω σε μερικές από τις λειτουργίες μέσα στον κώδικα,
ορισμένες από αυτές είναι Boolean λειτουργίες.
Στην αφηρημένη περίπτωση που έχουμε μια Boolean συνάρτηση που ονομάζεται foo,
βασικά, μπορούμε να υποθέσουμε ότι εκτός από να κάνει ό, τι κάνει foo,
δεδομένου ότι είναι μια Boolean λειτουργία, επιστρέφει αληθής ή ψευδής -
αλήθεια αν είναι επιτυχής, αν όχι ψευδείς.
Έτσι, θέλουμε να ελέγξουμε αν η τιμή επιστροφής της foo είναι αληθείς ή ψευδείς.
Αν είναι ψευδής, αυτό σημαίνει ότι θα πάμε να θέλετε να εκτυπώσετε κάποιο είδος του μηνύματος
και στη συνέχεια κλείστε το πρόγραμμα.
Αυτό που θέλουμε να κάνουμε είναι να ελέγξετε την τιμή επιστροφής της foo.
Αν foo επιστρέφει ψευδής, τότε ξέρουμε ότι αντιμετωπίζουν κάποιο είδος του σφάλματος
και θα πρέπει να εγκαταλείψει το πρόγραμμά μας.
Ένας τρόπος να γίνει αυτό είναι να έχουν μια κατάσταση όπου η πραγματική λειτουργία είναι η ίδια η κατάστασή σας.
Πείτε foo παίρνει το x.
Μπορούμε να έχουμε ως προϋπόθεση, αν (foo (x)).
Βασικά, αυτό σημαίνει ότι αν στο τέλος της εκτέλεσης foo επιστρέφει αλήθεια,
τότε μπορούμε να το κάνουμε αυτό, επειδή η λειτουργία πρέπει να αξιολογήσει foo
προκειμένου να αξιολογηθεί η όλη κατάσταση.
Έτσι, τότε αυτό είναι το πώς μπορείτε να κάνετε κάτι, αν η συνάρτηση επιστρέφει true και είναι επιτυχής.
Αλλά όταν είσαι έλεγχο σφαλμάτων, το μόνο που θέλουν να σταματήσουν το κάπνισμα, εάν η λειτουργία σας επιστρέφει false.
Τι θα μπορούσατε να κάνετε είναι απλά να προσθέσω ένα == ψευδείς ή απλά προσθέστε μια έκρηξη μπροστά από το
και στη συνέχεια, αν έχετε (! foo).
Μέσα σε αυτό το σώμα αυτής της κατάστασης θα έχετε όλη την αντιμετώπιση των λαθών,
έτσι όπως, "Δεν μπόρεσα να δημιουργήσω αυτό το δέντρο" και στη συνέχεια επιστρέφουν 1 ή κάτι τέτοιο.
Αυτό που κάνει, όμως, είναι ότι ακόμα κι αν foo επέστρεψε ψευδώς -
Πείτε foo επιστρέφει true.
Τότε δεν χρειάζεται να καλέσετε πάλι foo. Αυτό είναι μια κοινή παρερμηνεία.
Επειδή ήταν στην κατάστασή σας, είναι ήδη αξιολογηθεί,
έτσι ώστε να έχετε ήδη το αποτέλεσμα αν χρησιμοποιείτε κάνει δέντρο ή κάτι τέτοιο
ή φυτό ή επιλογή ή κάτι τέτοιο.
Έχει ήδη ότι η αξία. Είναι ήδη εκτελεστεί.
Γι 'αυτό είναι χρήσιμο να χρησιμοποιήσετε Boolean λειτουργίες όπως η κατάσταση
γιατί αν δεν έχετε εκτελέσει πραγματικά το σώμα του βρόχου,
εκτελεί τη λειτουργία ούτως ή άλλως.
>> Δεύτερος μας στο τελευταίο βήμα είναι η σύνταξη του μηνύματος στο αρχείο.
Όταν χτίζουμε το δέντρο Huffman, στη συνέχεια, γράφοντας το μήνυμα στο αρχείο είναι αρκετά απλή.
Είναι αρκετά εύκολο τώρα να ακολουθήσει ακριβώς την 0s και 1s.
Και έτσι, κατά συνθήκη, γνωρίζουμε ότι σε ένα δέντρο Huffman δείχνουν τα αριστερά 0s
και το 1s δείχνουν δεξιά.
Έτσι λοιπόν, αν μπορείτε να διαβάσετε σε λίγο-λίγο, κάθε φορά που παίρνετε ένα 0
θα ακολουθήσει το αριστερό κλάδο, και στη συνέχεια, κάθε φορά που θα διαβάσετε σε 1
πρόκειται να ακολουθήσει το σωστό κλάδο.
Και τότε θα πάμε για να συνεχιστεί μέχρι να χτυπήσει ένα φύλλο
γιατί τα φύλλα πρόκειται να είναι στο τέλος των κλαδιών.
Πώς μπορούμε να πούμε αν έχουμε χτυπήσει ένα φύλλο ή όχι;
Το είπαμε πριν.
[Φοιτητής] Αν οι δείκτες είναι NULL. Ναι >>.
Μπορούμε να πούμε αν έχουμε χτυπήσει ένα φύλλο, εάν οι δείκτες τόσο για το αριστερό και το δεξί δέντρα είναι NULL.
Τέλεια.
Ξέρουμε ότι θέλουμε να διαβάζονται σιγά-σιγά σε Huff αρχείο μας.
Όπως είδαμε πριν σε dump.c, τι έκαναν είναι να διαβάσετε σε λίγο-λίγο στο αρχείο Huff
και μόλις εκτυπωθούν τι ήταν αυτά τα κομμάτια.
Εμείς δεν πρόκειται να το κάνουμε αυτό. Εμείς πάμε για να κάνει κάτι που είναι λίγο πιο περίπλοκη.
Αλλά αυτό που μπορούμε να κάνουμε είναι που μπορούμε να πάρουμε εκείνο το κομμάτι του κώδικα που διαβάζει μέσα στο κομμάτι.
Εδώ έχουμε το ακέραιο κομμάτι που αντιπροσωπεύει το τρέχον κομμάτι που βρίσκεστε.
Αυτό φροντίζει για την επανάληψη όλων των bits στο αρχείο μέχρι να χτυπήσει το τέλος του αρχείου.
Με βάση αυτό, τότε θα πάμε να θέλουν να έχουν κάποιο είδος του iterator
να διασχίσει το δέντρο σας.
Και στη συνέχεια με βάση το αν το bit είναι 0 ή 1,
θα πάμε να θέλουν να μετακινηθούν είτε ότι iterator προς τα αριστερά ή να το μετακινήσετε προς τα δεξιά
σε όλη τη διαδρομή μέχρι να χτυπήσει ένα φύλλο, έτσι σε όλη τη διαδρομή μέχρι τον κόμβο ότι είστε σε
δεν δείχνουν καμία περισσότερους κόμβους.
Γιατί μπορούμε να το κάνουμε αυτό με ένα αρχείο αλλά δεν Huffman κώδικα Μορς;
Επειδή σε κώδικα Μορς υπάρχει ένα κομμάτι της ασάφειας.
Θα μπορούσε να είναι όπως, OH περιμένει, έχουμε χτυπήσει ένα γράμμα στο δρόμο, οπότε ίσως αυτό είναι η επιστολή μας,
ενώ αν συνεχιστεί μόλις λίγο περισσότερο, τότε θα είχαμε χτυπήσει ένα άλλο γράμμα.
Αλλά αυτό δεν πρόκειται να συμβεί στην κωδικοποίηση Huffman,
έτσι μπορούμε να είμαστε ήσυχοι ότι ο μόνος τρόπος που θα πάμε για να χτυπήσει ένα χαρακτήρα
αν είναι αριστερά και δεξιά στα παιδιά ότι ο κόμβος είναι NULL.
>> Τέλος, θέλουμε να ελευθερώσει όλους της μνήμης μας.
Θέλουμε τόσο κοντά το αρχείο Huff ότι έχουμε ήδη ασχολούνται με
καθώς και αφαιρέστε όλα τα δέντρα στο δάσος μας.
Με βάση την εφαρμογή σας, είστε κατά πάσα πιθανότητα θα θέλετε να καλέσετε αφαιρέσετε δάσος
αντί πραγματικά να περάσει από όλα τα δέντρα σας.
Αλλά αν γίνει οποιαδήποτε προσωρινή δέντρα, θα θελήσετε να ελευθερώσετε αυτό.
Ξέρετε τον κωδικό σας καλύτερα, ώστε να γνωρίζουν πού είστε κατανομή μνήμης.
Και έτσι αν πας σε, ξεκινήστε με τον έλεγχο, ακόμη και για f'ing malloc,
βλέπουμε κάθε φορά που malloc και να διασφαλίσουμε ότι θα απελευθερώσει όλα αυτά
αλλά στη συνέχεια απλά να περάσει τον κωδικό σας,
κατανόηση που μπορεί να έχουν κατανεμηθεί μνήμη.
Συνήθως θα μπορούσε απλώς να πω, "Στο τέλος του αρχείου είμαι απλώς πρόκειται να αφαιρέσετε δάσος για δάσος μου"
έτσι σαφές ότι η μνήμη βασικά, δωρεάν ότι,
»Και στη συνέχεια, είμαι επίσης πρόκειται να κλείσει το αρχείο και στη συνέχεια, το πρόγραμμά μου πρόκειται να σταματήσουν το κάπνισμα."
Όμως, είναι ότι η μόνη φορά που κλείνει το πρόγραμμά σας;
Όχι, επειδή μερικές φορές μπορεί να υπήρξαν ένα σφάλμα που συνέβη.
Ίσως θα μπορούσαμε να ανοίξετε ένα αρχείο ή δεν μπορούσε να κάνει άλλο ένα δέντρο
ή κάποιο είδος του λάθους που συνέβη κατά τη διαδικασία κατανομής της μνήμης και έτσι επέστρεψε NULL.
Ένα σφάλμα συνέβη και τότε θα επιστρέψει και σταματήσουν το κάπνισμα.
Έτσι, τότε θα θέλετε να βεβαιωθείτε ότι κάθε δυνατό χρόνο ότι το πρόγραμμά σας μπορεί να σταματήσουν το κάπνισμα,
θέλετε να ελευθερώσετε μνήμη του όλες σας εκεί.
Δεν είναι ακριβώς πρόκειται να είναι στο τέλος της κύριας λειτουργίας που θα σταματήσουν τον κωδικό σας.
Θέλετε να κοιτάξουμε πίσω σε κάθε περίπτωση ότι ο κωδικός σας ενδεχομένως να μπορεί να επιστρέψει πρόωρα
και στη συνέχεια, χωρίς οποιαδήποτε μνήμη νόημα.
Πέστε ότι είχε ζητήσει να κάνει δάσος και αυτό επέστρεψε ψευδείς.
Τότε μάλλον δεν θα χρειαστεί να αφαιρέσετε δάσος σας
γιατί δεν έχετε ακόμα ένα δάσος.
Όμως, σε κάθε σημείο του κώδικα όπου μπορεί να επιστρέψει πρόωρα
θέλετε να βεβαιωθείτε ότι έχετε απελευθερώσει κάθε δυνατή μνήμη.
>> Έτσι, όταν έχουμε να κάνουμε με την απελευθέρωση μνήμης και έχει πιθανές διαρροές,
θέλουμε όχι μόνο να χρησιμοποιήσει την κρίση μας και τη λογική μας
αλλά επίσης να χρησιμοποιήσετε Valgrind να καθοριστεί αν έχουμε απελευθερωθεί από όλα τη μνήμη μας σωστά ή όχι.
Μπορείτε να εκτελέσετε είτε Valgrind για Puff και στη συνέχεια θα πρέπει να περάσει επίσης
το σωστό αριθμό της γραμμής εντολών επιχειρήματα για να Valgrind.
Μπορείτε να εκτελέσετε ότι, αλλά η έξοδος είναι λίγο δυσνόητη.
Έχουμε πάρει ένα κομμάτι που χρησιμοποιείται σε αυτό με Ορθογράφος, αλλά χρειαζόμαστε ακόμα λίγο περισσότερη βοήθεια,
έτσι τρέχει στη συνέχεια με λίγες περισσότερες σημαίες, όπως η διαρροή-check = πλήρης,
που πιθανότατα θα μας δώσει λίγο περισσότερο χρήσιμες για έξοδο Valgrind.
>> Στη συνέχεια, μια άλλη χρήσιμη συμβουλή όταν debugging είναι η εντολή diff.
Μπορείτε να αποκτήσετε πρόσβαση υλοποίηση του προσωπικού του Huff, ότι τρέχει σε ένα αρχείο κειμένου,
και στη συνέχεια εξάγει σε ένα δυαδικό αρχείο, ένα δυαδικό αρχείο Huff, να είναι συγκεκριμένα.
Στη συνέχεια, αν έχετε δικό σας φούσκα σε αυτό το δυαδικό αρχείο,
στη συνέχεια, στην ιδανική περίπτωση, εξερχόμενο αρχείο κειμένου σας πρόκειται να είναι πανομοιότυπα
με το αρχικό που έχετε περάσει μέσα
Εδώ είμαι με τη χρήση hth.txt ως παράδειγμα, και αυτό είναι το ένα μίλησε για το spec σας.
Αυτό είναι κυριολεκτικά μόνο HTH και στη συνέχεια μια νέα γραμμή.
Αλλά σίγουρα αισθάνονται ελεύθεροι και είστε σίγουρα ενθαρρύνονται να χρησιμοποιούν περισσότερο τα παραδείγματα
για το αρχείο κειμένου σας.
>> Μπορείτε να πάρετε ακόμη και έναν πυροβολισμό στο ίσως συμπίεση και αποσυμπίεση, στη συνέχεια
μερικά από τα αρχεία που χρησιμοποιούνται σε Ορθογράφος, όπως Πόλεμος και Ειρήνη
ή Jane Austen ή κάτι τέτοιο - που θα είναι είδος δροσερό - ή Austin Powers,
είδος του που ασχολούνται με τα μεγαλύτερα αρχεία, επειδή δεν θα έρθει κάτω για να
αν χρησιμοποιηθεί το επόμενο εργαλείο εδώ, ls-l.
Έχουμε συνηθίσει να ls, το οποίο απαριθμεί βασικά όλα τα περιεχόμενα σε τρέχοντα κατάλογο μας.
Περνώντας στη σημαία-l εμφανίζει πραγματικά το μέγεθος αυτών των αρχείων.
Αν πάτε μέσω του spec PSET, αυτό που πραγματικά περπατά μέσω της δημιουργίας το δυαδικό αρχείο,
του huffing αυτό, και θα δείτε ότι για πολύ μικρά αρχεία
το κόστος χώρο της συμπίεσης και την μετάφραση όλων των πληροφοριών
από όλες τις συχνότητες και τα πράγματα όπως ότι είναι μεγαλύτερο από το πραγματικό όφελος
συμπιέσεως του αρχείου στην πρώτη θέση.
Αλλά αν το τρέξετε σε κάποια πλέον αρχεία κειμένου, τότε μπορείτε να δείτε ότι αρχίζετε να παίρνετε κάποιο όφελος
συμπίεση σε αυτά τα αρχεία.
>> Και τελικά, έχουμε παλιά GDB μας φίλε, το οποίο πρόκειται σίγουρα να έρθει σε πρακτικό πάρα πολύ.
>> Έχουμε απορίες σχετικά με Huff δέντρα ή τη διαδικασία ίσως καταστεί τα δέντρα
ή οποιεσδήποτε άλλες ερωτήσεις σχετικά με Puff Huff'n;
Εντάξει. Θα μείνω γύρω για λίγο.
>> Σας ευχαριστώ όλους. Αυτό ήταν Walkthrough 6. Και καλή τύχη.
>> [CS50.TV]