logo

Cấu trúc dữ liệu 2005 P5

Tham khảo tài liệu 'cấu trúc dữ liệu 2005 p5', công nghệ thông tin, cơ sở dữ liệu phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả
Chöông 5 – Chuoãi kyù töï Chöông 5 – CHUOÃI KYÙ TÖÏ Trong phaàn naøy chuùng ta seõ hieän thöïc moät lôùp bieåu dieãn moät chuoãi noái tieáp caùc kyù töï. Ví duï ta coù caùc chuoãi kyù töï: “Ñaây laø moät chuoãi kyù töï”, “Teân?” trong ñoù caëp daáu “ “ khoâng phaûi laø boä phaän cuûa chuoãi kyù töï. Moät chuoãi kyù töï roãng ñöôïc kyù hieäu “”. Chuoãi kyù töï cuõng laø moät danh saùch caùc kyù töï. Tuy nhieân, caùc taùc vuï treân chuoãi kyù töï coù hôi ñaëc bieät vaø khaùc vôùi caùc taùc vuï treân moät danh saùch tröøu töôïng maø chuùng ta ñaõ ñònh nghóa, chuùng ta seõ khoâng daãn xuaát lôùp chuoãi kyù töï töø moät lôùp List naøo tröôùc ñaây. Trong caùc taùc vuï thao taùc treân chuoãi kyù töï, taùc vuï tìm kieám laø khoù khaên nhaát. Chuùng ta seõ tìm hieåu hai giaûi thuaät tìm kieám vaøo cuoái chöông naøy. Trong phaàn ñaàu, chuùng ta ñaëc bieät quan taâm ñeán vieäc khaéc phuïc tính thieáu an toaøn cuûa chuoãi kyù töï trong ngoân ngöõ C maø ña soá ngöôøi laäp trình ñaõ töøng söû duïng. Do ñoù phaàn trình baøy tieáp theo ñaây lieân quan chaët cheõ ñeán ngoân ngöõ C vaø C++. 5.1. Chuoãi kyù töï trong C vaø trong C++ Ngoân ngöõ C++ cung caáp hai caùch hieän thöïc chuoãi kyù töï. Caùch nguyeân thuûy laø hieän thöïc string cuûa C. Gioáng nhö nhöõng phaàn khaùc, hieän thöïc string cuûa ngoân ngöõ C coù theå chaïy trong moïi hieän thöïc cuûa C++. Chuùng ta seõ goïi caùc ñoái töôïng string cung caáp bôûi C laø C-String. C-String theå hieän caû caùc ñieåm maïnh vaø caû caùc ñieåm yeáu cuûa ngoân ngöõ C: chuùng raát phoå bieán, raát hieäu quaû nhöng cuõng raát hay bò duøng sai. C-String lieân quan ñeán moät loaït caùc taäp quaùn maø chuùng ta seõ xem laïi döôùi ñaây. Moät C-String coù kieåu char*. Do ñoù, moät C-String tham chieáu ñeán moät ñòa chæ trong boä nhôù; ñòa chæ naøy laø ñieåm baét ñaàu cuûa taäp caùc bytes chöùa caùc kyù töï trong chuoãi kyù töï. Vuøng nhôù chieám bôûi moät chuoãi kyù töï phaûi ñöôïc keát thuùc baèng moät kyù töï ñaëc bieät ‘\0’. Trình bieân dòch khoâng theå kieåm tra giuùp quy ñònh naøy, söï thieáu soùt seõ gaây loãi thôøi gian chaïy. Noùi caùch khaùc, C-String khoâng coù tính ñoùng kín vaø thieáu an toaøn. Taäp tin chuaån chöùa thö vieän caùc haøm xöû lyù C-String. Trong caùc trình bieân dòch C++ cuõ, taäp tin naøy thöôøng coù teân laø . Caùc haøm thö vieän naøy raát tieän lôïi, hieäu quaû vaø chöùa haàu heát caùc taùc vuï treân chuoãi kyù töï maø chuùng ta caàn. Giaû söû s vaø t laø caùc C-String. Taùc vuï strlen(s) traû veà chieàu daøi cuûa s, strcmp(s,t) so saùnh töøng kyù töï cuûa s vaø t, vaø strstr(s,t) traû veà con troû tham chieáu ñeán vò trí baét ñaàu cuûa t trong s. Ngoaøi ra, trong C++ taùc vuï xuaát Chöông 5 – Chuoãi kyù töï Maëc duø hieän thöïc C-String coù nhieàu öu ñieåm tuyeät vôøi, nhöng noù cuõng coù nhöõng nhöôïc ñieåm nghieâm troïng. Thöïc vaäy, noù coù nhöõng vaán ñeà maø chuùng ta ñaõ gaëp phaûi khi nghieân cöùu CTDL ngaên xeáp lieân keát trong chöông 2 cuõng nhö caùc CTDL coù chöùa thuoäc tính con troû noùi chung. Thaät deã daøng khi ngöôøi söû duïng coù theå taïo bí danh cho chuoãi kyù töï, cuõng nhö gaây neân raùc. Trong hình 5.1, chuùng ta thaáy roõ pheùp gaùn s = t daãn ñeán caû hai vaán ñeà treân. Hình 5.1- Söï thieáu an toaøn cuûa C-String. Moät vaán ñeà khaùc cuõng thöôøng naûy sinh trong caùc öùng duïng coù söû duïng C- String. Moät C-String chöa khôûi taïo caàn ñöôïc gaùn NULL. Tuy nhieân, raát nhieàu haøm thö vieän cuûa C-String seõ gaëp söï coá trong thôøi gian chaïy khi gaëp ñoái töôïng C-String laø NULL. Chaúng haïn, leänh char* x = NULL; cout Chöông 5 – Chuoãi kyù töï 5.2. Ñaëc taû cuûa lôùp String Ñeå taïo moät hieän thöïc lôùp String an toaøn, chuùng ta ñoùng goùi C-String nhö moät thuoäc tính thaønh phaàn cuûa noù vaø ñeå thuaän tieän hôn, chuùng ta theâm moät thuoäc tính chieàu daøi cho chuoãi kyù töï. Do thuoäc tính char* laø moät con troû, chuùng ta caàn theâm caùc taùc vuï gaùn ñònh nghóa laïi (overloaded assignment), copy constructor, destructor, ñeå lôùp String cuûa chuùng ta traùnh ñöôïc caùc vaán ñeà bí danh, taïo raùc, hoaëc vieäc söû duïng ñoái töôïng maø chöa ñöôïc khôûi taïo. 5.2.1. Caùc pheùp so saùnh Vôùi moät soá öùng duïng, seõ heát söùc thuaän tieän neáu chuùng ta boå sung theâm caùc taùc vuï so saùnh , =, ==, != ñeå so saùnh töøng caëp ñoái töôïng String theo töøng kyù töï. Vì theá, lôùp String cuûa chuùng ta seõ chöùa caùc taùc vuï so saùnh ñöôïc ñònh nghóa laïi (overloaded comparison operators). 5.2.2. Moät soá constructor tieän duïng Taïo ñoái töôïng String töø moät C-String Chuùng ta seõ xaây döïng constructor vôùi thoâng soá char* cho lôùp String. Constructor naøy cung caáp moät caùch chuyeån ñoåi thuaän tieän moät ñoái töôïng C- String sang ñoái töôïng String. Vieäc chuyeån ñoåi thoâng qua caùch goïi töôøng minh nhö sau: String s(“some_string”); Trong leänh naøy, ñoái töôïng String s ñöôïc taïo ra chöùa döõ lieäu laø “some_string”. Constructor naøy ñoâi khi coøn ñöôïc goïi moät caùch khoâng töôøng minh bôûi trình bieân dòch moãi khi chöông trình caàn ñeán söï eùp kieåu (type cast) töø kieåu char* sang String. Laáy ví duï, String s; s = “some_string”; Ñeå chaïy leänh thöù hai, trình bieân dòch C++ tröôùc heát goïi constructor cuûa chuùng ta ñeå chuyeån “some_string” thaønh moät ñoái töôïng String taïm. Sau ñoù pheùp gaùn ñònh nghóa laïi cuûa String ñöôïc goïi ñeå cheùp ñoái töôïng taïm naøy vaøo s. Cuoái cuøng destructor cho ñoái töôïng taïm ñöôïc thöïc hieän. Taïo ñoái töôïng String töø moät danh saùch caùc kyù töï Töông töï, chuùng ta cuõng neân coù constructor ñeå chuyeån moät danh saùch caùc kyù töï sang moät ñoái töôïng String. Chaúng haïn, khi ñoïc moät chuoãi kyù töï töø ngöôøi söû duïng, chuùng ta neân ñoïc töøng kyù töï vaøo moät danh saùch caùc kyù töï do chöa bieát tröôùc Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 77 Chöông 5 – Chuoãi kyù töï chieàu daøi cuûa noù. Sau ñoù chuùng ta seõ chuyeån ñoåi danh saùch naøy sang moät ñoái töôïng String. Chuyeån töø moät ñoái töôïng String sang moät C-String Cuoái cuøng, neáu coù theå chuyeån ñoåi ngöôïc töø moät ñoái töôïng String sang moät ñoái töôïng C-String thì seõ raát coù lôïi cho nhöõng tröôøng hôïp string caàn ñöôïc xem laø char*. Ñoù laø nhöõng luùc chuùng ta caàn söû duïng laïi caùc haøm thö vieän cuûa C-String cho caùc ñoái töôïng String. Phöông thöùc naøy seõ ñöôïc goïi laø c_str() vaø phaûi traû veà const char* laø moät con troû tham chieáu ñeán döõ lieäu bieåu dieãn String. Phöông thöùc c_str() coù theå ñöôïc goïi nhö sau: String s = “some_String”; const char* new_s = s.c_str(); Ñieàu quan troïng ôû ñaây laø c_str() traû veà moät C-String nhö laø caùc kyù töï haèng. Chuùng ta coù theå thaáy ñöôïc söï caàn thieát naøy neáu chuùng ta xem xeùt ñeán vuøng nhôù chieám bôûi chuoãi kyù töï new_s. Vuøng nhôù naøy roõ raøng laø thuoäc ñoái töôïng cuûa lôùp String. Chuùng ta thaáy raèng lôùp String neân chòu traùch nhieäm veà vuøng nhôù naøy, vì ñieàu ñoù cho pheùp chuùng ta hieän thöïc haøm chuyeån ñoåi moät caùch hieäu quaû, ñoàng thôøi traùnh ñöôïc cho ngöôøi söû duïng khoûi phaûi chòu traùch nhieäm veà vieäc queân xoùa moät C-String ñaõ ñöôïc chuyeån ñoåi töø moät ñoái töôïng String. Do ñoù, chuùng ta khai baùo c_str() traû veà const char* ñeå ngöôøi söû duïng khoâng theå söû duïng con troû traû veà naøy maø thay ñoåi caùc kyù töï döõ lieäu ñöôïc tham chieáu ñeán, söï thay ñoåi naøy chæ thuoäc quyeàn cuûa lôùp String maø thoâi. Vôùi moät soá ít ñaëc tính ñöôïc moâ taû treân chuùng ta coù ñöôïc moät caùch xöû lyù chuoãi kyù töï voâ cuøng linh hoaït, hieäu quaû vaø an toaøn. Lôùp String cuûa chuùng ta laø moät ADT ñoùng kín hoaøn toaøn, nhöng noù cung caáp moät giao dieän thaät ñaày ñuû. Chuùng ta coù ñaëc taû lôùp String nhö sau: class String { public: String(); ~String(); String (const String ©); // copy constructor String (const char * copy); // Chuyeån ñoåi töø C-string String (List ©); // Chuyeån ñoåi töø List caùc kyù töï void operator =(const String ©); const char *c_str() const; // Chuyeån ñoåi sang C-string protected: char *entries; int length; }; Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 78 Chöông 5 – Chuoãi kyù töï bool operator ==(const String &first, const String &second); bool operator >(const String &first, const String &second); bool operator =(const String &first, const String &second); bool operator Chöông 5 – Chuoãi kyù töï caùch giaûi quyeát khaùc cuõng gaëp moät soá vaán ñeà. Caùch giaûi quyeát naøy coøn coù ñöôïc öu ñieåm laø tính hieäu quaû. Phöông thöùc c_str() traû veà con troû chæ ñeán maûng caùc kyù töï chæ coù theå ñoïc chöù khoâng theå söûa ñoåi do chuùng ta ñaõ eùp kieåu sang const char*. Tuy nhieân ngöôøi laäp trình coù theå eùp kieåu ngöôïc trôû laïi vaø gaùn vaøo moät con troû khaùc laøm phaù vôõ tính ñoùng kín cuûa döõ lieäu cuûa chuùng ta. Moät vaán ñeà nghieâm troïng hôn chính laø bí danh ñöôïc taïo bôûi phöông thöùc naøy. Chuùng ta thaáy raèng ngöôøi laäp trình neân söû duïng con troû traû veà ngay sau khi vöøa goïi phöông thöùc, neáu khoâng nhöõng gì xaûy ra seõ khoâng löôøng tröôùc ñöôïc. Laáy ví duï sau: String s = "abc"; const char *new_string = s.c_str(); s = "def"; cout Chöông 5 – Chuoãi kyù töï 5.4. Caùc taùc vuï treân String Chuùng ta seõ phaùt trieån moät soá taùc vuï laøm vieäc treân caùc ñoái töôïng String. Trong nhieàu tröôøng hôïp, caùc haøm cuûa C-String coù theå ñöôïc goïi tröïc tieáp cho caùc ñoái töôïng String ñaõ chuyeån ñoåi: String s = "some_string"; cout Chöông 5 – Chuoãi kyù töï cheùp chuoãi kyù töï hai laàn. Ñeå traùnh ñieàu naøy chuùng ta haõy thöû thay ñoåi doøng leänh. Chaúng haïn, moät caùch ñôn giaûn chuùng ta khai baùo strcat laø moät haøm friend cuûa lôùp String. Khi ñoù chuùng ta coù theå truy caäp ñeán thuoäc tính entries cuûa lôùp String: add_to.entries = copy. Chuùng ta caàn haøm ñeå ñoïc caùc ñoái töôïng String. Chuùng ta coù theå thöïc hieän töông töï nhö ñoái vôùi C-String, taùc vuï 0) cout Chöông 5 – Chuoãi kyù töï Trong caùc phaàn tieáp theo chuùng ta seõ söû duïng caùc haøm thö vieän cho lôùp String nhö sau: void strcpy(String ©, const String &original); post: Haøm cheùp String original sang String copy. void strncpy(String ©, const String &original, int n); post: Haøm cheùp nhieàu nhaát laø n kyù töï töø String original sang String copy. int strstr(const String &text, const String &target); post: Neáu String target laø chuoãi con (subtring) cuûa String text, haøm traû veà vò trí xuaát hieän ñaàu tieân cuûa target trong text; ngöôïc laïi, haøm traû veà -1. Caùc hieän thöïc cuûa caùc haøm naøy theo caùch söû duïng laïi thö vieän C-String ñöôïc xem nhö baøi taäp. 5.5. Caùc giaûi thuaät tìm moät chuoãi con trong moät chuoãi Phaàn sau ñaây chuùng ta seõ tìm hieåu laïi caùch hieän thöïc cuûa moät vaøi haøm thö vieän cuûa C-String. Caùc pheùp xöû lyù cô baûn treân chuoãi kyù töï bao goàm: tìm moät chuoãi con trong moät chuoãi, thay theá moät chuoãi con baèng moät chuoãi khaùc, cheøn moät chuoãi con vaøo moät chuoãi, loaïi moät chuoãi con trong moät chuoãi,… Trong ñoù pheùp tìm moät chuoãi con trong moät chuoãi coù theå xem laø pheùp cô baûn nhaát, nhöõng pheùp coøn laïi coù theå ñöôïc thöïc hieän deã daøng sau khi ñaõ xaùc ñònh ñöôïc vò trí cuûa chuoãi con. Chuùng ta seõ tìm hieåu hai giaûi thuaät tìm chuoãi con trong moät chuoãi cho tröôùc. 5.5.1. Giaûi thuaät Brute-Force YÙ töôûng giaûi thuaät naøy voâ cuøng ñôn giaûn, ñoù laø thöû so truøng chuoãi con taïi moïi vò trí baét ñaàu trong chuoãi ñaõ cho (Hình 5.2). Giaû söû chuùng ta caàn tìm vò trí cuûa chuoãi a trong chuoãi s. Caùc vò trí baét ñaàu so truøng a treân s laø 0, 1, 2, …Moãi laàn so truøng, chuùng ta laàn löôït so saùnh töøng caëp kyù töï cuûa a vaø s töø traùi sang phaûi. Khi gaëp hai kyù töï khaùc nhau, chuùng ta laïi phaûi baét ñaàu so truøng töø ñaàu chuoãi a vôùi vò trí môùi. Vò trí baét ñaàu so truøng treân s laàn thöù i seõ laø vò trí baét ñaàu so truøng treân s laàn thöù i-1 coäng theâm 1. Caùc kyù töï in nghieâng trong hình veõ beân döôùi laø vò trí thaát baïi trong moät laàn so truøng, phaàn coù neàn xaùm beân traùi chuùng laø nhöõng kyù töï so truøng ñaõ thaønh coâng. Moät laàn so truøng naøo ñoù maø chuùng ta ñaõ duyeät qua ñöôïc heát chieàu daøi cuûa a xem nhö ñaõ tìm thaáy a trong s vaø giaûi thuaät döøng. Cho i laø chæ soá chaïy treân s vaø j laø chæ soá chaïy treân a, j luoân ñöôïc gaùn veà 0 khi baét ñaàu moät laàn so truøng. Khi gaëp thaát baïi trong moät laàn so truøng naøo ñoù thì caû i vaø j ñeàu ñaõ tieán ñöôïc j böôùc so vôùi luùc baét ñaàu so truøng. Do ñoù ñeåû baét ñaàu so truøng cho laàn sau, i caàn luøi veà j-1 böôùc. Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 83 Chöông 5 – Chuoãi kyù töï 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 s 1 0 1 0 1 0 0 1 0 1 1 0 1 0 0 1 1 1 1 0 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 Hình 5.2- Minh hoïa giaûi thuaät Brute-Force // Giaûi thuaät Brute-Force int strstr(const String &s, const String &a); /* post: Neáu chuoãi a laø chuoãi con cuûa chuoãi s, haøm traû veà vò trí xuaát hieän ñaàu tieân cuûa a trong s; ngöôïc laïi, haøm traû veà -1. */ { int i = 0, // Chæ soá chaïy treân s. j = 0, // Chæ soá chaïy treân a. ls = s.strlen(); // Soá kyù töï cuûa s. la = a.strlen(), // Soá kyù töï cuûa a. const char* pa = a.c_str(); //Ñòa chæ kyù töï ñaàu tieân cuûa a. const char* ps = s.c_str(); //Ñòa chæ kyù töï ñaàu tieân cuûa s. do { if (pa[j] == ps[i]){ i++; j++; }; else { i = i – (j – 1); // Luøi veà cho laàn so truøng keá tieáp. j = 0; } } while ((jChöông 5 – Chuoãi kyù töï ls vaø la laø chieàu daøi cuûa chuoãi s vaø chuoãi a. Moãi laàn so truøng ñaõ phaûi so saùnh la kyù töï. Soá laàn so saùnh toái ña laø la*(ls-la+1) ≈ la*ls. 5.5.2. Giaûi thuaät Knuth-Morris-Pratt Giaûi thuaät naøy do Knuth, Morris vaø Pratt ñöa ra, coøn goïi laø giaûi thuaät KMP- Search. Trong ví duï treân chuùng ta thaáy giaûi thuaät Brute-Force phaûi so truøng ñeán laàn thöù 11 môùi phaùt hieän ñöôïc vò trí caàn tìm. Giaûi thuaät KMP-Search döôùi ñaây tieát kieäm ñöôïc moät soá laàn so truøng vaø chæ phaûi so truøng ñeán laàn thöù 5. Hôn theá nöõa, chæ soá i chaïy treân s cuõng khoâng bao giôø phaûi luøi laïi. Ñeå coù ñöôïc ñieàu naøy, chuùng ta haõy coá gaéng ruùt ra nhaän xeùt töø hình 5.3 beân döôùi. Trong laàn so truøng thöù nhaát, khi i=4 thì aj ≠ si, khi ñoù a seõ ñöôïc dòch chuyeån veà phía phaûi sao cho ñoaïn ñaàu cuûa a truøng khôùp vôùi ñoaïn cuoái cuûa a trong phaàn ñaõ ñöôïc duyeät qua (chæ tính phaàn maøu xaùm). Trong hình veõ laø hai kyù töï 1 vaø 0 coù gaïch döôùi. Laàn so truøng keá tieáp chính laø töø vò trí naøy, vaø nhöõng laàn so truøng trung gian giöõa hai laàn naøy coù theå boû qua. Ñieàu naøy coù theå lyù giaûi nhö sau: neáu phaàn ñaàu cuûa a truøng vôùi phaàn cuoái cuûa a thì noù cuõng truøng vôùi phaàn töông öùng cuûa s beân treân, do phaàn cuoái cuûa a vöøa môùi ñöôïc so truøng thaønh coâng vôùi phaàn töông öùng cuûa s. Ñöôïc nhö vaäy thì i môùi hoaøn toaøn khoâng phaûi luøi laïi. Trong laàn so truøng môùi, chính si naøy seõ ñöôïc so saùnh vôùi aj, vôùi j seõ ñöôïc tính toaùn thích hôïp maø chuùng ta seõ baøn ñeán sau. Trong ví duï chuùng ta thaáy j = 2, laàn so saùnh ñaàu tieân cuûa laàn so truøng thöù hai laø so saùnh giöõa s4 vaø a2. Töông töï, khi laàn so truøng thöù hai thaát baïi taïi s8, chuoãi con a seõ ñöôïc dòch chuyeån raát xa, tieát kieäm ñöôïc raát nhieàu laàn so truøng. Chuùng ta deã daøng kieåm chöùng, vôùi nhöõng vò trí trung gian khaùc, phaàn ñaàu cuûa a khoâng truøng vôùi phaàn cuoái (chæ tính phaàn maøu xaùm) cuûa a, neân cuõng khoâng theå truøng vôùi phaàn töông öùng treân s, coù thöïc hieän so truøng cuõng seõ thaát baïi maø thoâi. Baét ñaàu laàn so truøng thöù hai Baét ñaàu laàn so truøng thöù ba (i = 4, j = 2) (i = 8, j = 1) • 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 s 1 0 1 0 1 0 0 1 0 1 1 0 1 0 0 1 1 1 1 0 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 a 1 0 1 0 0 1 1 1 Hình 5.3- Minh hoïa giaûi thuaät Knuth-Morris-Pratt Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 85 Chöông 5 – Chuoãi kyù töï Hình veõ döôùi ñaây giuùp chuùng ta hieåu ñöôïc caùch tính chæ soá j thích hôïp cho ñaàu moãi laàn so truøng (trong khi i khoâng luøi veà maø giöõ nguyeân ñeå tieáp tuïc tieán tôùi). Trích töø hình veõ treân, chuùng ta coù ñöôïc keát quaû sau ñaây. Xeùt vò trí i = 4, j = 4, do so saùnh si vôùi aj thaát baïi, chuùng ta ñang muoán bieát phaàn cuoái cuûa a keå töø ñieåm naøy trôû veà tröôùc (töùc chæ tính phaàn maøu xaùm) vaø phaàn ñaàu cuûa a truøng ñöôïc bao nhieâu kyù töï. Goïi a’ = a. Chuùng ta seõ nhìn queùt töø cuoái phaàn maøu xaùm cuûa a vaø töø ñaàu cuûa a’, chuùng ta seõ bieát ñöôïc coù bao nhieâu kyù töï truøng. Ñoù laø hai kyù töï 1 vaø 0 ñöôïc gaïch döôùi. i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 s 1 0 1 0 1 0 0 1 0 1 1 0 1 0 0 1 1 1 1 0 1 j=4, soá kyù töï truøng laø 2 a 1 0 1 0 0 1 1 1 a’ 1 0 1 0 0 1 1 1 Nhö vaäy, ñieàu naøy hoaøn toaøn khoâng coøn phuï thuoäc vaøo s nöõa. Chuùng ta coù theå tính soá kyù töï truøng theo j döïa treân a vaø a’. Ñoàng thôøi ta thaáy soá kyù töï truøng naøy cuõng laø chæ soá maø j phaûi luøi veà cho laàn so truøng keá tieáp aj vôùi si, i khoâng ñoåi. Chuùng ta baét ñaàu vôùi j = 1 vaø xem hình 5.4 sau ñaây. Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 86 Chöông 5 – Chuoãi kyù töï j=1, soá kyù töï truøng laø 0 (khi ñeám soá kyù töï truøng, luoân phaûi dòch chuyeån a’ sang phaûi so vôùi a, töùc chæ so saùnh phaàn cuoái cuûa a vôùi phaàn ñaàu cuûa a’, tröôøng hôïp naøy xem nhö khoâng coù kyù töï truøng). a 1 0 1 0 0 1 1 1 next1 = 0 a’ 1 0 1 0 0 1 1 1 j=2, soá kyù töï truøng laø 0 a 1 0 1 0 0 1 1 1 next2 = 0 a’ 1 0 1 0 0 1 1 1 j=3, soá kyù töï truøng laø 1 a 1 0 1 0 0 1 1 1 next3 = 1 a’ 1 0 1 0 0 1 1 1 j=4, soá kyù töï truøng laø 2 a 1 0 1 0 0 1 1 1 next4 = 2 a’ 1 0 1 0 0 1 1 1 j=5, soá kyù töï truøng laø 0 a 1 0 1 0 0 1 1 1 next5 = 0 a’ 1 0 1 0 0 1 1 1 j=6, soá kyù töï truøng laø 1 a 1 0 1 0 0 1 1 1 next6 = 1 a’ 1 0 1 0 0 1 1 1 j=7, soá kyù töï truøng laø 1 a 1 0 1 0 0 1 1 1 next7 = 1 a’ 1 0 1 0 0 1 1 1 Hình 5.4- Minh hoïa giaûi thuaät Knuth-Morris-Pratt Giaû söû chuùng ta ñaõ taïo ñöôïc danh saùch next maø phaàn töû thöù j chöùa trò maø j phaûi luøi veà khi ñang so saùnh aj vôùi si maø thaát baïi (aj ≠ si), ñeå baét ñaàu laàn so truøng keá tieáp (i giöõ nguyeân khoâng ñoåi). Hình 5.4 cho thaáy next1 luoân baèng 0 vôùi moïi a. Chuùng ta coù giaûi thuaät KMP-Search nhö döôùi ñaây. Laàn so truøng thöù nhaát luoân baét ñaàu töø kyù töï ñaàu cuûa s vaø a, neân hai chæ soá i vaø j ñeàu laø 0. • Tröôøng hôïp deã hieåu nhaát laø trong khi maø aj=si thì i vaø j ñeàu ñöôïc nhích tôùi. Ñieàu kieän döøng cuûa voøng laëp hoaøn toaøn nhö giaûi thuaät Brute-Force treân, coù nghóa laø j ñi ñöôïc heát chieàu daøi cuûa a (tìm thaáy a trong s), hoaëc i ñi quaù chieàu daøi cuûa s (vieäc tìm keát thuùc thaát baïi). Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 87 Chöông 5 – Chuoãi kyù töï • Tröôøng hôïp aj≠si (vôùi j≠0) trong moät laàn so truøng naøo ñoù thì nhö ñaõ noùi ôû treân, chæ vieäc cho j luøi veà vò trí ñaõ ñöôïc chöùa trong phaàn töû thöù j trong danh saùch next. Nhôø vaäy trong laàn laëp keá tieáp seõ tieáp tuïc so saùnh aj naøy vôùi si maø i khoâng ñoåi. • Rieâng tröôøng hôïp ñaëc bieät, vôùi j = 0 maø aj≠si, ta xem hình döôùi ñaây i s … 1 1 0 0 1 0 0 1 1 1 0 1 1 … j=0, soá kyù töï truøng laø 0 a 1 0 1 0 0 1 1 1 Baát cöù moät laàn so saùnh si naøo ñoù vôùi a0 maø thaát baïi thì chuoãi a cuõng phaûi dòch chuyeån sang phaûi moät böôùc, ñeå laàn so saùnh keá tieáp (cuõng laø laàn so truøng môùi) coù theå so saùnh a0 vôùi si+1. Nhö vaäy ta chæ caàn taêng i vaø giöõ nguyeân j maø thoâi. // Giaûi thuaät Knuth- Morris – Pratt int strstr(const String &s, const String &a); /* post: Neáu a laø chuoãi con cuûa s, haøm traû veà vò trí xuaát hieän ñaàu tieân cuûa a trong s; ngöôïc laïi, haøm traû veà -1. */ { List next; int i = 0, // Chæ soá chaïy treân s. j = 0, // Chæ soá chaïy treân a. ls = s.strlen(); // Soá kyù töï cuûa s. la = a.strlen(), // Soá kyù töï cuûa a. const char* pa = a.c_str(); //Ñòa chæ kyù töï ñaàu tieân cuûa a. const char* ps = s.c_str(); //Ñòa chæ kyù töï ñaàu tieân cuûa s. InitNext(a, next); // Khôûi gaùn caùc phaàn töû next1, next2,…,nextla-1. // Khoâng söû duïng next0. do { if (pa[j]==ps[i]){// Vaãn coøn kyù töï truøng trong moät laàn so truøng i++; // naøo ñoù, i vaø j ñöôïc quyeàn nhích tôùi. j++; } else if (j == 0) // Ñaây laø tröôøng hôïp ñaëc bieät, phaûi dòch a sang phaûi i++; // moät böôùc, coù nghóa laø cho i nhích tôùi. else next.retrieve(j, j); // Cho j luøi veà trò ñaõ chöùa trong nextj. } while ((jChöông 5 – Chuoãi kyù töï Sau ñaây chuùng ta seõ vieát haøm InitNext gaùn caùc trò cho caùc phaàn töû cuûa next, töùc laø tìm soá phaàn töû truøng theo hình veõ 5.4. Coù moät ñieàu khaù thuù vò trong giaûi thuaät naøy, ñoù chính laø haøm taïo danh saùch next laïi söû duïng ngay chính danh saùch naøy. Chuùng ta thaáy raèng ñeå tìm soá phaàn töû truøng nhö ñaõ noùi, chuùng ta caàn dòch chuyeån a’ veà beân phaûi so vôùi a, maø vieäc dòch chuyeån a’ treân a cuõng hoaøn toaøn gioáng nhö vieäc dòch chuyeån a treân s trong khi ñi tìm a trong s. // Haøm phuï trôï gaùn caùc phaàn töû cho danh saùch next. void InitNext(const String &a, List &next); /* post: Gaùn caùc trò cho caùc phaàn töû cuûa next döïa treân chuoãi kyù töï a. */ { int i = 1, // Chæ soá chaïy treân a. j = 0, // Chæ soá chaïy treân a’. la = a.strlen(), // Soá kyù töï cuûa a (cuõng laø cuûa a’). const char* pa = a.c_str(); //Ñòa chæ kyù töï ñaàu tieân cuûa a (cuõng laø cuûa a’). next.clear(); next.insert(1, 0); // Luoân ñuùng vôùi moïi a. do { if (pa[j]==pa[i]){ // Vaãn coøn kyù töï truøng trong moät laàn so truøng i++; // naøo ñoù, i vaø j ñöôïc quyeàn nhích tôùi. j++; // Töø vò trí i treân a trôû veà tröôùc, j xem nhö ñaõ next.insert(i, j);// queùt ñöôïc soá phaàn töû truøng cuûa a’ so vôùi a. } else if (j == 0){ // Tröôøng hôïp ñaëc bieät, phaûi dòch a sang phaûi i++; // moät böôùc, coù nghóa laø cho i nhích tôùi. next.insert(i, j); }; else next.retrieve(j, j); // Cho j luøi veà trò ñaõ chöùa trong nextj. } while (iChöông 5 – Chuoãi kyù töï Khi ai ≠ a’j, chuùng ta söû duïng yù töôûng cuûa KMP-Search laø cho j luøi veà nextj. Vaán ñeà coøn laïi caàn kieåm chöùng laø giaù trò cuûa nextj phaûi coù tröôùc khi noù ñöôïc söû duïng. Do chuùng ta ñaõ gaùn vaøo nexti vaø ñaõ söû duïng nextj, maø i luoân luoân ñi tröôùc j, neân chuùng ta hoaøn toaøn yeân taâm veà ñieàu naøy. Cuoái cuøng, chæ coøn moät ñieàu nhoû maø chuùng ta caàn xem xeùt. Ñoù laø tröôøng hôïp coù nhieàu phöôg aùn cho soá kyù töï truøng nhau. Chaúng haïn vôùi a laø “10101010111…” vaø j=8, soá kyù töï truøng khi dòch a’=a veà beân phaûi so vôùi a laø: Vò trí j ñang xeùt a 1 0 1 0 1 0 1 0 1 1 1... Soá kyù töï truøng laø 6 a’ 1 0 1 0 1 0 1 0 1 1 1... a 1 0 1 0 1 0 1 0 1 1 1... a’ 1 0 1 0 1 0 1 0 1 1 1... Soá kyù töï truøng laø 4 a 1 0 1 0 1 0 1 0 1 1 1... a’ 1 0 1 0 1 0 1 0 1 1 1... Soá kyù töï truøng laø 2 Sinh vieân haõy töï suy nghó xem caùch choïn phöông aùn naøo laø ñuùng ñaén nhaát vaø kieåm tra laïi caùc ñoaïn chöông trình treân xem chuùng coù caàn phaûi ñöôïc söûa ñoåi gì hay khoâng. Ngoaøi ra, giaûi thuaät KMP-Search coøn coù theå caûi tieán moät ñieåm nhoû, ñoù laø tröôùc khi gaùn nexti=j trong InitNext, chuùng ta kieåm tra neáu paj=pai thì seõ gaùn nexti=nextj. Do khi so truøng pai maø thaát baïi thì coù luøi veà panexti=paj cuõng seõ thaát baïi, chuùng ta neân luøi haún veà panextj. Soá laàn so saùnh toái ña trong KMP-Search laø ls+la. Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 90
DMCA.com Protection Status Copyright by webtailieu.net