Nobody wrote:
....
> Any ideas?
You could use an "index" sort and this would be O(n) - this only works
if the elements are "indexable" i.e. a limited range otherwise you're
limited to nlogn.
i.e.
using an index sort:
a) create a "tally" vector<int> sized to the max element in the set.
b) scan through the elements incrementing the tally[index] in the vector.
c) scan through the elements a second time and stop on the first one
with tally[index] ==1.
If you can't use an index, you can sort the elements through a double
indirection:
a) create a "flags" vector<pair<bool,iterator>> setting first to true
and second to each consecutive iterator of the element list
b) create a "pointers" initialized to point to each element in flags
c) use a special compare routine that compares two * pair<bool,iterator>
if the (*second) are equal then set the first to false on both
operands.
d) scan through the "flags" vector looking for the first element with
first as "true".
This uses a property of sort algorithms (except for index sorts) that is
tricky to describe but I'll give it a go. While performing any sort on
any list of elements, any element that is duplicated must be compared to
at least one other duplicated element. Hence if you instrument the
compare operator of a sort algorithm, you can eliminate duplicate
elements. The corollary is that removing duplicates from a list of
elements need not be more complex that sorting. It's probably not any
easier than sorting either.
G
Here is an implementation of the second algorithm:
// ======== FirstUniqueDupeEliminator =================================
/**
* Helper for FirstUnique().
*
*/
template <
typename w_iterator
>
class FirstUniqueDupeEliminator
{
public:
typedef
std:

air<
bool,
w_iterator
> Element;
std::vector< Element > m_values;
std::vector< Element * > m_values_ptrs;
w_iterator m_result;
void Remove( Element * i_listiter )
{
i_listiter->first = false;
}
bool operator()( Element * i_rhs, Element * i_lhs )
{
// if we're pointing to the same element
// we don't do anything special
if ( i_lhs == i_rhs )
{
return false;
}
if ( *(i_lhs->second) < *(i_rhs->second) )
{
return true;
}
if ( *(i_rhs->second) < *(i_lhs->second) )
{
return false;
}
// oops they're the same eliminate the elements from the list
//
Remove( i_rhs );
Remove( i_lhs );
return false;
}
FirstUniqueDupeEliminator(
const w_iterator & i_begin,
const w_iterator & i_end
)
{
if ( i_begin == i_end )
{
m_result = i_end;
return;
}
w_iterator l_tmp = i_begin;
while ( l_tmp != i_end )
{
m_values.push_back( Element( true, l_tmp ) );
++ l_tmp;
}
m_values_ptrs.resize( m_values.size() );
for ( std::size_t i = 0; i < m_values.size(); ++i )
{
m_values_ptrs[ i ] = & m_values[ i ];
}
std::sort( m_values_ptrs.begin(), m_values_ptrs.end(), *this );
for ( std::size_t i = 0; i < m_values.size(); ++i )
{
if ( m_values[ i ].first )
{
m_result = m_values[ i ].second;
return;
}
}
m_result = i_end;
}
operator w_iterator() const
{
return m_result;
}
};
// ======== FirstUnique ===============================================
/**
* FirstUnique returns the first unique element in a container
*
* @param i_begin The first element in the continer
* @param i_end The last element in the container
*
* @return The iterator to the first element in the
* range that is unique or i_end if no elements are unique
*/
template <
typename w_iterator
>
w_iterator FirstUnique(
const w_iterator & i_begin,
const w_iterator & i_end
) {
return FirstUniqueDupeEliminator<w_iterator>( i_begin, i_end );
}
const int array[] = { 3,1,3,7,1,2,4,4,3 };
int main()
{
const int * l_val = FirstUnique(
&array[0], at::ArrayEnd( array )
);
}