I am trying to heapify a given vector passed by reference to a function. The function takes a reference to a vector as an argument and heapifies it. I'm also trying to calculate how many positions in the vector changed value as compared to the starting point. I'd like to update this difference variable inside the function.
For each position in the new and old vector: if the positions have a different value: diff++
Here's What I Have:
void heapify(std::vector<int> &v, int &diff)
{
int max = diff;
int l = 2 * diff + 1;
int r = 2 * diff + 2;
if (l < (int)v.size() && v[l] > v[diff])
diff = l;
if (r < (int)v.size() && v[r] > v[diff])
diff = r;
if (max != diff) {
swap(v[max], v[diff]);
heapify(v, diff);
}
}
int main()
{
vector<int> v = {20, 19, 100, 2};
int diff = 0;
heapify(v, diff);
cout << "Different in " << diff << " positions. Heap: ";
for(int i: v)
cout << i << ", ";
cout << endl;
return 0;
}
It is really close. A couple of glitches: for a one item vector, the contents shouldn't change. For a vector that's smallest to largest from 1 to 10, the difference is off by 2. For a really large random vector, the difference is off by 1.
Using std::make_heap
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v = {20, 19, 100, 2};
std::make_heap(v.begin(), v.end());
for(int i: v)
std::cout << i << ", ";
std::cout << std::endl;
return 0;
}
prints:
100, 19, 20, 2,
Related
struct Pair
{
int min;
int max;
};
struct Pair getMinMax(int arr[], int n)
{
struct Pair minmax;
int i;
// If array has even number of elements
// then initialize the first two elements
// as minimum and maximum
if (n % 2 == 0)
{
if (arr[0] > arr[1])
{
minmax.max = arr[0];
minmax.min = arr[1];
}
else
{
minmax.min = arr[0];
minmax.max = arr[1];
}
// Set the starting index for loop
i = 2;
}
// If array has odd number of elements
// then initialize the first element as
// minimum and maximum
else
{
minmax.min = arr[0];
minmax.max = arr[0];
// Set the starting index for loop
i = 1;
}
// In the while loop, pick elements in
// pair and compare the pair with max
// and min so far
while (i < n - 1)
{
if (arr[i] > arr[i + 1])
{
if(arr[i] > minmax.max)
minmax.max = arr[i];
if(arr[i + 1] < minmax.min)
minmax.min = arr[i + 1];
}
else
{
if (arr[i + 1] > minmax.max)
minmax.max = arr[i + 1];
if (arr[i] < minmax.min)
minmax.min = arr[i];
}
// Increment the index by 2 as
// two elements are processed in loop
i += 2;
}
return minmax;
}
// Driver code
int main()
{
int arr[] = { 1000, 11, 445,
1, 330, 3000 };
int arr_size = 6;
Pair minmax = getMinMax(arr, arr_size);
cout << "nMinimum element is "
<< minmax.min << endl;
cout << "nMaximum element is "
<< minmax.max;
return 0;
}
In this qsn we have to return max and min value simultaneously so here struct is made.
I copied this code from GEEKSFORGEEKS site. I was trying this code's approach but stuck in doubt that how here comparisons is being calculates.
In this code i want to know that how comparisons is 3*(n-1)/2 when n=odd?
The above code is the definition of premature optimization. Where you literally are taking the below code that takes 4 int compares per two elements, down to 3, and the cost of making the code hard to read, and easier to write bugs into.
Even in the code written below these could be changed to if() else if(), since they are populated with the same value to start with, both conditions are impossible to be true. But it's not worth making that change to make the reader have to think through if that is actually true.
Trying to be too smart, and you'll only outsmart yourself.
struct Pair
{
int min;
int max;
};
Pair getMinMax(int arr[], int length){
Pair output = {0, 0};
if(length < 1){
return output;
}
output.min = arr[0];
output.max = arr[0];
for(int i= 1; i < length; i++){
if(arr[i] < output.min){
output.min = arr[i];
}
if(arr[i] > output.max){
output.max = arr[i];
}
}
return output;
}
int main()
{
int array[] = { 8, 6, 4, 2, 9, 4};
auto data = getMinMax(array, 6);
std::cout << data.min << " " << data.max;
}
Solution using STL code (C++20) :
#include <algorithm>
#include <vector>
#include <iostream>
struct MinMaxResult
{
int min;
int max;
};
MinMaxResult getMinMax(const std::vector<int>& values)
{
return (values.size() == 0) ?
MinMaxResult{} :
MinMaxResult(std::ranges::min(values), std::ranges::max(values));
}
int main()
{
std::vector<int> values{ 8, 6, 4, 2, 9, 4 };
auto data = getMinMax(values);
std::cout << data.min << ", " << data.max;
return 0;
}
There are answers (good ones imho), but so far none does actually count the number of comparisons. With std::minmax_element you can count the number of comparisons like this:
#include <utility>
#include <vector>
#include <iostream>
#include <algorithm>
template <typename TAG>
struct compare {
static size_t count;
template <typename T>
bool operator()(const T& a,const T& b){
++count;
return a < b;
}
};
template <typename TAG> size_t compare<TAG>::count = 0;
template <typename TAG>
compare<TAG> make_tagged_compare(TAG) { return {};}
int main()
{
std::vector<int> x{1,2,3};
auto c = make_tagged_compare([](){});
auto mm = std::minmax_element(x.begin(),x.end(),c);
std::cout << *mm.first << " " << *mm.second << " " << c.count;
}
Standard algorithms may copy predicates passed to them, hence count is static. Because I want to reuse compare later to count a different algorithm, I tagged it (each lambda expression is of different type, hence it can be used as unique tag). The output is:
1 3 3
It correctly finds min and max, 1 and 3, and needs 3 comparisons to achieve that.
Now if you want to compare this to a different algorithm, it will look very similar to the above. You pass a functor that compares elements and counts the number of comparisons of the algorithm. As example I use a skeleton implementation that does only a single comparison and either returns {x[0],x[1]} or {x[1],x[0]}:
template <typename IT, typename Compare>
auto dummy_minmax(IT first, IT last,Compare c) {
auto second = first+1;
if (c(*first,*second)) return std::pair(*first,*second);
else return std::pair(*second,*first);
}
int main()
{
std::vector<int> x{1,2,3};
auto c = make_tagged_compare([](){});
auto mm = std::minmax_element(x.begin(),x.end(),c);
std::cout << *mm.first << " " << *mm.second << " " << c.count << "\n";
double x2[] = {1.0,2.0,5.0};
auto c2 = make_tagged_compare([](){});
auto mm2 = dummy_minmax(std::begin(x2),std::end(x2),c2);
std::cout << mm2.first << " " << mm2.second << " " << c2.count;
}
Complete example
I'm generating an array of random integers and trying to shift the values one to the right and replace the first element with the former last element.
The output is not ordered, and the final element is a randomly generated integer.
#include <iostream>
#include <cstdlib>
#include <iomanip>
using namespace std;
void shift(int values[], int size) {
int temp;
for (int i = 0; i < size; i++) {
temp = values[size - 1];
values[i] = values[i + 1];
values[0] = temp;
cout << values[i] << setw(4);
}
cout << endl;
}
int main()
{
cout << "Random 10 index array" << endl;
const int CAP = 10;
int numbers[CAP];
srand(time(0));
int i;
for (i = 0; i < CAP; i++) {
int rng = rand() % 100 + 1;
numbers[i] = rng;
cout << numbers[i] << setw(4);
}
cout << "shifting all elements to the right: " << endl;
shift(numbers, CAP);
cout << endl;
system("pause");
return 0;
}
I tried using i < size - 1, but I got 9 out of the 10 numbers I needed.
Have you tried
If you want a circular shift of the elements:
std::rotate(&arr[0], &arr1, &arr[10]); ... will do the trick. You'll
need to #include the algorithm header.
Optimal way to perform a shift operation on an array
Edit: As pointed out, std::rotate rotates left if used directly. Here is an example doing rotate right on a vector with some change:
#include <vector>
#include <iostream>
#include <algorithm>
int main()
{
std::vector<int> v{2, 4, 2, 0, 5, 10, 7, 3, 7, 1};
// simple rotation to the right
std::rotate(v.rbegin(), v.rbegin() + 1, v.rend());
std::cout << "simple rotate right : ";
for (int n: v)
std::cout << n << ' ';
std::cout << '\n';
}
Output:
simple rotate right : 1 2 4 2 0 5 10 7 3 7
Here's the offending code:
temp = values[size - 1];
This statement does not use the loop variable. Why is it sitting in the loop? This assignment will keep happening size-1 times.
values[i] = values[i + 1];
Your loop invariant is i <size, yet you try to access i+1. That's just asking for trouble :). This is why you don't get garbage values when you use i < size-1.
values[0] = temp;
Again, this doesn't use the loop variable. It doesn't belong in the loop. You just keep setting values[0]over and over again.
Here's a solution that works, using two temp variables:
void shift(int values[], int size) {
7 int temp = values[size-1], temp1;
8 for (int i = 0; i < size; i++) {
9 temp1 = values[i];
10 values[i] = temp;
11 temp = temp1;
12 cout << values[i] << setw(4);
13 }
14 cout << endl;
15 }
Another soution would be to copy the end of the array to the beginning of a temporary array and copy the beginning to the end of the temporary. Here is an exapmle with std::vector.
#include <algorithm>
#include <vector>
vector<int> shiftRight(vector<int> &A, int K)
{
if (A.size() <= 1) // No need to rotate if the array is smaller than 2 elements
return A;
K %= A.size(); // ensure K is less than size.
vector<int> S(A.size());
std::copy(A.cend() - K, A.cend() , S.begin());
std::copy(A.cbegin(), A.cend() - K, S.begin() + K);
return S;
}
It can be also implemented with memcpy which will be faster for big arrays.
#include <cstring>
void shiftRight(int *A, int size, int K)
{
if (size <= 1) // No need to rotate if the array is smaller than 2 elements
return;
K %= size; // ensure K is less than size.
int *temp = new int[size];
memcpy(temp, A + (size - K), K*sizeof(int));
memcpy(temp + K, A, (size - K)*sizeof(int));
memcpy(A, temp, size*sizeof(int)); // copy back to the original array
delete [] temp;
}
This question already has answers here:
c++ sort keeping track of indices [duplicate]
(4 answers)
Closed 8 years ago.
Variable x is a vector of n ints, and I want to sort the vector in ascending order. However, for reasons outside the scope of this question, I want to vector to remain untouched. Therefore, rather than actually sorting the contents of x, I want to create another vector of n indices, where each index refers to the respective value in x, if x were to have been sorted.
For example:
std::vector<int> x = {15, 3, 0, 20};
std::vector<int> y;
// Put the sorted indices of x into the vector y
for (int i = 0; i < 4; i++)
{
std::cout << y[i];
}
Should give the output:
2
1
0
3
Corresponding to values in x:
0
3
15
20
I can think of plenty of timely ways of implementing this, but I'm wondering whether the STL has something build-in to perform this efficiently for me?
1) Create y as a vector of index (an integer range)
2) Sort this range with a comparator that returns the indexes elements from x
Using the Standard Library, that gives :
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> x = {15, 3, 0, 20};
std::vector<int> y;
std::vector<int> y(x.size());
std::size_t n(0);
std::generate(std::begin(y), std::end(y), [&]{ return n++; });
std::sort( std::begin(y),
std::end(y),
[&](int i1, int i2) { return x[i1] < x[i2]; } );
for (auto v : y)
std::cout << v << ' ';
return 0;
}
Live demo.
Fill y with all the indices of x then use std::sort on y but provide a comparator that compares the corresponding elements in x:
std::vector<int> y(x.size());
std::iota(y.begin(), y.end(), 0);
auto comparator = [&x](int a, int b){ return x[a] < x[b]; };
std::sort(y.begin(), y.end(), comparator);
You can provide your own Comparator that checks the target vector's values while sorting a vector of indexes rather like this:
#include <vector>
#include <iostream>
#include <algorithm>
struct IdxCompare
{
const std::vector<int>& target;
IdxCompare(const std::vector<int>& target): target(target) {}
bool operator()(int a, int b) const { return target[a] < target[b]; }
};
int main()
{
std::vector<int> x = {15, 3, 0, 20};
std::vector<int> y;
// initialize indexes
for(size_t i = 0; i < x.size(); ++i)
y.push_back(i);
std::sort(y.begin(), y.end(), IdxCompare(x));
std::cout << "\nvector x: " << '\n';
for(size_t i = 0; i < x.size(); ++i)
std::cout << x[i] << '\n';
std::cout << "\nvector y: " << '\n';
for(size_t i = 0; i < x.size(); ++i)
std::cout << y[i] << '\n';
std::cout << "\nvector x through y: " << '\n';
for(size_t i = 0; i < x.size(); ++i)
std::cout << x[y[i]] << '\n';
}
OUTPUT:
vector x:
15
3
0
20
vector y:
2
1
0
3
vector x through y:
0
3
15
20
We can take a "refers" approach directly and use an array of pointers to values in the source vector.
#include <iostream>
#include <vector>
#include <algorithm>
int main(int argc, const char * argv[]) {
//a source vector, who's order shouldn't be changed
std::vector<int> values = {15, 4, 20, 25, 0, 19, -5};
//a vector of pointers to the values in the source vector
std::vector<int *> pointersToValues;
pointersToValues.reserve(values.size());
for(auto& value : values){
pointersToValues.push_back(&value);
}
//two comparators in form of lambda functions
auto descendingOrderSorter = [](int * i, int * j){
return *i > *j;
};
auto ascendingOrderSorter = [](int * i, int * j){
return *i < *j;
};
//examples of usage
std::cout<<"Sorting in a descending order"<<std::endl;
std::sort( pointersToValues.begin(), pointersToValues.end(), descendingOrderSorter);
for(int i = 0; i < pointersToValues.size(); ++i) {
std::cout << "index: " << i << ", value: " << *pointersToValues[i] << std::endl;
}
std::cout<<"Sorting in an ascending order"<<std::endl;
std::sort( pointersToValues.begin(), pointersToValues.end(), ascendingOrderSorter);
for(int i = 0; i < pointersToValues.size(); ++i) {
std::cout << "index: " << i << ", value: " << *pointersToValues[i] << std::endl;
}
return 0;
}
pointersToValues[i] would give you a pointer to the original value, *pointersToValues[i] would give you the value.
You can do a sort into another list then a comparison with the unsorted list then a 3rd list where you can store the indices i.e nlog(n) + n^2 or just O(n^2)
Note: this is Pseudo code
vector<int> x = {15, 3, 0, 20};
vector<int> y = sort(x);
vector<in> z;
for(int i = 0; y < y.size(); i++){
for(int j = 0; j < y.size(); j++){
if(y[i] == x[j]){
z.push_back(j);
}
}
}
I've tried to implement an algorithm that would search for both minimum and maximum elements in a given array, and used the ideas from Cormen's Introduction to Algorithms. My code compiles and starts working, outputs the generated random array and then does nothing for a really long time.
Why could that be?
The code is this:
// fast min and max --cormen exercise 1.cpp: entry point
//implemented from a verbal description in cormen's book, p 243
#include "stdafx.h"
#include <vector>
#include <ctime>
#include <cstdlib>
#include <iostream>
struct min_and_max
{
int min, max;
};
min_and_max find_min_and_max(std::vector<int>& A)
{
int n = A.size();
int min, max;
if (n%2 == 1)
min = max = A[0];
if (n%2 == 0)
if (A[0] < A[1])
{
min = A[0];
max = A[1];
}
else
{
min = A[1];
max = A[0];
}
for(int i = 2; i < A.size(); (i + 2))
{
if (A[i] < A[i+1])
{
if (min > A[i])
min = A[i];
if (max < A[i+1])
max = A[i+1];
}
else
{
if (min > A[i+1])
min = A[i+1];
if (max < A[i])
max = A[i];
}
}
min_and_max result;
result.min = min;
result.max = max;
return result;
}
int main()
{
std::srand(std::time(0));
std::vector<int> A(10);
for (auto i = 0; i < A.size(); i++)
{
A[i] = rand() % 1000;
std::cout << A[i] << " ";
}
std::cout << std::endl; //IT GOES AS FAR AS THIS
std::cout << "The array has been analyzed; its' minimum is " << find_min_and_max(A).min << "and its' maximum is " << find_min_and_max(A).max << std::endl;
return 0;
}
for(int i = 2; i < A.size(); (i + 2))
i + 2 won't change the value of i, you need to use i += 2.
The problem lies here:
for(int i = 2; i < A.size(); (i + 2))
You never actually increment i, thus causing an infinite loop.
change it to:
for(int i = 2; i < A.size(); i+=2)
Additional to the given answers, if you're using c++11 you can simplify your algorithm using lambdas and the std::for_each function:
#include <algorithm>
#include <iostream>
#include <cmath>
int main() {
int array[] = { -8, 8, 0, 9, 5, -3, 4, 6, -1, 15, 31 };
int min, max;
// User std::for_each(v.begin(), v.end(), ...) for either vector or list
std::for_each(std::begin(array), std::end(array), [&min, &max](int elem) {
max = std::max(max, elem);
min = std::min(min, elem);
});
std::cout << min << ", " << max << std::endl;
return 0;
}
And maybe it could be even simpler
Update: As #Blastfurnace pointed out, the std::minmax_element function could be used to further reduce the code needed for searching both the min and max element, yielding this shorter version:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> values = { -8, 8, 0, 9, 5, -3, 4, 6, -1, 15, 31 };
auto minAndMax = std::minmax_element(values.begin(), values.end());
std::cout << *minAndMax.first << ", " << *minAndMax.second << std::endl;
return 0;
}
Is important to note that everything done in this answer, besides being OT, is for the sake of learning, to give the OP alternatives to improve his (or her) work and help other users that could have the same requirement.
In any case the algorithm is incorrect because the vector can have the size equal to 0. In this case 1) you try to access alements that are not exist and 2) you return undefined values from the function. The more correct approach is to return indexes of the minimum and maximum elements and in the case if the vector is empty return a pair of A.size().
i would like to check an array for a specific range of values.
ie, the range of values is from 0 --> 9 and the actual array is 50 elements large.
i also want to keep track of how many of each value there is.
ie, if there are 3 zeroes, 8 ones and 5 two's, then my final vector should look like, 3 8 5.
i was able to solve it with the code below BUT, i realized that my range values needs to be equal to my array size, otherwise it does not check all elements.
is there a better way to do this?
int main() {
int intensityRange = 10;
int cloudSize = 10;
int cloud [] = {0, 3, 3, 2, 1, 5, 2, 3, 5, 2};
vector <int> totalGreyValues;
int k = 0;
for (int i = 0; i < intensityRange; i++) {
for (int j = 0; j < cloudSize; j++) {
if (cloud[j] == i) {
k = k + 1;
cout << " " << k;
}
else
cout << " no match ";
}
totalGreyValues.push_back (k);
k = 0;
}
cout << endl << endl << totalGreyValues.size();
for (int h = 0; h < totalGreyValues.size(); h ++)
cout << " " << totalGreyValues[h];
// values --> 0 1 2 3 4 5 6 7 8 9
// answer --> 1 1 3 3 0 2 0 0 0 0
return 0;
}
It's much easier to use std::map:
int size = 50;
int data[size] = { 1, 2, 3, 4, 5, ... };
std::map<int, int> mymap;
for(int i = 0; i < size; i++)
{
if(data[i] >= min && data[i] <= max)
mymap[data[i]] = mymap[data[i]] + 1;
}
This saves some space, because you don't save unused values and the loop count is also much smaller, because you only process once per value.
If your range is continuous I would prefer a boost::vector_property_map.
#include <boost/property_map/vector_property_map.hpp>
#include <iostream>
int main()
{
boost::vector_property_map<unsigned int> m(10); // size of expected range
std::vector<int> cloud = {0, 3, 3, 2, 1, 5, 2, 3, 5, 2};
for(auto x : cloud) { m[x]++; }
for(auto it = m.storage_begin(); it != m.storage_end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
If your range does not start at 0 you can use IndexMap template
argument to remap the indices. This will also work if you map a non
continous set of values that you want to count into a continous
range. You might need to perform a check if you only want to count
specific values, but given the expensiveness of the count operation,
I'd rather count them all instead of checking what to count.
Use a std::map and the std::accumulate function:
#include <map>
#include <algorithm>
typedef std::map<int, int> Histogram;
Histogram& addIfInRange(Histogram& histogram, const int value)
{
if(inRange(value))
{
++histogram[value];
}
// else don't add it
return histogram;
}
Histogram histogram =
std::accumulate(data, data + size, Histogram(), addIfInRange);
If you have large enough empty regions, you can try a multiset, together with some of C++' new facilities:
#include <set>
#include <iostream>
int main () {
int vals[] = { 0, 1, 2, 3, 4, 5, 5, 5, 6 };
std::multiset <int> hist;
for (auto const &v : vals)
if (v >= 3 && v <= 5) hist.insert (v);
for (auto const &v : hist)
std::cout << v << " -> " << hist.count (v) << '\n';
}
If your data is densely populated, a std::vector might give superiour results:
#include <algorithm>
#include <iostream>
int main () {
using std::begin; using std::end;
int vals[] = { 1, 2, 4, 5, 5, 5, 6 };
const auto val_mm = std::minmax_element (begin(vals), end(vals));
const int val_min = *val_mm.first,
val_max = *val_mm.second + 1;
std::vector<int> hist (val_max - val_min);
for (auto v : vals)
++hist [v - val_min];
for (auto v : vals)
std::cout << v << " -> " << hist[v-val_min] << '\n';
}