4

I'm running a test showing the benefits of sorting a 2d array, by columns, by pulling the data off into an individual array and sorting that array, then copying it back to the column. I'm wanting to run std::sort as a the sorting algorithm for every run. I'm trying to figure out how to run the loop in place first, before moving into the copying on and off the 2D array. An example of the input / output would be this.

#include <iostream>
#include <algorithm>

int main() {
    int input[][5] =  { { 13, 27, 4 , 1 , 11 },
                        { 11, 19, 2 , 37, 1  },
                        { 32, 64, 11, 22, 41 },
                        { 71, 13, 27, -8, -2 },
                        { 0 , -9, 11, 99, 13 } };

    // std::sort something here.

    int output[][5] = { { 0 , -9, 2 , -8, -2 },
                        { 11, 13, 4 , 1 , 1  },
                        { 13, 19, 11, 22, 11 },
                        { 32, 27, 11, 37, 13 },
                        { 71, 64, 27, 99, 41 } };                      
    return 0;
}

Thanks for the help.

7
  • Do you want to sort each array separately or is the 2D array considered one big one? Commented Jan 8, 2014 at 4:41
  • I basically want to isolate each column and sort that column. Commented Jan 8, 2014 at 4:44
  • How would I do it given vectors? Commented Jan 8, 2014 at 4:45
  • 1
    Maybe you should have a look into how to rotate the matrix you have there, sort each row, and rotate back. Commented Jan 8, 2014 at 4:49
  • 1
    Standard sort take iterators. You could define you own iterator that steps row-lenght spaces. Commented Jan 8, 2014 at 4:50

3 Answers 3

3

You may write your own iterator, something like:

#include <iterator>

template<typename Container>
class column_iterator : public std::iterator<std::random_access_iterator_tag,
                                            typename std::decay<decltype(std::declval<Container>()[0][0])>::type>
{
    typedef typename Container::iterator iterator;
    typedef typename std::decay<decltype(std::declval<Container>()[0][0])>::type type;
public:

    column_iterator(iterator it, int n) : it(it), n(n) {}

    column_iterator& operator++() {++it; return *this;}
    column_iterator& operator++(int) { auto res(*this); ++*this; return res;}
    column_iterator& operator +=(std::ptrdiff_t offset) { it += offset; return *this;}
    column_iterator operator +(std::ptrdiff_t offset) const { auto res(*this); res += offset; return res;}

    column_iterator& operator--() {--it; return *this;}
    column_iterator& operator--(int) { auto res(*this); --*this; return res;}
    column_iterator& operator -=(std::ptrdiff_t offset) { it -= offset; return *this;}
    column_iterator operator -(std::ptrdiff_t offset) const { auto res(*this); res -= offset; return res;}

    type& operator*() { return (*it)[n];}
    type* operator->() { return &(it)[n];}

    bool operator == (const column_iterator& rhs) const { return it == rhs.it && n == rhs.n; }
    bool operator != (const column_iterator& rhs) const { return !(*this == rhs); }
    bool operator < (const column_iterator& rhs) const { return it < rhs.it; }

    std::ptrdiff_t operator -(const column_iterator& rhs) const { return it - rhs.it; }

private:
    iterator it;
    int n;
};

template<typename Container>
column_iterator<Container> begin(Container& cont, int n)
{
    return column_iterator<Container>(cont.begin(), n);
}

template<typename Container>
column_iterator<Container> end(Container& cont, int n)
{
    return column_iterator<Container>(cont.end(), n);
}

Now, let's test it:

#include <algorithm>
#include <array>
#include <iostream>
#include <vector>
#include <cassert>

void display(const std::vector<std::array<int, 5>>& v)
{
    for (auto rows : v) {
        for (auto elem : rows) {
            std::cout << elem << " ";
        }
        std::cout << std::endl;
    }
}

int main() {
    std::vector<std::array<int, 5>> input {
                        {{ 13, 27, 4 , 1 , 11 }},
                        {{ 11, 19, 2 , 37, 1  }},
                        {{ 32, 64, 11, 22, 41 }},
                        {{ 71, 13, 27, -8, -2 }},
                        {{ 0 , -9, 11, 99, 13 }} };

    for (int i = 0; i != 5; ++i) {
        std::sort(begin(input, i), end(input, i));
    }

    display(input);

    const std::vector<std::array<int, 5>> output {
                        {{ 0 , -9, 2 , -8, -2 }},
                        {{ 11, 13, 4 , 1 , 1  }},
                        {{ 13, 19, 11, 22, 11 }},
                        {{ 32, 27, 11, 37, 13 }},
                        {{ 71, 64, 27, 99, 41 }} };

    assert(input == output);
    return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

great atlast i found adapter that rely on boost
1

You can copy each column into a temp array,sort them and put them back into output array

for(j=0;j<5;++j)
{
 for(i=0;i<5;++i)
  {
    temp[i]=input[i][j];
  }
    //sort temp[i]
    //put it in output array
}

1 Comment

Planning on doing that later for a comparison, baseline is an inline sort.
0

I finally gave up and decided to write my own version to compare with. I think I'm just going to keep all versions of the sorting algorithm similar to this.

@RichardPlunkett I tried creating my own compare function but was worried about it swapping entire rows.

#include <iostream>
#include <vector>
#include <random>

void sort (std::vector<std::vector<int> >& array, int start, int stop, int pos) {
  if (stop - start < 2) return;

  int mid = (start + stop) / 2;
  int i = start, j = stop, pivot = array[mid][pos];
  while (true) {
    while (array[i][pos] < pivot) i++;
    while (array[j][pos] > pivot) j--;
    if (i > j) break;
    std::swap(array[i++][pos], array[j--][pos]);
  }

  sort (array, start, j, pos);
  sort (array, i, stop, pos);
}

int main() {
  const int size = 10;
  std::random_device rd;
  std::default_random_engine generator(rd());
  std::uniform_int_distribution<int> distribution(-10,10);
  std::vector<std::vector<int> > test(size, std::vector<int>(size));

  std::cout << "Unsorted array: \n";
  for (int i=0;i<(int) test.size();++i) {
    for (int j=0;j<(int) test[i].size();++j) {
      test[i][j] = distribution(generator);
      std::cout << test[i][j] << '\t';
    }
    std::cout << std::endl;
  }

  for (int i=0;i<size;++i)
    sort(test, 0, size-1, i);

  std::cout << "\nSorted array: \n";
  for (int i=0;i<(int) test.size();++i) {
    for (int j=0;j<(int) test[i].size();++j)
      std::cout << test[i][j] << '\t';
    std::cout << ' ' << std::endl;
  }
  return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.