mardi 21 avril 2015

how to implement a commonly used sort function with C++?

How to implement a commonly used sort function with C++?

This sort function:

  • Can be used for any comparable type.
  • Can be used for C-style array or C++ containers (like vector or list)
  • Can be used for the containers with different kinds of iterators, such as RandomAccessIterator, ForwardIterator, BidirectionIterator, etc.
  • Users can define their own comparing function / factor / lambda function

Here is an example with C++11. It works well with my g++4.6 compiler.

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>

using namespace std;

template<typename RandomAccessor>
struct myiter_traits {
    typedef typename RandomAccessor::value_type value_type;
};

template<typename T>
struct myiter_traits<T*> {
    typedef T value_type;
};

template<typename RandomAccessor>
RandomAccessor mypartition(
        const RandomAccessor& head,
        const RandomAccessor& tail,
        function<bool(
            typename myiter_traits<RandomAccessor>::value_type va, 
            typename myiter_traits<RandomAccessor>::value_type vb)> cmp) {
    RandomAccessor pivot = head;
    RandomAccessor l = head;
    RandomAccessor r = tail - 1;
    int ptr = 0;
    while (l <= r) {
        while (l <= r) {
            bool lt = cmp(*l, *pivot);
            bool gt = cmp(*pivot, *l);
            bool eq = !lt && !gt;
            if (lt || (eq && ptr == 0)) {
                l++;
                ptr ^= (eq? 1: 0);
            } else {
                break;
            }
        }
        while (l <= r) {
            bool lt = cmp(*r, *pivot);
            bool gt = cmp(*pivot, *r);
            bool eq = !lt && !gt;
            if (gt || (eq && ptr == 1)) {
                r--;
                ptr ^= (eq? 1: 0);
            } else {
                break;
            }
        }
        if (l <= r) {
            swap(*l, *r);
            l++;
            r--;
        }
    }
    swap(*pivot, *r);
    return r;
}

template<typename RandomAccessor>
void mysortWithRandomAccessor(
        const RandomAccessor& head,
        const RandomAccessor& tail,
        function<bool(
            typename myiter_traits<RandomAccessor>::value_type va, 
            typename myiter_traits<RandomAccessor>::value_type vb)> cmp
    ) {
    if (tail - head <= 1) {
        return;
    }
    const RandomAccessor pivot = mypartition(head, tail, cmp);

    mysortWithRandomAccessor(head, pivot, cmp);
    mysortWithRandomAccessor(pivot + 1, tail, cmp);
}

int main() {
    function<bool(int, int)> myless    = [](int a, int b)->bool { return a < b; };
    function<bool(int, int)> mygreater = [](int a, int b)->bool { return a > b; };

    vector<int> vec({2, 1, 3, 0, 4, 1999});

    mysortWithRandomAccessor(vec.begin(), vec.end(), myless);
    for (const auto& i: vec) {
        printf("%d ", i);
    }
    puts("");

    int array[] = {99, 19, 9999};
    mysortWithRandomAccessor(array + 0, array + 3, mygreater);
    for (int i = 0; i < 3; i++) {
        printf("%d ", array[i]);
    }
    puts("");

    return 0;
}

Aucun commentaire:

Enregistrer un commentaire