This question already has answers here:
Sorting zipped (locked) containers in C++ using boost or the STL
(5 answers)
Closed 7 years ago.
I'm coding in C++ (with c++11 standards) and I have two big arrays of built-in type that I want to sort the second one based on the first.
here is an example:
A = {1, 5, 4, 3, 6, 2};
B = {1, 2, 3, 4, 5, 6};
after sorting:
A = {1, 2, 3, 4, 5, 6};
B = {1, 6, 4, 3, 2, 5};
It's as if each element B[i] is attached to element A[i] and you just sort array A. So elements in B move according the corresponding element in A. I know this questions has been asked over and over, yet the only solution I've come across with is to use pair<type 1, type 2>. But considering the arrays are big, it takes quite a while to allocate the memory for pairs array and copy arrays back and forth.
But I believe the sorting can be done in-place, i.e., using only O(1) memory. In fact if std::sort allowed for costume swap it would have been fine. Because I assume that's the only thing beyond comparator that sorting algorithms use.
A = vector<double>(1e6); // some random numbers
B = vector<double>(1e6); // some random numbers
Comp comp(&A,&B);
Swap swap(&A,&B);
costume_sort(A,B,comp,swap); // some sort function that can take costume swap and compare
class Comp {
vector<double> *A;
vector<double> *B;
Comp(vector<double> *A, vector<double> *B) : A(A),B(B) {};
bool compareTo(size_t i, size_t j) { return A->at(i) < A->at(j); };
};
class Swap {
vector<double> *A;
vector<double> *B;
Swap(vector<double> *A, vector<double> *B) : A(A),B(B) {};
void swapFnc(size_t i, size_t j) { swap(A->at(i), A->at(j));swap(B->at(i), B->at(j)); };
};
Is there any function in STL or other libraries available that can do that? This is a sort of pseudo-code of the idea I'm trying to explain here. Obviously it's not precise but I hope it's clear what I mean.
You can sort based on indices similar to the related post: std::sort and custom swap function.
It is not a custom swap function and allocateds some more memory, but should perform well.
If you are defining the types, then you can overload std::swap to do what you want: How to overload std::swap().
No there is not an std:: function that meets your requirements.
Although it's possible to provide its custom comparison (so Q&A) and swap (so Q&A) functor, those take a (constant) reference to the items to compare or swap, not an index on an hypothetical container. Indeed those functors should have meaning for comparisons and swaps of non-contained objects.
Example of reorder a[] and b[] in place according to a sorted array of pointers to a[]. Since an array of pointers is used, the compare function only needs to know the type of elements being compared. The reorder in place code time complexity is O(n), every store places a value in its sorted location. Note that the array of pointers is restored to it's original state (&a[0] ... &a[n-1]) during the reorder.
bool compare(const int *p0, const int *p1)
{
return *p0 < *p1;
}
int main()
{
int a[8] = {7,5,0,6,4,2,3,1};
char b[8] = {'h','f','a','g','e','c','d','b'};
int *pa[8];
size_t i, j, k;
int ta;
char tb;
// create array of pointers to a[]
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
pa[i] = &a[i];
// sort array of pointers to a[]
std::sort(pa, pa+sizeof(a)/sizeof(a[0]), compare);
// reorder a[] and b[] according to the array of pointers to a[]
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++){
if(i != pa[i]-a){
ta = a[i];
tb = b[i];
k = i;
while(i != (j = pa[k]-a)){
a[k] = a[j];
b[k] = b[j];
pa[k] = &a[k];
k = j;
}
a[k] = ta;
b[k] = tb;
pa[k] = &a[k];
}
}
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
std::cout << a[i] << ' ';
std::cout << std::endl;
for(i = 0; i < sizeof(b)/sizeof(b[0]); i++)
std::cout << b[i] << ' ';
std::cout << std::endl;
return 0;
}
Related
My task is to count the no of elements greater than an element aij in the corresponding row i and column j for every element of a 2D array in C++. My way is to extract the ith row and jth column, sort them and traverse the sorted array with a counter variable until aij element is found.
But the problem is in extracting the entire row i and entire column j for every such element. I know that the row can easily be extracted with std::copy function in c++.
int **adj=new int *[n];
for(r=0;r<m;r++)
for(c=0;c<n;c++)
cin>>adj[r][c];
int buf[n];
std::copy(adj[i], adj[i] + n, buf);
But how to extract the corresponding jth column?
I can easily do it with a looping structure like:
int buf[m];
for(r=0;r<m;r++)
buf[r]=adj[r][j];
but this will increase time complexity keeping in mind that this operation is required for every element of the array. Any better way to do this?
If you decide to write program in C++, then
Stop using plain C-Style arrays. There is No reason whatsoever for C-Style arrays. Do never use them again. Simply stop this.
Stop using raw pointers. For now and ever. Do not use raw pointers
Do not use new. Never
The language C++, which you want to use, does not support VLA (avariable length arrays), Do not use C-Style arrays in the first place and not at all VLA (like int buf[m];
Especially, do not use such constructs, if you do not understand how thew work
In you first row, you are writing
int **adj=new int *[n];
With that you are allocating an array of pointer. Those pointers are not initialized. They point to somewhere random in the memory.
And with
for(r=0;r<m;r++)
for(c=0;c<n;c++)
cin>>adj[r][c];
You are getting user input and write them into random memory, somehwere, undifined, corrupting the heap and causing a crash.
With
int buf[n];
std::copy(adj[i], adj[i] + n, buf);
you copy some random values into buf. It will look like it works. But it is only by accident.
In the future please use std::vector or std array (if you know the dimension at compile time). For 2 dimensional arrays use a vector of vectors.
See the following example:
int main()
{
const size_t numberOfRows = 3;
const size_t numberOfColumns = 4;
std::vector<std::vector<int>> a2d(numberOfRows, std::vector<int>(numberOfColumns));
// Fill a2d with data
for (size_t row = 0; row < a2d.size(); ++row) {
for (size_t col = 0; col < a2d.front().size(); ++col) {
std::cin >> a2d[row][col];
}
}
// Get 2nd row
std::vector<int> row(numberOfColumns);
std::copy(a2d[1].begin(), a2d[1].end(), row.begin());
return 0;
}
But the problem is in extracting the entire row i and entire column j for every such element.
The algorithm you are trying to implement doesn't need to copy and sort the row and the column every time. You can copy and sort each row and each column once, then reuse those for every element. While time consuming, it should be asintotically faster than traversing the rows and columns multiple times to count the greater values.
See e.g. the following implementation (testable HERE).
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
int main()
{
std::vector<std::vector<int>> a {
{3, 5, 1, 2},
{8, 0, -2, 7},
{1, -5, 3, 6},
};
// Make a transposed copy. That's really cache unfriendly
auto a_t = std::vector<std::vector<int>>(a[0].size(), std::vector<int>(a.size()));
for (size_t r = 0; r < a.size(); ++r)
{
for (size_t c = 0; c < a[r].size(); ++c)
{
a_t[c][r] = a[r][c];
}
}
// Sort the rows of a_t (columns of a)
for (auto & row : a_t)
{
std::sort(row.begin(), row.end());
}
auto c = std::vector<std::vector<int>>(a.size(), std::vector<int>(a[0].size()));
for (size_t i = 0; i < c.size(); ++i)
{
// Sort a (copied) row at a time.
auto row_copy(a[i]);
std::sort(row_copy.begin(), row_copy.end());
// The columns have already been copied and sorted,
// now it just takes a couple of binary searches.
for (size_t j = 0; j < c[i].size(); ++j)
{
auto it_r = std::upper_bound(row_copy.cbegin(), row_copy.cend(), a[i][j]);
auto it_c = std::upper_bound(a_t[j].cbegin(), a_t[j].cend(), a[i][j]);
c[i][j] = std::distance(it_r, row_copy.cend())
+ std::distance(it_c, a_t[j].cend());
}
}
for (auto const & row : c)
{
for (auto i : row)
std::cout << std::setw(3) << i;
std::cout << '\n';
}
}
I have this function:
void reverse(int* nums, unsigned int size)
This function is supposed to reverse the values in the array it is getting.
Now for reversing I thought to create another array with the size of the array passed in. Assigning this new one from the end of the original array to the start.
But I am a kind of new in C++, So I don't know how to create dynamic array in the size of the parameter of the function.
It's actually not necessary to allocate a new array here. See if you can find a way to solve this problem just by rearranging the existing elements in-place.
Given that this seems like it's an exercise with pointers, you can allocate space by using the new[] operator:
int* auxiliaryArray = new int[size];
You'd then free it by writing
delete[] auxiliaryArray;
However, this isn't the preferred way of doing this in C++. The better route is to use std::vector, which does all its own memory management. That would look like this:
std::vector<int> auxSpace(size);
You can then access elements using the square brackets as you could in a real array. To do this, you'll need to #include <vector> at the top of your program.
In C++, the recommended way to create an array of variable size would be to use an std::vector
#include <vector>
void reverse(int* nums, unsigned int size)
{
std::vector<int> V(size);
...
}
But that approach isn't the best here for performance because it requires additional memory to be allocated of the size of the array, which could be big. It would be better to start from the outside of the array and swap members one by one that are at mirroring positions (so if the size is 5, swap 0 and 4, then swap 1 and 3 and leave 2 alone). This only requires temporary storage of a single int.
You can do it without the need to create another array:
void reverse(int* array, const int size){
for(int i = 0; i < size / 2; i++){
int tmp = array[i];
array[i] = array[size - 1 - i];
array[size - 1 - i] = tmp;
}
}
int main(){
int array[] = {1, 3, 5, 7, 9, 11};
const int size = sizeof(array) / sizeof(array[0]);
reverse(array, size);
for(int i(0); i < size; i++)
std::cout << array[i] << ", ";
}
As you can see above in the loop you only need to swap the first element (element 0) with the n-1 element and the second one with n-1-1 and son on...
Remember arrays are indexed from 0 through n-1.
If you want to allocate new array which is not practical:
int* reverse2(int* array, const int size){
int* tmp = new int[size];
for(int i(size - 1), j(0); j < size; j++, i--)
tmp[j] = array[i];
return tmp;
}
int main(){
int array[] = {1, 3, 5, 7, 9, 11};
for(int i(0); i < size; i++)
std::cout << array[i] << ", ";
std::cout << std::endl;
int* newArray = reverse2(array, size);
for(int i(0) ; i < size; i++)
std::cout << newArray[i] << ", ";
std::cout << std::endl;
delete[] newArray;
return 0;
}
If you want to use a new array you can, but I think is to kill flies with a cannon.
Looks like you are using plain C code and not C++. I say that because of the signature of the function. The signature of the function in a common C++ code could be something like this other:
void reverse(std::vector& items);
You can reverse the current array without a new array, using the current one. You are passing the pointer to the first item of the array, and the content is not constant so that you can modify it. A better signature for the function could be:
void reverse(int* const nums, const unsigned int size);
Looks like a pointer problem. Think about the boundaries to iterate the positions of the array. Would you need to iterate the whole array? Maybe only half array? ;)
As bonus track, what about to exchange the values without an auxiliar variable? (this is true into this case that we are using the fundamental type int... remember the binary arithmetic).
array[pos_head] ^= array[pos_tail];
array[pos_tail] ^= array[pos_head];
array[pos_head] ^= array[pos_tail];
Suppose I want to do something for every number in a multi-dimensional array. I've found that you can get a pointer for the first number and then use use pointer addition. For example, the following code prints the numbers 1 through 12:
double a[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
double *p = &a[0][0][0];
for (int i = 0; i < 12; i++)
cout << *(p + i) << endl;
Is it unidiomatic to consider a multi-dimensional array as being flat in this way? If so, what is the preferred way of doing it? Also, is there a simpler way to write double *p = &a[0][0][0]; to get a pointer for the first number in a multi-dimensional array (in the same way that you can just write double *p = a; for a one-dimensional array)?
Yes, a multidimensional array is guaranteed to be flat. However, it may be best to kind this sort of thing. If you want to flatwise iterate over a multidimensional array, I think it'd be better to introduce a range view into it:
template <typename T>
struct Flat {
auto begin() { return first(arr); }
auto end() {
return begin() + sizeof(arr)/sizeof(*begin());
}
template <typename X> X* first(X& val) { return &val; }
template <typename X, size_t N> auto first(X(&val)[N]) { return first(*val); }
T& arr;
};
template <typename T>
Flat<T> flatten(T& arr) {
return Flat<T>{arr};
}
And simply use that one:
for (double d : flatten(a)) {
std::cout << d << std::endl;
}
Otherwise, the only other way of declaring p is something like double *p = &***a; I'm not sure if becoming a three star programmer is high on your life achievement list.
While it can be very useful to know that a multidimensional array is actually flat, it would usually be unidiomatic to refer to it using pointers and pointer arithmetic, because it introduces more potential for error and is harder to read than the idiomatic solution, subscript notation. Because of that, I would recommend using this:
double a[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 2; k++)
{
cout << a[i][j][k] << endl;
}
}
}
Yes, a multi-dimensional array can always be treated as flat. Also, same as a one dimensional array you can say double *p = reinterpret_cast<double*>(a) which is the same as double *p = &a[0][0][0].
A multi-dimensional array, if dynamically allocated, may not be flat. But then that would be obvious as the allocation will be done by you.
I would like to sort an array by increasing order of frequency. For example, if I had an array
int arr[] = { 3, 3, 10, 2, 5, 10, 10, 2, 2, 2 };
or another array would have the following sequence in it:
int arr[] = {5, 3, 3, 10, 10, 10, 2, 2, 2, 2};
However, I cannot use hashing or maps – I can only use arrays. What I have thought of is sorting the array using a quick sort algorithm, scanning the sorted array and performing the count in a 2d array so that for each element, there is a count associated with it, and then sorting by count. If two counts are same then I would merely print out the one with the lower value first. I'm having trouble implementing the last two steps. I'm not sure how to "map" a count to an index in the 2d array, nor am I sure on how to sort the 2d array by a count. Could anyone help me out? Thanks!
Scan your array (sort first to optimize, but not needed), and generate an array of the struct below. Now sort the array of these structs, then regenerate your original array.
struct ElemCount {
int Elem;
int count;
bool operator<(const ElemCount& other) {
if (count!=other.count)
return count<other.count;
return Elem<other.Elem;
}
};
That's how I'd code it without STL (requires additional O(n) memory):
// Represents a bunch of equal numbers in an array
struct Bunch
{
int x; // value of numbers
int n; // count of numbers
};
int cmp_int(const void *x, const void *y)
{
return *static_cast<const int*>(x) - *static_cast<const int*>(y);
}
int cmp_bunch(const void *x, const void *y)
{
const Bunch* bx = static_cast<const Bunch*>(x);
const Bunch* by = static_cast<const Bunch*>(y);
return (bx->n != by->n) ? bx->n - by->n : bx->x - by->x;
}
void sort_by_freq(int arr[], int arr_size)
{
// Buffer array to store counted bunches of numbers
Bunch* buf = new Bunch [arr_size];
int buf_size = 0;
// Sort input array
qsort(arr, arr_size, sizeof(int), cmp_int);
// Compute bunches
Bunch bunch;
bunch.x = arr[0];
bunch.n = 1;
for (int i = 1; i < arr_size; ++i)
{
if (arr[i] > bunch.x)
{
buf[buf_size++] = bunch;
bunch.x = arr[i];
bunch.n = 1;
}
else
{
++bunch.n;
}
}
buf[buf_size++] = bunch; // Don't forget the last one!
// Sort bunches
qsort(buf, buf_size, sizeof(Bunch), cmp_bunch);
// Populate bunches to the input array
int i = 0;
for (int k = 0; k < buf_size; ++k)
for (int j = 0; j < buf[k].n; ++j) arr[i++] = buf[k].x;
// Don't forget to deallocate buffer, since we cannot rely on std::vector...
delete [] buf;
}
how to delete all elements of a std::tr1::array?
For example I have defined the following array.
std::tr1::array <int, 5> a = { 1, 2, 3, 4, 5}
Just like in vectors I am looking for a method such as a.clear() or a.erase() but couldn't find one for arrays.
Thank you
arrays are static size, you can neither add nor remove elements, that's what vector is for.
Once defined, the size of an array cannot be modified.
Arrays have a fixed size. You can, however, keep track of the number of elements you use in the array, for a fixed-maximum-sized-vector:
array<int,5> arr;
int number_of_elements = 0;
for ( int i = 0; i < 4; ++i ) {
// arr.push_back(i)
arr[number_of_elements] = i;
number_of_elements++;
}
// arr.erase( arr.begin() + 2 )
for ( int i = 2; i < number_of_elements-1; ++i )
arr[i] = arr[i+1];
number_of_elements--;
// arr.clear()
number_of_elements = 0;
you can delete specific index information if want!
for(int i=0;i<n;i++) //for deletion
{
if(arr[i]==_delete)
{
arr[i]=arr[i+1];
--n;
}
}