C++ EIGEN: How to create triangular matrix map from a vector? - c++

I would like to use data stored into an Eigen (https://eigen.tuxfamily.org) vector
Eigen::Vector<double, 6> vec({1,2,3,4,5,6});
as if they were a triangular matrix
1 2 3
0 4 5
0 0 6
I know how to do it for a full matrix using Eigen's Map
Eigen::Vector<double, 9> vec({1,2,3,4,5,6,7,8,9});
std::cout << Eigen::Map<Eigen::Matrix<double, 3, 3, RowMajor>>(vec.data());
which produces
1 2 3
4 5 6
7 8 9
However I do not know how to make a Map to a triangular matrix.
Is it possible?
Thanks!
[Edited for clarity]

In my opinion this cannot be done using Map only: The implementation of Map as it is relies on stride sizes that remain constant no matter their index positions, see https://eigen.tuxfamily.org/dox/classEigen_1_1Stride.html.
To implement a triangular matrix map you would have to have a Map that changes its inner stride depending on the actual column number. The interfaces in Eigen do not allow that at the moment, see https://eigen.tuxfamily.org/dox/Map_8h_source.html.
But if you are just concerned about the extra memory you can just use Eigen's sparse matrix representation:
https://eigen.tuxfamily.org/dox/group__TutorialSparse.html
(Refer to section "Filling a sparse matrix".)

This is not a direct solution to your problem but a way how to calculate the std::vector to fill in the 0 at the correct place. I think it is also possible to calculate it as a std::array if needed. I am not sure if that helps, but I guess you could use the calculated vector to fill the Eigen::Map
#include <array>
#include <cstddef>
#include <iostream>
#include <vector>
template<typename T, size_t N>
class EigenVector
{
static constexpr int CalculateRowColSize(size_t n)
{
size_t i = 1;
size_t inc = 1;
do
{
if (inc == n)
{
return static_cast<int>(i);
}
i++;
inc += i;
} while (i < n);
return -1;
}
static constexpr bool IsValid(size_t n)
{
if(CalculateRowColSize(n) == -1)
{
return false;
}
return true;
}
static_assert(IsValid(N));
public:
EigenVector() = delete;
static std::vector<T> Calculate(std::array<T, N> values)
{
constexpr size_t mRowColSize = CalculateRowColSize(N);
std::vector<T> ret;
auto count = 0;
auto valueCounter = 0;
for (size_t i = 0; i < mRowColSize; i++)
{
for (auto j = 0; j < count; j++)
{
ret.push_back(T());
}
for (size_t j = 0; j < mRowColSize - count; j++)
{
ret.push_back(values[valueCounter]);
valueCounter++;
}
count++;
}
return ret;
}
};
int main()
{
{
const std::array<int, 6> arr{ 1,2,3,4,5,6 };
const auto values = EigenVector<int, 6>::Calculate(arr);
for (auto& val : values)
{
std::cout << val << " ";
}
}
std::cout << std::endl << std::endl;
{
const std::array<int, 10> arr{ 1,2,3,4,5,6,7,8,9,10 };
const auto values = EigenVector<int, 10>::Calculate(arr);
for (auto& val : values)
{
std::cout << val << " ";
}
}
return 0;
}
Output:
1 2 3 0 4 5 0 0 6
1 2 3 4 0 5 6 7 0 0 8 9 0 0 0 10
Note that the algorithm is written that only possible matrix sizes are valid as input

Related

generic slicing (views) of multidimensional array in C++20 using ranges

In Python, accessing a subset of a multidimensional numpy is normally done using the slicing sintax [bx:ex] for a 1D array, [bx:ex,by:ey] for a 2D array and so on and so forth. It is also possible to write a code which is generic such as
def foo(Vin,Vout,lows,highs):
# Vin and Vout are numpys with dimension len(lows)
# and len(lows)=len(highs)
S=tuple(slice(l,h) for l,h in zip(lows,highs))
Vout[S]=Vin[S]
I would like to achieve something similar in C++, where the data is stored in a std::vector and having the same performance (or better) of a bunch of nested for-loops which for a 3D array would look like
for (int k=lz; k<hz; ++k)
for (int j=ly; j<hy; ++j)
for (int i=lx; i<hx; ++i)
Vout[i+nx*(j+ny*k)=Vin[i+nx*(j+ny*k)];
Could this be done using C++20 ranges?
The long term goal is to generate lazily evaluated views of subsets of multidimensional arrays that can be combined together. In other words, being able to fuse loops without creating intermediate arrays.
I am not sure about the performance, but here is one option.
You create a templated struct MD<N,M,L> that takes array dimensions N,M,L and has a static function slice.
slice takes a flat input range and one Slice instance per dimension and returns a corresponding multidimensional range over the elements of the flat input range.
The Slice instances are just structs containing a start index and an optional end index.
You can use deep_flatten from this SO answer to prevent having to use nested for loops over the multidimensional range. Note that the returned range is just an input_range, which does not have a rich interface.
#include <vector>
#include <ranges>
#include <cassert>
#include <iostream>
template <size_t dim>
struct Slice {
// default constructor leaves start at zero and end empty. Correspondes to the whole dimension
constexpr Slice() = default;
// Create a slice with a single index
constexpr Slice(size_t i) : begin(i), end(i+1) {
assert( (0 <= i) && (i < dim));
}
// Create a slice with a start and an end index
constexpr Slice(size_t s, size_t e) : begin(s), end(e+1) {
assert( (0 <= s) && (s <= e) && (e < dim) );
}
size_t begin {0};
size_t end {dim};
};
// An adaptor object to interpret a flat range as a multidimensional array
template <size_t dim, size_t... dims>
struct MD {
constexpr static auto dimensions = std::make_tuple(dim, dims...);
consteval static size_t size(){
if constexpr (sizeof...(dims) > 0) {
return dim*(dims * ...);
}
else {
return dim;
}
}
// returns a multidimensional range over the elements in the flat array
template <typename Rng>
constexpr static auto slice(
Rng&& range,
Slice<dim> const& slice,
Slice<dims> const&... slices
)
{
return slice_impl(range, 0, slice, slices...);
}
template <typename Rng>
constexpr static auto slice_impl(
Rng&& range,
size_t flat_index,
Slice<dim> const& slice,
Slice<dims> const&... slices
)
{
if constexpr (std::ranges::sized_range<Rng>) { assert(std::size(range) >= size()); }
static_assert(sizeof...(slices) == sizeof...(dims), "wrong number of slice arguments.");
if constexpr (sizeof...(slices) == 0)
{
// end recursion at inner most range
return range | std::views::drop(flat_index*dim + slice.begin) | std::views::take(slice.end - slice.begin);
}
else
{
// for every index to be kept in this dimension, recurse to the next dimension and increment the flat_index
return std::views::iota(slice.begin, slice.end) | std::views::transform(
[&range, flat_index, slices...](size_t i){
return MD<dims...>::slice_impl(range, flat_index*dim + i, slices...);
}
);
}
}
// convenience function for the full view
template <typename Rng>
constexpr static auto as_range(Rng&& range){
return slice(range, Slice<dim>{}, Slice<dims>{}...);
}
};
// recursively join a range of ranges
// https://stackoverflow.com/questions/63249315/use-of-auto-before-deduction-of-auto-with-recursive-concept-based-fun
template <typename Rng>
auto flat(Rng&& rng) {
using namespace std::ranges;
auto joined = rng | views::join;
if constexpr (range<range_value_t<decltype(joined)>>) {
return flat(joined);
} else {
return joined;
}
}
int main()
{
static_assert(MD<2,3,2>::size() == 12);
static_assert(std::get<0>(MD<2,3,2>::dimensions) == 2);
static_assert(std::get<1>(MD<2,3,2>::dimensions) == 3);
static_assert(std::get<0>(MD<2,3,2>::dimensions) == 2);
std::vector v = {1,2,3,4,5,6,7,8,9,10,11,12};
// obtain the full view of the data, interpreted as a 2x3x2 array
auto full = MD<2,3,2>::as_range(v);
// print the full view
std::cout << "data interpreted as 2x3x2 array:\n";
for (size_t i=0; i < full.size(); i++) {
std::cout << "index " << i << ":\n";
for (auto const& d3 : full[i]) {
for (auto const& val : d3) {
std::cout << val << " ";
}
std::cout << "\n";
}
}
std::cout << "\n";
auto sliced = MD<2,3,2>::slice(
v,
{}, // 1st dim: take all elements along this dim
{1,2}, // 2nd dim: take indices 1:2
{0} // 3rd dim: take only index 0
);
std::cout << "2x2x1 Slice with indices {{}, {1,2}, {0}} of the 2x3x2 data:\n";
for(size_t i=0; i < 2; ++i){ // index-based loop
for (size_t j=0; j < 2; ++j){
std::cout << sliced[i][j][0] << " ";
}
std::cout << "\n";
}
std::cout << "\n";
for(auto& val : flat(sliced)){
val *= val;
}
// print the whole flat data
std::cout << "\nThe whole data, after squaring all elements in sliced view:\n";
for (auto const& val : v){
std::cout << val << " ";
}
}
Output:
data interpreted as 2x3x2 array:
index 0:
1 2
3 4
5 6
index 1:
7 8
9 10
11 12
2x2x1 Slice with indices {{}, {1,2}, {0}} of the 2x3x2 data:
3 5
9 11
The whole data, after squaring all elements in sliced view:
1 2 9 4 25 6 7 8 81 10 121 12
Live Demo on godbolt compiler explorer
This is a prototype. I am sure the ergonomics can be improved.
Edit
A first quick and dirty benchmark of assigning a 6x6x6 view with another 6x6x6 view out of a 10x10x10:
Quickbench
A nested for loop over the multidimensional range is about 3 times slower than the traditional nested for-loop. Flattening the view using deep_flatten/std::views::join seems to make it 20-30 times slower. Apparently the compiler is having a hard time optimizing here.

access to iterator in lambda function of an algorithm cause me segmentation fault

I need to sort a table by column. My tables are represents by a single vector.
example :
col_name A B C
vector : 1 2 3 6 5 4 7 8 9
that give me the table :
A B C
1 6 7
2 5 8
3 4 9
After a sort on column B , I need to obtain :
A B C
3 4 9
2 5 8
1 6 7
my code :
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::vector<std::string> vec = {"1","8","1","2","3","2","3",
"5","5","2","5","6","5","6",
"9","3","3","4","8","3","9"};
std::vector<std::string> rec = {"1","1","8","2","2","3","3",
"2","5","5","5","5","6","6",
"3","9","3","4","3","8","9"};
int size = 7;
int col_idx = 1;
for(int i = 0; i<3;++i)
{
if(i==col_idx)
continue;
std::sort(vec.begin() + i*size, vec.begin() + (i+1)*size,
[col_idx, size, i](std::string& s1,std::string& s2)
{
std::cout << s1 << " "
<< s2 << " "
<< *(&s1 +(col_idx - i)*size) << " "
<< *(&s2 +(col_idx - i)*size) << " "
<< (*(&s1 +(col_idx - i)*size) < *(&s2 +(col_idx - i)*size)) << std::endl;
return *(&s1 +(col_idx - i)*size) < *(&s2 +(col_idx - i)*size);
});
}
std::sort(vec.begin() + col_idx*size, vec.begin() + (col_idx+1)*size);
}
assert(vec==res);
I have a segmentation fault error : only the first line appear from the cout.
Honestly, your approach looks rather complicated to me. Most of its complexity is due to the fact that you have rows in your code but they are present only implicitly. Making stuff explicit in code not only helps to increase readability but also makes code easier to write.
Lets say you use std::array<std::string,3> for rows, then your code could be as leightweight as this:
#include <vector>
#include <array>
#include <algorithm>
#include <iostream>
int main() {
using row_t = std::array<std::string,3>;
std::vector<row_t> vec = { {"1","8","1"},{"2","3","2"},{"3","5","5"},{"2","5","6"}};
std::sort(vec.begin(),vec.end(),[](const row_t& a, const row_t& b) { return a[2] < b[2]; });
for (const auto& row : vec) {
for (const auto& e : row) std::cout << e << " ";
std::cout << '\n';
}
}
Output:
1 8 1
2 3 2
3 5 5
2 5 6
Ok, that's probably a good approch for this problem, and maybe it's what should I do, but I can't pass 2 months to change all the code ...
You could have made the requirements more clear in the question. I think if you have 10k lines of code that depend on this particular issue using a flat vector, when a different data structure would be more appropriate, then you have a bigger problem than how to sort rows. Anyhow...
Using a flat std::vector is usually not a bad idea. What I miss from your code is something along the line of
template <int stride>
std::string& access_at(std::vector<std::string>& vec,size_t row,size_t col) {
return vec[ row * stride + col ];
}
template <int stride>
const std::string& access_at(const std::vector<std::string>& vec,size_t row,size_t col) {
return vec[ row * stride + col ];
}
That lets you iterate the table like this:
for (size_t i=0;i < vec.size()/3;++i) {
for (size_t j=0;j<3;++j) {
std::cout << access_at<3>(vec,i,j) << " ";
}
std::cout << '\n';
}
Next I am going to shamelessly steal and modify code from this answer. The basic idea is to sort a vector of indices instead of sorting the vector directly:
using index_t = std::vector<size_t>;
template <int stride>
index_t make_sorted_index(const std::vector<std::string>& values,size_t col) {
index_t index(values.size() / stride);
std::iota(index.begin(), index.end(), 0);
std::sort(index.begin(),
index.end(),
[&values,&col](size_t a, size_t b) {
return access_at<stride>(values,a,col) < access_at<stride>(values,b,col);
}
);
return index;
}
Once you have that, the loop to print the sorted table need only a minor modification:
for (size_t i=0;i < vec.size()/3;++i) {
for (size_t j=0;j<3;++j) {
std::cout << access_at<3>(vec,index[i],j) << " ";
}
std::cout << '\n';
}
Putting everything together:
#include <vector>
#include <numeric>
#include <algorithm>
#include <iostream>
template <int stride>
std::string& access_at(std::vector<std::string>& vec,size_t row,size_t col) { return vec[ row * stride + col ]; }
template <int stride>
const std::string& access_at(const std::vector<std::string>& vec,size_t row,size_t col) { return vec[ row * stride + col ]; }
using index_t = std::vector<size_t>;
template <int stride>
index_t make_sorted_index(const std::vector<std::string>& values,size_t col) {
index_t index(values.size() / stride);
std::iota(index.begin(), index.end(), 0);
std::sort(index.begin(),
index.end(),
[&values,&col](size_t a, size_t b) { return access_at<stride>(values,a,col) < access_at<stride>(values,b,col); }
);
return index;
}
int main() {
std::vector<std::string> vec = { "1","8","1","2","3","2","3","5","5","2","5","6"};
for (size_t i=0;i < vec.size()/3;++i) {
for (size_t j=0;j<3;++j) {
std::cout << access_at<3>(vec,i,j) << " ";
}
std::cout << '\n';
}
std::cout << '\n';
auto index = make_sorted_index<3>(vec,1);
for (size_t i=0;i < vec.size()/3;++i) {
for (size_t j=0;j<3;++j) {
std::cout << access_at<3>(vec,index[i],j) << " ";
}
std::cout << '\n';
}
}
With output:
1 8 1
2 3 2
3 5 5
2 5 6
2 3 2
3 5 5
2 5 6
1 8 1
I'll leave it to you to actually copy the vector to get the sorted one, if you really need that.
PS: In the first version above I sorted with respect to column C, the last part sorts with respect to B as requested.
PPS: I still dont understand your code. I don't understand why you have std::cout inside the predicate and to be honest I have no clue how your call to sort is supposed to achieve what you want.

How to find indexes from vector1 in vector2 in c++

i was envolving about a week with this issue, i have two vector for example vec1 and vec2, i want after search and find values from vec1 in vec2 return their indexes where only found for example:
vector<int>vec2 = { 1, 2, 2, 4 };
vector<int>vec1 = { 1, 2, 4 };
i want somthing like this pseudo code and this result:
pseudo code:
for i = 0 to vec2.size() do
return vec1 indexes in vec2;
end
result:
pass1:
1 0 0 0
pass2:
0 1 1 0
pass3:
0 0 0 1
final resault:
0 0 0 1
My code (it does not compile):
My code:
#include <vector>
#include <iostream>
using namespace std;
vector<int> find_index(vector<int>vec2, vector<int>vec1)
{
std::vector<double> tmp;
for (int i = 0; i<vec2.size(); i++)
{
for (int j = 0; j<vec2.size(); j++)
{
if (vec2[i] == vec1[j])
{
tmp.push_back(i);
}
}
}
return tmp;
}
int main()
{
vector<int>vec2 = { 1, 2, 2, 4 };
vector<int>vec1 = { 1, 2, 4 };
cout << find_index(vec2, vec1);
getchar();
return 0;
}
The code you have fails to compile for two reasons:
Using double item type for the tmp vector. A vector<double> does not convert implicitly to the required function result type vector<int>.
The standard library does not define output of vectors, so the cout << a vector in main doesn't compile.
To output the vector you can define function like this:
void write_to( ostream& stream, vector<int> const& v )
{
for( int i = 0; i < int( v.size() ); ++i )
{
stream << (i > 0? " " : "") << v[i];
}
}
and call it like this:
write_to( cout, find_index(vec2, vec1) );
cout << "\n";
It's also possible to write a little glue code that would enable the cout << notation, i.e. that would make it use the write_to function, but that is maybe just complication now.
With these changes your code compiles and outputs
0 1 2 3

Using binary counting to count all subsets of an array

So if I am given an array such as
a = {1, 2, 3}
We know that the given subarrays (non contiguous included) are (this represents the power set)
{1} {2} {3} {1,2,3} {1,2} {1,3} {2,3}
I also know that these subsets can be represented by counting in binary from
000 -> 111 (0 to 7), where each 1 bit means we 'use' this value from the array
e.g. 001 corresponds to the subset {3}
I know that this method can somehow be used to generate all subsets, but im not really sure how this can be implemented in c++
So basically what I am asking is how can (if it can) binary counting be used to generate power sets?
Any other methods for generating a power set are also much appreciated!
For your example with 3 set elements you can just do this:
for (s = 1; s <= 7; ++s)
{
// ...
}
Here's a demo program:
#include <iostream>
int main()
{
const int num_elems = 3; // number of set elements
const int elems[num_elems] = { 1, 2, 3 }; // mapping of set element positions to values
for (int s = 1; s < (1 << num_elems); ++s) // iterate through all non-null sets
{
// print the set
std::cout << "{";
for (int e = 0; e < num_elems; ++e) // for each set element
{
if (s & (1 << e)) // test for membership of set
{
std::cout << " " << elems[e];
}
}
std::cout << " }" << std::endl;
}
return 0;
}
Compile and test:
$ g++ -Wall sets.cpp && ./a.out
{ 1 }
{ 2 }
{ 1 2 }
{ 3 }
{ 1 3 }
{ 2 3 }
{ 1 2 3 }
Note that it's a common convention to make the least significant bit correspond to the first set element.
Note also that we are omitting the null set, s = 0, as you don't seem to want to include this.
If you need to work with sets larger than 64 elements (i.e. uint64_t) then you'll need a better approach - you can either expand the above method to use multiple integer elements, or use std::bitset or std::vector<bool>, or use something like #Yochai's answer (using std::next_permutation).
Actually creating the sets is pretty easy - just use bitwise operations >>= and & to test a bit at a time. Assuming input vector/array a[] known to have 3 elements and therefore produce a 7 vector output:
std::vector<std::vector<T>> v(7);
for (int n = 1; n <= 7; ++n) // each output set...
for (int i = 0, j = n; j; j >>= 1, ++i) // i moves through a[i],
// j helps extract bits in n
if (j & 1)
v[n-1].push_back(a[i]);
For compile time size, you may use bitset, something like:
template <std::size_t N>
bool increase(std::bitset<N>& bs)
{
for (std::size_t i = 0; i != bs.size(); ++i) {
if (bs.flip(i).test(i) == true) {
return true;
}
}
return false; // overflow
}
template <typename T, std::size_t N>
void display(const std::array<T, N>& a, const std::bitset<N>& bs)
{
std::cout << '{';
const char* sep = "";
for (std::size_t i = 0; i != bs.size(); ++i) {
if (bs.test(i)) {
std::cout << sep << a[i];
sep = ", ";
}
}
std::cout << '}' << std::endl;
}
template <typename T, std::size_t N>
void display_all_subsets(const std::array<T, N>& a)
{
std::bitset<N> bs;
do {
display(a, bs);
} while (increase(bs));
}
Live example

How to make double sort integer arrays using C++?

I have 3-column integer arrays, whose last 2 elements are for sorting. For example
10 0 1
11 0 2
12 1 2
13 0 1
I want them to become:
10 0 1
13 0 1
11 0 2
12 1 2
The arrays are first sorted according to the 2nd column, and then again according to 3rd column.
I have over 3000 rows, so I need something also fast. How can you do this in c++?
Note: The array will be allocated dynamically using the following templates:
template <typename T>
T **AllocateDynamic2DArray(int nRows, int nCols){
T **dynamicArray;
dynamicArray = new T*[nRows];
for( int i = 0 ; i < nRows ; i++ ){
dynamicArray[i] = new T[nCols];
for ( int j=0; j<nCols;j++){
dynamicArray[i][j]= 0;
}
}
return dynamicArray;
}
in main,
int ** lineFilter = AllocateDynamic2DArray(2*numberOfLines,3);
you can use std::sort(); however, this is complicated by your array being 2D.
In general, std::sort() can't eat 2D arrays; you have to create a class to cast around the compiler warnings and complaints:
#include <iostream>
#include <algorithm>
int data[4][3] = {
{10,0,1},
{11,0,2},
{12,1,2},
{13,0,1}
};
struct row_t { // our type alias for sorting; we know this is compatible with the rows in data
int data[3];
bool operator<(const row_t& rhs) const {
return (data[1]<rhs.data[1]) || ((data[1]==rhs.data[1]) && (data[2]<rhs.data[2]));
}
};
int main() {
std::sort((row_t*)data,(row_t*)(data+4));
for(int i=0; i<4; i++)
std::cout << i << '=' << data[i][0] << ',' << data[i][1] << ',' << data[i][2] << ';' << std::endl;
return 0;
}
It becomes much easier if you use a std::vector to hold your items that really are of type row_t or such. Vectors are dynamically sized and sortable.
I think this should work:
template<typename T>
struct compareRows {
bool operator() (T * const & a, T * const & b) {
if (a[1] == b[1])
return a[2] < b[2];
else
return a[1] < b[1];
}
};
std::sort(dynamicArray, dynamicArray+nrows, compareRows<int>());
Use a functor to implement the comparison between the rows. The sort will take pointers to the beginning of each row and swap them according to the contents of the rows. The rows will stay in the same places in memory.
OK, the OP has a three-column integer arrays, which is not straightforward to sort, because you can't assign arrays.
One option is to have arrays of structs, where the struct contains one element for each column, write a custom compare routine and use std::sort.
Another option is to pretend we have such an array of structs and employ the evilness of reinterpret_cast, like below:
#include <algorithm>
#include <iostream>
struct elt_t
{
int e0;
int e1;
int e2;
};
int
compare (const elt_t &a, const elt_t &b)
{
if (a.e1 == b.e1)
return a.e2 < b.e2;
else
return a.e1 < b.e1;
}
int a [10][3] =
{
{ 10, 0, 1 },
{ 11, 0, 2 },
{ 12, 1, 2 },
{ 13, 0, 1 }
};
int
main ()
{
std::sort (reinterpret_cast<elt_t *>(&a[0]),
reinterpret_cast<elt_t *>(&a[4]), compare);
int i, j;
for (i = 0; i < 4; ++i)
std::cout << a [i][0] << ", " << a [i][1] << ", " << a [i][2] << std::endl;
return 0;
}
Of course, whether or not this is standards compliant is highly debatable :)
EDIT:
With the added requirement for the matrix to by dynamically allocated, you can use an array of std::vector, or a vector of std::vector:
#include <algorithm>
#include <iostream>
#include <vector>
int
compare (const std::vector<int> &a, const std::vector<int> &b)
{
if (a[1] == b[1])
return a[2] < b[2];
else
return a[1] < b[1];
}
std::vector<int> *
make_vec (unsigned int r, unsigned int c)
{
std::vector<int> *v = new std::vector<int> [r];
/* Don't care for column count for the purposes of the example. */
v [0].push_back (10); v [0].push_back (0); v [0].push_back (1);
v [1].push_back (11); v [1].push_back (0); v [1].push_back (2);
v [2].push_back (12); v [2].push_back (1); v [2].push_back (2);
v [3].push_back (13); v [3].push_back (0); v [3].push_back (1);
return v;
}
int
main ()
{
std::vector<int> *v = make_vec (4, 3);
std::sort (&v[0], &v[4], compare);
int i, j;
for (i = 0; i < 4; ++i)
std::cout << v[i][0] << ", " << v [i][1] << ", " << v [i][2] << std::endl;
delete [] v;
return 0;
}
use this for the second column and then for the third. Now it works for single dim arrays
int *toplace(int *start, int *end)
{
int *i = start+1, *j= end-1;
while(i<=j)
{
while(*i<=*start && i<=j) {i++;}
while(*j>=*start && i<=j) {j--;}
if (i<j) std::swap(*i++,*j--);
}
std::swap(*start,*(i-1));
return i-1;
}
void quicksort(int *start, int *end)
{
if (start >= end) return;
int *temp = start;
temp = toplace(start,end);
quicksort(start,temp);
quicksort(temp+1,end);
}
You can do this using the bubble sort algorithm (http://en.wikipedia.org/wiki/Bubble_sort)
Basically iterate through all records, comparing the current record, with the next. If the current record's 2nd column is higher then swap these records. If the current record's 2nd column is equal but the 3rd column is higher, then swap also.
Continue iterating until no more swaps are made.
To use your example:
10 0 1
11 0 2
12 1 2 (swap with next)
13 0 1
10 0 1
11 0 2(swap with next)
13 0 1
12 1 2
10 0 1
13 0 1
11 0 2
12 1 2
And done!