/lcs_detail.hpp
C++ Header | 169 lines | 120 code | 22 blank | 27 comment | 33 complexity | 8358538a3c155edafe24e2d7a3de42f9 MD5 | raw file
1// (C) Copyright Craig Henderson 2002 2// cdm.henderson@virgin.net 3// 4// Permission to use, copy, modify, distribute and sell this software 5// and its documentation for any purpose is hereby granted without fee, 6// provided that the above copyright notice appears in all copies and 7// that both that copyright notice and this permission notice appear 8// in supporting documentation. The author makes no representations 9// about the suitability of this software for any purpose. It is 10// provided "as is" without express or implied warranty. 11 12// guarded header file to prevent multiple include compilation errors 13#ifndef LCS_DETAIL_H_ 14#define LCS_DETAIL_H_ 15 16 17namespace boost { 18 19namespace detail { 20 21// recursive lcs algorithm 22template<typename size_type, 23 typename ItIn1, 24 typename ItIn2, 25 typename ItSubSeq> 26size_type linear_space_lcs(ItIn1 begin_first, 27 ItIn1 end_first, 28 ItIn2 begin_second, 29 ItIn2 end_second, 30 ItSubSeq subsequence, 31 size_type *pA) 32{ 33#ifdef BOOST_STATIC_ASSERT // Not supported for BCC 5.5.1 34 BOOST_STATIC_ASSERT(boost::is_integral<size_type>::value); 35#endif 36 std::ptrdiff_t col, row; 37 38 // calculate the length of each subsequence 39 std::ptrdiff_t size_first = std::distance<>(begin_first, end_first); 40 std::ptrdiff_t size_second = std::distance<>(begin_second, end_second); 41 42#ifdef DBG_SCOPE 43 DBG_SCOPE(L"linear_space_lcs: Sequence lengths %lu and %lu", size_first, size_second); 44#endif 45 46 size_type lcs = 0; 47 48 // compare the heads of the sequences to skip equal 49 // elements more efficiently 50 while (size_first > 0 51 && size_second > 0 52 && *begin_first == *begin_second) 53 { 54 *subsequence++ = *begin_first; 55 ++begin_first; 56 ++begin_second; 57 --size_first; 58 --size_second; 59 ++lcs; 60 } 61 62 if (size_first == 0 || size_second == 0) 63 return lcs; 64 65 // initialise working array 66 const std::ptrdiff_t array_size = (size_first + 1) * sizeof(size_type) * 3; 67 memset(pA, 0, array_size); 68 size_type *pB = pA + size_first + 1; 69 std::ptrdiff_t *pO = reinterpret_cast<std::ptrdiff_t *>(pB + size_first + 1); 70 71 // we need to track the position in middle row that each entry 72 // comes from, so create another working array and initial each 73 // member to contains it's index 74 for (col=0; col<=size_first; ++col) 75 pO[col] = col; 76 77 // work down the imaginary array, until the 'middle' row is reached 78 ItIn2 it2 = begin_second; 79 for (row=1; row<=(size_second>>1); ++row, ++it2) 80 { 81 ItIn1 it1 = begin_first; 82 for (col=1; col<=size_first; ++col, ++it1) 83 { 84 if (*it1 == *it2) 85 pB[col] = 1 + pA[col-1]; 86 else 87 pB[col] = std::max(pB[col-1], pA[col]); 88 } 89 std::swap(pA, pB); 90 } 91 92 // now continue processing the rest of the imaginary array 93 for (; row<=size_second; ++row, ++it2) 94 { 95 ItIn1 it1 = begin_first; 96 for (col=1; col<=size_first; ++col, ++it1) 97 { 98 if (*it1 == *it2) 99 { 100 pB[col] = 1 + pA[col-1]; 101 pO[col] = pO[col-1]; 102 } 103 else if (pB[col-1] > pA[col]) 104 { 105 pB[col] = pB[col-1]; 106 pO[col] = pO[col-1]; 107 } 108 else 109 pB[col] = pA[col]; 110 } 111 std::swap(pA, pB); 112 } 113 114 // now we have reached the end of the imaginary array, the last entry 115 // in pA contains the length of the subsequence and the last entry 116 // in pO contains the position in the middle row that the last entry 117 // came from. This is the middle node along the solution path. 118 lcs += pA[size_first]; 119 if (lcs > 0) 120 { 121 if (size_second > 2 && pO[size_first] > 0) 122 { 123 ItIn1 left_it = begin_first; 124 ItIn1 left_ite = begin_first; 125 std::advance<>(left_ite, pO[size_first]); 126 127 ItIn2 right_it = begin_second; 128 ItIn2 right_ite = begin_second; 129 std::advance<>(right_ite, size_second>>1); 130 131 if ((size_second>>1) > 0 && pO[size_first] > 0) 132 { 133 linear_space_lcs<size_type>(left_it, left_ite, 134 right_it, right_ite, 135 subsequence, std::min(pA,pB)); 136 } 137 138 if (left_ite != end_first && right_ite != end_second) 139 { 140 linear_space_lcs<size_type>(left_ite, end_first, 141 right_ite, end_second, 142 subsequence, std::min(pA,pB)); 143 } 144 } 145 else 146 { 147 // Note that pA and pB have been swapped so pB is actually 148 // the top most row 149 ItIn1 it1 = begin_first; 150 size_type val = 1; 151 for (col=1; col<=size_first; ++col, ++it1) 152 { 153 if (pA[col] == pB[col-1]+1 && pA[col] == val) 154 { 155 *subsequence++ = *it1; 156 ++val; 157 } 158 } 159 } 160 } 161 162 return lcs; 163} 164 165} // namespace detail 166 167} // namespace boost 168 169#endif // LCS_DETAIL_H_