SDSL: Succinct Data Structure Library
A C++ template library for succinct data structures
|
00001 /* sdsl - succinct data structures library 00002 Copyright (C) 2008 Simon Gog 00003 00004 This program is free software: you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation, either version 3 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program. If not, see http://www.gnu.org/licenses/ . 00016 */ 00022 #ifndef INCLUDED_SDSL_ALGORITHMS 00023 #define INCLUDED_SDSL_ALGORITHMS 00024 00025 #include "int_vector.hpp" 00026 00027 #include <stdexcept> // for exceptions 00028 #include <iostream> 00029 #include <cassert> 00030 #include <stack> 00031 #include <utility> 00032 00033 00034 namespace sdsl 00035 { 00036 00038 00041 namespace algorithm 00042 { 00043 // private: 00044 // algorithm(); // This helper class can not be instantiated 00045 00046 // Returns if the pair (a1,a2) is lex. less or equal than (b1,b2) 00047 template<typename I> 00048 static bool leq(I a1, I a2, I b1, I b2) 00049 { 00050 return a1 < b1 || (a1 == b1 && a2 <= b2); 00051 } 00052 00053 // Returns if the triple (a1,a2,a3) is lex. less or equal than (b1,b2,b3) 00054 template<typename I> 00055 static bool leq(I a1, I a2, I a3, I b1, I b2, I b3) 00056 { 00057 return a1 < b1 || (a1 == b1 && leq(a2,a3,b2,b3)); 00058 } 00059 00060 00061 // public: 00063 00067 double H_0(const unsigned char* c); 00068 00069 // Claculate the star entropy of T, see Manzini 2001 for details 00070 double H_0s(const unsigned char* c); 00071 00072 00074 00080 template<class RandomAccessContainer1, class RandomAccessContainer2> 00081 static void sa2isa(const RandomAccessContainer1& sa, RandomAccessContainer2& isa); 00082 00083 template<class RandomAccessContainer> 00084 static void sa2isa(const RandomAccessContainer& sa, int_vector<>& isa); 00085 00087 00095 template<class RandomAccessContainer> 00096 static void inverse_permutation_inplace(RandomAccessContainer& sa); 00097 00099 00106 template<class RandomAccessContainer1, class RandomAccessContainer2> 00107 void calculate_psv(const RandomAccessContainer1& a, RandomAccessContainer2& psv); 00108 00109 00111 00113 template<class RandomAccessContainer1, class RandomAccessContainer2> 00114 static bool verify_psv(const RandomAccessContainer1& a, RandomAccessContainer2& psv); 00115 00116 template<class RandomAccessContainer1, class RandomAccessContainer2> 00117 static void calculate_psv2(const RandomAccessContainer1& a, RandomAccessContainer2& psv); 00118 00120 00127 template<class RandomAccessContainer1, class RandomAccessContainer2> 00128 static void calculate_nsv(const RandomAccessContainer1& a, RandomAccessContainer2& nsv); 00129 00131 template<class RandomAccessContainer1, class RandomAccessContainer2> 00132 static bool verify_nsv(const RandomAccessContainer1& a, RandomAccessContainer2& nsv); 00133 00135 template<class RandomAccessContainer, class Text> 00136 static void calculate_lcp(const RandomAccessContainer& sa, const Text& text, RandomAccessContainer& lcp); 00137 00139 00149 template<class RandomAccessContainer> 00150 static bool verify_sa(const unsigned char* c, typename RandomAccessContainer::size_type len, const RandomAccessContainer& sa); 00151 00153 template<class SelectSupport> 00154 inline static bool verify_select_support(const SelectSupport& ss, const int_vector<1>& b); 00155 00157 template<class Container1, class Container2> 00158 static bool equal_container_values(const Container1& c1, Container2& c2); 00159 00161 00167 template<class RandomAccessContainer> 00168 static void sa2isa_inplace(RandomAccessContainer& sa); 00169 00171 /* \param bwt Burrows and Wheeler Transformation. 00172 * \param len Length of the bwt. 00173 * \param psi Container of size len for the result. 00174 * \par Time complexity 00175 * \f$\Order{2n}\f$ i.e. linear. 00176 * \par Space complexity 00177 * Space of bwt (\f$\Order{n}\f$ bits) + space of uncompressed \f$\Psi\f$-function (\f$\Order{4n}\f$ bits). 00178 */ 00179 template<class RandomAccessContainer> 00180 static void bwt2psi(const unsigned char* bwt, typename RandomAccessContainer::size_type len, RandomAccessContainer& psi); 00181 00183 00190 template<class RandomAccessContainer1, class RandomAccessContainer2> 00191 static void sa2psi(const RandomAccessContainer1& sa, RandomAccessContainer2& psi); 00192 00193 template<class RandomAccessContainer> 00194 static void sa2psi(const RandomAccessContainer& sa, int_vector<>& psi); 00195 00197 00204 template<class RandomAccessContainer, class Text> 00205 static void calculate_lcp12(const RandomAccessContainer& sa, const Text& text, RandomAccessContainer& lcp); 00206 00208 00214 template<class RandomAccessContainer1, class RandomAccessContainer2> 00215 static void psi2sa(const RandomAccessContainer1& psi, const typename RandomAccessContainer1::size_type isa_0, RandomAccessContainer2& sa); 00216 00217 template<class RandomAccessContainer> 00218 static void psi2sa(const RandomAccessContainer& psi, const typename RandomAccessContainer::size_type isa_0, int_vector<>& sa); 00220 00226 template<class RandomAccessContainer> 00227 static void psi2isa(const RandomAccessContainer& psi, const typename RandomAccessContainer::size_type isa_0, RandomAccessContainer& isa); 00228 00229 00230 template<class RandomAccessContainer1, class RandomAccessContainer2> 00231 void calculate_psv(const RandomAccessContainer1& a, RandomAccessContainer2& psv) 00232 { 00233 assert(psv.size() == a.size()); 00234 if (a.empty()) 00235 return; 00236 psv[0] = psv.size(); 00237 assert(psv[0] == psv.size()); 00238 std::stack<typename RandomAccessContainer1::size_type> psv_index; 00239 typename RandomAccessContainer1::value_type min_element = a[0]; 00240 for (typename RandomAccessContainer1::size_type i=0; i < a.size(); ++i) { 00241 if (a[i] <= min_element) { 00242 while (!psv_index.empty()) 00243 psv_index.pop(); 00244 min_element = a[i]; 00245 psv[i] = a.size(); 00246 psv_index.push(i); 00247 } else { // a[i] > min_element => stack will not be empty 00248 while (a[psv_index.top()] >= a[i]) 00249 psv_index.pop(); 00250 psv[i] = psv_index.top(); 00251 psv_index.push(i); 00252 } 00253 } 00254 } 00255 00256 template<class RandomAccessContainer1, class RandomAccessContainer2> 00257 bool verify_psv(const RandomAccessContainer1& a, RandomAccessContainer2& psv) 00258 { 00259 if (a.size()!=psv.size()) 00260 return false; 00261 typename RandomAccessContainer1::value_type min_element = a[0]; 00262 for (typename RandomAccessContainer1::size_type i=0; i<a.size(); ++i) { 00263 if (a[i] <= min_element) { 00264 min_element = a[i]; 00265 if (psv[i] != a.size()) // see definition of calculate_psv 00266 return false; 00267 } else { 00268 if (psv[i]>=i) 00269 return false; 00270 if (a[psv[i]] >= a[i]) 00271 return false; 00272 for (typename RandomAccessContainer1::size_type j=psv[i]+1; j<i; ++j) 00273 if (a[j]<a[i]) 00274 return false; 00275 } 00276 } 00277 return true; 00278 } 00279 00280 00281 template<class RandomAccessContainer1, class RandomAccessContainer2> 00282 void calculate_psv2(const RandomAccessContainer1& a, RandomAccessContainer2& psv) 00283 { 00284 assert(psv.size() == a.size()); 00285 if (a.empty()) 00286 return; 00287 psv[0] = psv.size(); 00288 assert(psv[0] == psv.size()); 00289 // TODO implementing the algorithm with use of a stack 00290 psv[0] = psv.size(); 00291 typedef std::pair<typename RandomAccessContainer1::value_type, typename RandomAccessContainer1::size_type> tPII; 00292 std::stack<tPII> psv_stack; 00293 typename RandomAccessContainer1::value_type min_element = a[0], ai; 00294 for (typename RandomAccessContainer1::size_type i=0; i < a.size(); ++i) { 00295 if ((ai=a[i]) <= min_element) { 00296 while (!psv_stack.empty()) 00297 psv_stack.pop(); 00298 min_element = ai; 00299 psv[i] = a.size(); 00300 psv_stack.push(tPII(ai, i)); 00301 } else { // a[i] > min_element => stack will not be empty 00302 while (psv_stack.top().first >= ai) 00303 psv_stack.pop(); 00304 psv[i] = psv_stack.top().second; 00305 psv_stack.push(tPII(ai, i)); 00306 } 00307 } 00308 } 00309 00310 template<class RandomAccessContainer1, class RandomAccessContainer2> 00311 void calculate_nsv(const RandomAccessContainer1& a, RandomAccessContainer2& nsv) 00312 { 00313 assert(nsv.size() == a.size()); 00314 if (a.empty()) 00315 return; 00316 nsv[nsv.size()-1] = 0; 00317 std::stack<typename RandomAccessContainer1::size_type> nsv_index; 00318 typename RandomAccessContainer1::value_type min_element = a[nsv.size()-1]; 00319 for (typename RandomAccessContainer1::size_type i=nsv.size(); i > 0; --i) { 00320 if (a[i-1] <= min_element) { 00321 while (!nsv_index.empty()) 00322 nsv_index.pop(); 00323 min_element = a[i-1]; 00324 nsv[i-1] = 0; 00325 nsv_index.push(i-1); 00326 } else { // a[i] > min_element => stack will not be empty 00327 while (a[nsv_index.top()] >= a[i-1]) 00328 nsv_index.pop(); 00329 nsv[i-1] = nsv_index.top(); 00330 nsv_index.push(i-1); 00331 } 00332 } 00333 } 00334 00335 00336 template<class RandomAccessContainer1, class RandomAccessContainer2> 00337 bool verify_nsv(const RandomAccessContainer1& a, RandomAccessContainer2& nsv) 00338 { 00339 if (a.size() != nsv.size()) 00340 return false; 00341 typename RandomAccessContainer1::value_type min_element = a[a.size()-1]; 00342 for (typename RandomAccessContainer1::size_type i=a.size(); i>0; --i) { 00343 if (a[i-1] <= min_element) { 00344 min_element = a[i-1]; 00345 if (nsv[i-1] != 0) // see definition of calculate_nsv 00346 return false; 00347 } else { 00348 if (nsv[i-1] <= i-1) 00349 return false; 00350 if (a[nsv[i-1]] >= a[i-1]) 00351 return false; 00352 for (typename RandomAccessContainer1::size_type j=i; j<nsv[i-1]; ++j) 00353 if (a[j]<a[i-1]) 00354 return false; 00355 } 00356 } 00357 return true; 00358 } 00359 00360 00361 00362 00363 00364 template<class RandomAccessContainer> 00365 void bwt2psi(const unsigned char* bwt, typename RandomAccessContainer::size_type len, RandomAccessContainer& psi) 00366 { 00367 if (psi.size() != len) 00368 psi.resize(len); 00369 typename RandomAccessContainer::size_type C[256] = {0}, index_of_dollar = 0; 00370 for (typename RandomAccessContainer::size_type i=0; i<len; ++i) { 00371 ++C[bwt[i]]; 00372 if (bwt[i]=='\0') 00373 index_of_dollar = i; 00374 } 00375 // std::cerr<<"index of . = "<<index_of_dollar<<std::endl; 00376 for (uint16_t i=255; i!=0; --i) 00377 C[i] = C[i-1]; 00378 C[0]=0; 00379 for (uint16_t i=1; i<256; ++i) { 00380 C[i] += C[i-1]; 00381 } 00382 // assert(C[bwt[0]]==0); 00383 // psi[C[bwt[0]]] = index_of_dollar; 00384 // ++C[bwt[0]]; 00385 for (typename RandomAccessContainer::size_type i=0; i<len; ++i) { 00386 psi[C[bwt[i]]] = i; 00387 ++C[bwt[i]]; 00388 } 00389 /* for(typename RandomAccessContainer::size_type i=index_of_dollar+1; i<len; ++i){ 00390 psi[C[bwt[i]]] = i; 00391 ++C[bwt[i]]; 00392 } 00393 */ 00394 /* 00395 typename RandomAccessContainer::size_type C[256] = {0}, index_of_dollar = 0; 00396 for(typename RandomAccessContainer::size_type i=0; i<len+1; ++i){ 00397 ++C[bwt[i]]; 00398 if(bwt[i]=='\0') 00399 index_of_dollar = i; 00400 } 00401 // std::cerr<<"index of $ = "<<index_of_dollar<<std::endl; 00402 for(uint16_t i=255;i!=0;--i) 00403 C[i] = C[i-1]; 00404 C[0]=0; 00405 for(uint16_t i=1;i<256;++i){ 00406 C[i] += C[i-1]; 00407 } 00408 psi[C[bwt[0]]-1] = index_of_dollar-1; 00409 ++C[bwt[0]]; 00410 for(typename RandomAccessContainer::size_type i=1; i<index_of_dollar; ++i){ 00411 psi[C[bwt[i]]-1] = i-1; 00412 ++C[bwt[i]]; 00413 } 00414 for(typename RandomAccessContainer::size_type i=index_of_dollar+1; i<len+1; ++i){ 00415 psi[C[bwt[i]]-1] = i-1; 00416 ++C[bwt[i]]; 00417 } 00418 */ 00419 } 00420 00421 template<class RandomAccessContainer1, class RandomAccessContainer2> 00422 void sa2isa(const RandomAccessContainer1& sa, RandomAccessContainer2& isa) 00423 { 00424 isa.resize(sa.size()); // init isa 00425 typename RandomAccessContainer1::size_type i = 0; 00426 for (typename RandomAccessContainer1::const_iterator sa_it = sa.begin(), end = sa.end(); sa_it != end; ++sa_it, ++i) { 00427 isa[ *sa_it ] = i; 00428 } 00429 } 00430 00431 template<class RandomAccessContainer> 00432 void sa2isa(const RandomAccessContainer& sa, int_vector<>& isa) 00433 { 00434 isa.set_int_width(bit_magic::l1BP(sa.size())+1); 00435 isa.resize(sa.size()); // init isa 00436 typename RandomAccessContainer::size_type i = 0; 00437 for (typename RandomAccessContainer::const_iterator sa_it = sa.begin(), end = sa.end(); sa_it != end; ++sa_it, ++i) { 00438 isa[ *sa_it ] = i; 00439 } 00440 } 00441 00442 template<class RandomAccessContainer> 00443 void inverse_permutation_inplace(RandomAccessContainer& perm) 00444 { 00445 if (perm.size() == 0) 00446 return; 00447 typedef bit_vector::size_type size_type; 00448 #ifdef SDSL_DEBUG 00449 { 00450 // check if input permutation perm is really a permutation from \f$0..perm.size()-1\f$ 00451 bit_vector visited(perm.size(),0); 00452 for (size_type i=0; i<perm.size(); ++i) { 00453 if (!(perm[i]>=0 and perm[i]<perm.size() and 0==visited[perm[i]])) 00454 throw std::invalid_argument("Input for inverse_permutation_inplace is not a permutation!"); 00455 visited[perm[i]]=1; 00456 } 00457 } 00458 #endif 00459 uint8_t w = bit_magic::l1BP(perm.size()-1)+1; 00460 uint64_t b = 1ULL << ((w+1)%64); 00461 uint64_t biggest = b | (perm.size()-1); 00462 uint64_t perm_0 = perm[0]; 00463 perm[0] = biggest; 00464 if (w != 63 and perm[0] == biggest) { // space left for real inplace calculation 00465 #ifdef SDSL_DEBUG 00466 std::cout<<"using real in-place procedure for inverse_permutation_inplace"<<std::endl; 00467 #endif 00468 perm[0] = perm_0; 00469 for (size_type i=0, j,jj,t; i < perm.size(); ++i) { 00470 if ((perm[i] & b) == 0) { 00471 j = perm[i]; jj = i; 00472 while ((perm[j] & b) == 0) { 00473 t = perm[j]; 00474 perm[j] = jj | b; // mark perm[j] as visited 00475 jj=j; j=t; 00476 } 00477 } 00478 } 00479 for (size_type i=0; i < perm.size(); ++i) 00480 perm[i] = perm[i] & (b-1); 00481 } else { // not enough space for real inplace calculation => use additional 00482 perm[0] = perm_0; 00483 bit_vector is_inverse(perm.size(), 0); // indicator bit_vector! 00484 for (size_type i=0, j,jj,t; i<perm.size(); ++i) { 00485 if (!is_inverse[i]) { 00486 j = perm[i]; jj = i; 00487 while (!is_inverse[j]) { 00488 is_inverse[j] = 1; // mark perm[j] as visited 00489 t = perm[j]; perm[j] = jj; jj=j; j=t; 00490 } 00491 } 00492 } 00493 } 00494 #ifdef SDSL_DEBUG 00495 { 00496 // check if the result is really a permutation form \f$0..perm.size()-1\f$ 00497 bit_vector visited(perm.size(),0); 00498 for (size_type i=0; i<perm.size(); ++i) { 00499 assert(perm[i]>=0 and perm[i]<perm.size() and 0==visited[perm[i]]); 00500 visited[perm[i]]=1; 00501 } 00502 } 00503 #endif 00504 } 00505 00506 template<class RandomAccessContainer1, class RandomAccessContainer2> 00507 void sa2psi(const RandomAccessContainer1& sa, RandomAccessContainer2& psi) 00508 { 00509 RandomAccessContainer2 isa; // temporary array for the inverse suffix array 00510 sa2isa(sa, isa); 00511 psi.resize(sa.size()); 00512 typename RandomAccessContainer1::value_type tmp; // 00513 typename RandomAccessContainer2::iterator psi_it = psi.begin(); 00514 for (typename RandomAccessContainer1::const_iterator sa_it = sa.begin(), end = sa.end(); sa_it != end; ++sa_it, ++psi_it) { 00515 if ((tmp = *sa_it+1) != sa.size()) 00516 *psi_it = isa[tmp]; 00517 else 00518 *psi_it = isa[0]; 00519 } 00520 } 00521 00522 template<class RandomAccessContainer> 00523 void sa2psi(const RandomAccessContainer& sa, int_vector<>& psi) 00524 { 00525 int_vector<> isa; // temporary array for the inverse suffix array 00526 sa2isa(sa, isa); 00527 psi.set_int_width(bit_magic::l1BP(sa.size())+1); 00528 psi.resize(sa.size()); 00529 typename RandomAccessContainer::value_type tmp; // 00530 int_vector<>::iterator psi_it = psi.begin(); 00531 for (typename RandomAccessContainer::const_iterator sa_it = sa.begin(), end = sa.end(); sa_it != end; ++sa_it, ++psi_it) { 00532 if ((tmp = *sa_it+1) != sa.size()) 00533 *psi_it = isa[tmp]; 00534 else 00535 *psi_it = isa[0]; 00536 } 00537 } 00538 00539 template<class RandomAccessContainer, class Text> 00540 void calculate_lcp(const RandomAccessContainer& sa, const Text& text, RandomAccessContainer& lcp) 00541 { 00542 lcp = sa; 00543 RandomAccessContainer isa; 00544 sa2isa(sa, isa); 00545 00546 lcp[0] = 0; 00547 typename RandomAccessContainer::size_type i=0,j,k,l=0; 00548 for (typename RandomAccessContainer::const_iterator isa_it = isa.begin(), end = isa.end(); isa_it != end; ++isa_it, ++i) { 00549 if ((j = *isa_it)) { 00550 k = sa[j-1]; 00551 while (text[k+l]==text[i+l]) 00552 ++l; 00553 lcp[j] = l; 00554 l = (l==0)?0:l-1; 00555 } 00556 } 00557 } 00558 00559 /* 00560 TODO: add implementation and definition 00561 template<class RandomAccessContainer> 00562 void algorithm::calculate_lps(){ 00563 00564 } 00565 */ 00566 00567 template<class RandomAccessContainer1, class RandomAccessContainer2> 00568 void psi2sa(const RandomAccessContainer1& psi, const typename RandomAccessContainer1::size_type isa_0, RandomAccessContainer2& sa) 00569 { 00570 sa.resize(psi.size()); 00571 if (psi.empty()) 00572 return; 00573 typename RandomAccessContainer1::value_type isa_k = isa_0; 00574 for (typename RandomAccessContainer1::size_type k = 0, size=psi.size(); k < size; ++k, isa_k = psi[isa_k]) { 00575 sa[isa_k] = k; 00576 } 00577 } 00578 00579 template<class RandomAccessContainer> 00580 void psi2sa(const RandomAccessContainer& psi, const typename RandomAccessContainer::size_type isa_0, int_vector<>& sa) 00581 { 00582 sa.set_int_width(bit_magic::l1BP(psi.size())+1); 00583 sa.resize(psi.size()); 00584 if (psi.empty()) 00585 return; 00586 typename RandomAccessContainer::value_type isa_k = isa_0; 00587 for (typename RandomAccessContainer::size_type k = 0, size=psi.size(); k < size; ++k, isa_k = psi[isa_k]) { 00588 sa[isa_k] = k; 00589 } 00590 } 00591 00592 template<class RandomAccessContainer> 00593 void psi2isa(const RandomAccessContainer& psi, const typename RandomAccessContainer::size_type isa_0, RandomAccessContainer& isa) 00594 { 00595 isa = psi; 00596 if (psi.empty()) 00597 return; 00598 typename RandomAccessContainer::value_type isa_k = isa_0; 00599 for (typename RandomAccessContainer::size_type k=0, size=psi.size(); k < size; ++k, isa_k = psi[isa_k]) { 00600 isa[k] = isa_k; 00601 } 00602 } 00603 00604 template<class RandomAccessContainer> 00605 bool verify_sa(const unsigned char* c, typename RandomAccessContainer::size_type len, const RandomAccessContainer& sa) 00606 { 00607 typedef typename RandomAccessContainer::size_type size_type; 00608 if (sa.size() != len) { // check length 00609 std::cerr<<"sa.size()!=len"<<std::endl; 00610 std::cerr<<sa.size()<<"!="<<len<<std::endl; 00611 return false; 00612 } 00613 { 00614 // check if values are in the range [0..len) and all are different 00615 int_vector<> occ(len); 00616 util::set_zero_bits(occ); 00617 for (typename RandomAccessContainer::const_iterator it=sa.begin(), end=sa.end(); it!=end; ++it) { 00618 size_type value = *it; 00619 if (value < len and !occ[value]) 00620 occ[value] = 1; 00621 else { 00622 std::cerr<<"sa is not a permutation"<<std::endl; 00623 return false; 00624 } 00625 } 00626 } 00627 // check if the lexicographic order is correct 00628 if (sa.size()<2) 00629 return true; 00630 size_type v1,v2; 00631 v1 = v2 = sa[(size_t)0]; 00632 for (typename RandomAccessContainer::const_iterator it=sa.begin()+1, end = sa.end(); it!=end; ++it) { 00633 v1 = v2; 00634 v2 = *it; 00635 size_type i=v1, j=v2; 00636 for (; i!=len and j!=len; ++i, ++j) { 00637 if (c[i] < c[j]) 00638 break; 00639 else if (c[i]>c[j]) { // lex order is wrong! 00640 std::cerr<<"lex order is wrong"<<std::endl; 00641 std::cerr<<"v1="<<v1<<" v2="<<v2<<std::endl; 00642 // std::cerr<<c+v1<<std::endl; 00643 // std::cerr<<c+v2<<std::endl; 00644 return false; 00645 } 00646 } 00647 } 00648 return true; 00649 } 00650 00651 template<class SelectSupport> 00652 bool verify_select_support(const SelectSupport& ss, const int_vector<1>& b) 00653 { 00654 uint64_t i=0,j=0; 00655 for (int_vector<1>::const_iterator it = b.begin(), end = b.end(); it != end; ++it, ++i) { 00656 if (*it) { 00657 ++j;// it's the j-th 1 detected 00658 if (ss.select(j)!=i) return false; 00659 } 00660 } 00661 return true; 00662 } 00663 00664 template<class Container1, class Container2> 00665 bool equal_container_values(const Container1& c1, Container2& c2) 00666 { 00667 if (c1.size() != c2.size()) 00668 return false; 00669 typename Container2::const_iterator c2_it = c2.begin(); 00670 for (typename Container1::const_iterator c1_it = c1.begin(), c1_end = c1.end(); c1_it!=c1.end(); ++c1_it, ++c2_it) 00671 if (*c1_it != *c2_it) 00672 return false; 00673 return true; 00674 } 00675 00676 00677 // template<uint8_t w> 00678 // void inplace_radix_sort(int_vector<w> &v); 00679 // template<class RandomAccessContainer, class Text> 00680 // static void calulate_lcp9(const RandomAccessContainer &sa, const Text &text, RandomAccessContainer& lcp); 00681 00682 00683 } // end namespace algorithm 00684 00685 } // end namespace sdsl 00686 00687 #include "algorithms_for_suffix_array_construction.hpp" 00688 #include "algorithms_for_balanced_parentheses.hpp" 00689 #include "algorithms_for_compressed_suffix_arrays.hpp" 00690 #include "algorithms_for_compressed_suffix_trees.hpp" 00691 #include "algorithms_for_string_matching.hpp" 00692 00693 00694 00695 #endif