/lcs_detail.hpp

http://github.com/cdmh/algorithms · 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. // guarded header file to prevent multiple include compilation errors
  12. #ifndef LCS_DETAIL_H_
  13. #define LCS_DETAIL_H_
  14. namespace boost {
  15. namespace detail {
  16. // recursive lcs algorithm
  17. template<typename size_type,
  18. typename ItIn1,
  19. typename ItIn2,
  20. typename ItSubSeq>
  21. size_type linear_space_lcs(ItIn1 begin_first,
  22. ItIn1 end_first,
  23. ItIn2 begin_second,
  24. ItIn2 end_second,
  25. ItSubSeq subsequence,
  26. size_type *pA)
  27. {
  28. #ifdef BOOST_STATIC_ASSERT // Not supported for BCC 5.5.1
  29. BOOST_STATIC_ASSERT(boost::is_integral<size_type>::value);
  30. #endif
  31. std::ptrdiff_t col, row;
  32. // calculate the length of each subsequence
  33. std::ptrdiff_t size_first = std::distance<>(begin_first, end_first);
  34. std::ptrdiff_t size_second = std::distance<>(begin_second, end_second);
  35. #ifdef DBG_SCOPE
  36. DBG_SCOPE(L"linear_space_lcs: Sequence lengths %lu and %lu", size_first, size_second);
  37. #endif
  38. size_type lcs = 0;
  39. // compare the heads of the sequences to skip equal
  40. // elements more efficiently
  41. while (size_first > 0
  42. && size_second > 0
  43. && *begin_first == *begin_second)
  44. {
  45. *subsequence++ = *begin_first;
  46. ++begin_first;
  47. ++begin_second;
  48. --size_first;
  49. --size_second;
  50. ++lcs;
  51. }
  52. if (size_first == 0 || size_second == 0)
  53. return lcs;
  54. // initialise working array
  55. const std::ptrdiff_t array_size = (size_first + 1) * sizeof(size_type) * 3;
  56. memset(pA, 0, array_size);
  57. size_type *pB = pA + size_first + 1;
  58. std::ptrdiff_t *pO = reinterpret_cast<std::ptrdiff_t *>(pB + size_first + 1);
  59. // we need to track the position in middle row that each entry
  60. // comes from, so create another working array and initial each
  61. // member to contains it's index
  62. for (col=0; col<=size_first; ++col)
  63. pO[col] = col;
  64. // work down the imaginary array, until the 'middle' row is reached
  65. ItIn2 it2 = begin_second;
  66. for (row=1; row<=(size_second>>1); ++row, ++it2)
  67. {
  68. ItIn1 it1 = begin_first;
  69. for (col=1; col<=size_first; ++col, ++it1)
  70. {
  71. if (*it1 == *it2)
  72. pB[col] = 1 + pA[col-1];
  73. else
  74. pB[col] = std::max(pB[col-1], pA[col]);
  75. }
  76. std::swap(pA, pB);
  77. }
  78. // now continue processing the rest of the imaginary array
  79. for (; row<=size_second; ++row, ++it2)
  80. {
  81. ItIn1 it1 = begin_first;
  82. for (col=1; col<=size_first; ++col, ++it1)
  83. {
  84. if (*it1 == *it2)
  85. {
  86. pB[col] = 1 + pA[col-1];
  87. pO[col] = pO[col-1];
  88. }
  89. else if (pB[col-1] > pA[col])
  90. {
  91. pB[col] = pB[col-1];
  92. pO[col] = pO[col-1];
  93. }
  94. else
  95. pB[col] = pA[col];
  96. }
  97. std::swap(pA, pB);
  98. }
  99. // now we have reached the end of the imaginary array, the last entry
  100. // in pA contains the length of the subsequence and the last entry
  101. // in pO contains the position in the middle row that the last entry
  102. // came from. This is the middle node along the solution path.
  103. lcs += pA[size_first];
  104. if (lcs > 0)
  105. {
  106. if (size_second > 2 && pO[size_first] > 0)
  107. {
  108. ItIn1 left_it = begin_first;
  109. ItIn1 left_ite = begin_first;
  110. std::advance<>(left_ite, pO[size_first]);
  111. ItIn2 right_it = begin_second;
  112. ItIn2 right_ite = begin_second;
  113. std::advance<>(right_ite, size_second>>1);
  114. if ((size_second>>1) > 0 && pO[size_first] > 0)
  115. {
  116. linear_space_lcs<size_type>(left_it, left_ite,
  117. right_it, right_ite,
  118. subsequence, std::min(pA,pB));
  119. }
  120. if (left_ite != end_first && right_ite != end_second)
  121. {
  122. linear_space_lcs<size_type>(left_ite, end_first,
  123. right_ite, end_second,
  124. subsequence, std::min(pA,pB));
  125. }
  126. }
  127. else
  128. {
  129. // Note that pA and pB have been swapped so pB is actually
  130. // the top most row
  131. ItIn1 it1 = begin_first;
  132. size_type val = 1;
  133. for (col=1; col<=size_first; ++col, ++it1)
  134. {
  135. if (pA[col] == pB[col-1]+1 && pA[col] == val)
  136. {
  137. *subsequence++ = *it1;
  138. ++val;
  139. }
  140. }
  141. }
  142. }
  143. return lcs;
  144. }
  145. } // namespace detail
  146. } // namespace boost
  147. #endif // LCS_DETAIL_H_