PageRenderTime 29ms CodeModel.GetById 17ms app.highlight 11ms RepoModel.GetById 0ms app.codeStats 0ms

/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
 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_