简体   繁体   中英

sort multidimensional std::vector as single vector

Is there a way to sort multidimensional std::vector like that:

std::vector<std::vector<int> > vec = { {3,1,2}, {5,4,6} };

result: { {1, 2, 3}, {4, 5, 6} }

without creating another temporary vectors?

I think, i need treat multidimensional std::vector like simple vector, something like that:

int* begin = &vec[0][0];
int* end = ....
std::sort(begin, end);

If all elements located continuously in memory, and if i understand std::vector correctly all i need is just a pointer to first element and last. For check this thought, i create simple test - print all elements from multidimensional vector without nested loop. But test returned wrong result.

    std::vector<std::vector<int> > vec(10);
    for(int i = 0; i < vec.size(); ++i)
    {
            std::vector<int> tmp(1);
            tmp[0] = i;
            vec[i] = tmp;
    }
    int* a = &vec[0][0];
    for(int i = 0; i < vec.size(); i++) {
            std::cout << *a << " ";
            ++a;
    }
    std::cout << std::endl;

0 0 0 0 0 0 33 0 1 0

std::vector guarantees to store elements continuously. However, a vector consists of more than its elements. Thus, if you iterate over the boundary of one of the inner vectors you will not end up on the first element of the next inner vector. Instead you'll end up on one of the (private) members of either vector.

To solve your problem, you could for example write a custom iterator, which you can pass to std::sort . std::sort requires a random access iterator . Assuming that your inner vector are always of the same length ( 3 ) such an iterator implementation might look something like this:

struct myiter
{
    myiter() : m_vec(NULL), m_idx(0) {}
    myiter(std::vector<std::vector<int>>& vec, int idx=0) : m_vec(&vec), m_idx(idx) {}
    myiter(myiter& other) : m_vec(other.m_vec), m_idx(other.m_idx) {}

    myiter& operator++()
    {
        m_idx++;
        return *this;
    }

    myiter& operator++(int)
    {
        myiter& self = *this;
        m_idx++;
        return self;
    }

    myiter& operator--()
    {
        m_idx--;
        return *this;
    }

    myiter& operator--(int)
    {
        myiter& self = *this;
        m_idx--;
        return self;
    }

    myiter operator + (int n) const
    {
        return myiter(*m_vec, m_idx+n);
    }

    myiter operator - (int n) const
    {
        return myiter(*m_vec, m_idx-n);
    }

    int operator - (myiter rhs) const
    {
        if (m_vec != rhs.m_vec) throw std::exception("incompatible iterators");
        return m_idx-rhs.m_idx;
    }

    int& operator*()
    {
        return (*m_vec)[m_idx/3][m_idx%3];
    }

    bool operator == (const myiter& rhs) const
    {
        return (m_vec == rhs.m_vec && m_idx == rhs.m_idx);
    }

    bool operator != (const myiter& rhs) const
    {
        return !operator==(rhs);
    }

    bool operator < (const myiter& rhs) const
    {
        if (m_vec != rhs.m_vec) throw std::exception("incompatible iterators");
        return m_idx<rhs.m_idx;
    }

    std::vector<std::vector<int>>* m_vec;
    int m_idx;
};

template<>
struct std::iterator_traits<myiter> {
    typedef int difference_type;
    typedef int value_type;
    typedef int& reference;
    typedef int* pointer;
    typedef std::random_access_iterator_tag iterator_category;
};

With this iterator you could then use std::sort as follows:

std::sort(myiter(vec), myiter(vec,vec.size()*3));

As already mentioned, the above iterator implementation assumes, that your inner vectors are always of size 3. If their size varies, you might want to store two iterators instead of m_idx . One to iterate over the outer vector and one to iterate over the inner vector to which the first iterator points.

I think you could use something like this:

std::for_each(std::begin(vec), std::end(vec), [](auto &v) { std::sort(std::begin(v), std::end(v));});
std::sort(std::begin(vec), std::end(vec), [](auto &v1, auto &v2) { return v1[0] < v2[0];});
std::cout << vec << std::endl;

if I understand you correctly once you've sorted the inner vectors you can order them by the first value.

The problem with your solution is that you assume that not only the vactors are continuous but also all their elements but it's wrong all you know is that each vector's elements are contiguous and that the vector of vector objects (eg in memory vec: |v1|v2|...|vn| ) is contiguous but not all the elements of all subvectors.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM