John Torjo有一篇很好的文章,它以系統的方式處理這個問題。他出現的結果似乎更通用,更高效比任何解決方案,至今這裏建議:
http://www.builderau.com.au/program/java/soa/C-Removing-duplicates-from-a-range/0,339024620,320271583,00.htm
https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-1052159.html
不幸的是,約翰的解決方案的完整的代碼似乎不再可用,約翰沒有迴應可能發送電子郵件。因此,我寫了我自己的代碼,基於類似他的理由,但在一些細節上故意有所不同。如果您願意,請隨時與我聯繫(vschoech think-cell com)並討論細節。
爲了讓代碼爲你編譯,我添加了一些我自己定期使用的庫東西。另外,我不用簡單的stl,而是使用boost來創建更通用,更高效,更易讀的代碼。
玩得開心!
#include <vector>
#include <functional>
#include <boost/bind.hpp>
#include <boost/range.hpp>
#include <boost/iterator/counting_iterator.hpp>
/////////////////////////////////////////////////////////////////////////////////////////////
// library stuff
template< class Rng, class Func >
Func for_each(Rng& rng, Func f) {
return std::for_each(boost::begin(rng), boost::end(rng), f);
};
template< class Rng, class Pred >
Rng& sort(Rng& rng, Pred pred) {
std::sort(boost::begin(rng), boost::end(rng), pred);
return rng; // to allow function chaining, similar to operator+= et al.
}
template< class T >
boost::iterator_range< boost::counting_iterator<T> > make_counting_range(T const& tBegin, T const& tEnd) {
return boost::iterator_range< boost::counting_iterator<T> >(tBegin, tEnd);
}
template< class Func >
class compare_less_impl {
private:
Func m_func;
public:
typedef bool result_type;
compare_less_impl(Func func)
: m_func(func)
{}
template< class T1, class T2 > bool operator()(T1 const& tLeft, T2 const& tRight) const {
return m_func(tLeft) < m_func(tRight);
}
};
template< class Func >
compare_less_impl<Func> compare_less(Func func) {
return compare_less_impl<Func>(func);
}
/////////////////////////////////////////////////////////////////////////////////////////////
// stable_unique
template<class forward_iterator, class predicate_type>
forward_iterator stable_unique(forward_iterator itBegin, forward_iterator itEnd, predicate_type predLess) {
typedef std::iterator_traits<forward_iterator>::difference_type index_type;
struct SIteratorIndex {
SIteratorIndex(forward_iterator itValue, index_type idx) : m_itValue(itValue), m_idx(idx) {}
std::iterator_traits<forward_iterator>::reference Value() const {return *m_itValue;}
index_type m_idx;
private:
forward_iterator m_itValue;
};
// {1} create array of values (represented by iterators) and indices
std::vector<SIteratorIndex> vecitidx;
vecitidx.reserve(std::distance(itBegin, itEnd));
struct FPushBackIteratorIndex {
FPushBackIteratorIndex(std::vector<SIteratorIndex>& vecitidx) : m_vecitidx(vecitidx) {}
void operator()(forward_iterator itValue) const {
m_vecitidx.push_back(SIteratorIndex(itValue, m_vecitidx.size()));
}
private:
std::vector<SIteratorIndex>& m_vecitidx;
};
for_each(make_counting_range(itBegin, itEnd), FPushBackIteratorIndex(vecitidx));
// {2} sort by underlying value
struct FStableCompareByValue {
FStableCompareByValue(predicate_type predLess) : m_predLess(predLess) {}
bool operator()(SIteratorIndex const& itidxA, SIteratorIndex const& itidxB) {
return m_predLess(itidxA.Value(), itidxB.Value())
// stable sort order, index is secondary criterion
|| !m_predLess(itidxB.Value(), itidxA.Value()) && itidxA.m_idx < itidxB.m_idx;
}
private:
predicate_type m_predLess;
};
sort(vecitidx, FStableCompareByValue(predLess));
// {3} apply std::unique to the sorted vector, removing duplicate values
vecitidx.erase(
std::unique(vecitidx.begin(), vecitidx.end(),
!boost::bind(predLess,
// redundand boost::mem_fn required to compile
boost::bind(boost::mem_fn(&SIteratorIndex::Value), _1),
boost::bind(boost::mem_fn(&SIteratorIndex::Value), _2)
)
),
vecitidx.end()
);
// {4} re-sort by index to match original order
sort(vecitidx, compare_less(boost::mem_fn(&SIteratorIndex::m_idx)));
// {5} keep only those values in the original range that were not removed by std::unique
std::vector<SIteratorIndex>::iterator ititidx = vecitidx.begin();
forward_iterator itSrc = itBegin;
index_type idx = 0;
for(;;) {
if(ititidx==vecitidx.end()) {
// {6} return end of unique range
return itSrc;
}
if(idx!=ititidx->m_idx) {
// original range must be modified
break;
}
++ititidx;
++idx;
++itSrc;
}
forward_iterator itDst = itSrc;
do {
++idx;
++itSrc;
// while there are still items in vecitidx, there must also be corresponding items in the original range
if(idx==ititidx->m_idx) {
std::swap(*itDst, *itSrc); // C++0x move
++ititidx;
++itDst;
}
} while(ititidx!=vecitidx.end());
// {6} return end of unique range
return itDst;
}
template<class forward_iterator>
forward_iterator stable_unique(forward_iterator itBegin, forward_iterator itEnd) {
return stable_unique(itBegin, itEnd, std::less< std::iterator_traits<forward_iterator>::value_type >());
}
void stable_unique_test() {
std::vector<int> vecn;
vecn.push_back(1);
vecn.push_back(17);
vecn.push_back(-100);
vecn.push_back(17);
vecn.push_back(1);
vecn.push_back(17);
vecn.push_back(53);
vecn.erase(stable_unique(vecn.begin(), vecn.end()), vecn.end());
// result: 1, 17, -100, 53
}
由於從元素構造一個集合需要花費O(n log n),所以不可能構造一個集合並且保持所看到的順序。所以,選擇一個O(n log n)然後去。 – 2012-06-19 11:35:02