On Thu, Jan 22, 2015 at 02:51:38PM -0800, H. S. Teoh via Digitalmars-d wrote:
> On Thu, Jan 22, 2015 at 02:29:58PM -0800, Andrei Alexandrescu via 
> Digitalmars-d wrote:
> [...]
> > Thanks. I'm thinking of something based on general comparisons.
> > Something like a modified quicksort with fat pivot:
> > 
> > A. Partition into three subranges: R1<pivot, R2=pivot, R3>pivot
> > 
> > B. Recurse on R1 obtaining R11, a subrange of R1 containing only
> > unique elements.
> > 
> > C. Sort-move-unique R2 into the portion after R11, obtaining the
> > result.
> > 
> > A and B seem fine, I'm unclear about C. It would be an algorithm that
> > sorts and simultaneously moves data in a range that overlaps the
> > input.
> [...]
> 
> Wait, if R1 and R3, after the recursion, are sorted and contain only
> unique elements, doesn't that mean that we can just collapse R2 into a
> single element along with the endpoints of R1 and R3? So if R1[$-1] <
> pivot, then we're done, otherwise coalesce it with the pivot, and
> likewise with R3[0].
[...]

Working proof of concept:

        import std.algorithm;
        import std.array;
        import std.stdio;
        
        // Returns: final index of pivot
        size_t partition(R)(R r)
        {
            auto pivot = r[0];
            swap(r[0], r[$-1]); // move pivot to end
        
            auto leftIdx = 0;
            foreach (i; 0 .. r.length)
            {
                if (r[i] < pivot)
                    swap(r[i], r[leftIdx++]);
            }
            swap(r[leftIdx], r[$-1]);
        
            return leftIdx;
        }
        
        R uniqueSort(R)(R r)
        {
            if (r.empty) return r;
        
            // Partition
            auto pivotIdx = partition(r);
            auto pivot = r[pivotIdx];
        
            // Recurse
            auto left = uniqueSort(r[0 .. pivotIdx]);
            auto right = uniqueSort(r[pivotIdx + 1 .. $]);
        
            // Coalesce left ~ pivot ~ right.
            if (!left.empty && left[$-1] == pivot)
                left = left[0 .. $-1];
        
            if (!right.empty && right[0] == pivot)
                right = right[1 .. $];
        
            r[left.length] = pivot;
            auto vacant = copy(right, r[left.length + 1 .. $]);
        
            return r[0 .. $ - vacant.length];
        }
        
        unittest
        {
            auto data = [4, 0, 9, 7, 2, 5, 1, 1, 3, 4, 2, 0, 9, 5, 3, 6, 1, 7, 
4, 8];
            auto sorted = data.uniqueSort();
        
            assert(sorted == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
        }


I'm not sure about the performance of this algorithm, though, because
the call to copy() might become prohibitive once you add up all the
recursive calls to uniqueSort().

Also, I only got one test case working; no idea if there are subtle bugs
that are lurking in there somewhere. Please test with more test cases.
:-)


T

-- 
"No, John.  I want formats that are actually useful, rather than over-featured 
megaliths that address all questions by piling on ridiculous internal links in 
forms which are hideously over-complex." -- Simon St. Laurent on xml-dev

Reply via email to