How can I use C++ copy for reverse elements? - c++

I want to reverse the elements in vector, so I use reverse function and copy function. reverse function act well but copy function got wrong result.
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include "show.h"
int main()
{
std::vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };
std::list<int> s = { 1,2,3,4,5,6,7,8,9,10 };
std::copy(v.rbegin(), v.rend(), v.begin());
show(v); // expected result: 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
// result: 10, 9, 8, 7, 6, 6, 7, 8, 9, 10
return 0;
}
what's the problem with my code?

what's the problem with my code?
Because it's reading and writing from the same vector. It's reading from one side, and writing from the other side.
When the two sides meet in the middle, the reading side continues to read what was already written from the other side. Hilarity ensues.
Your expected results would be as if the original, pristine contents of the vector get read from start to finish. But you seem to be forgetting that, as the vector gets read, the other end of the vector starts to get immediately overwritten by the writing side of the copy.
That's the problem with your code.

Related

MultiIndex containers -- offering vector and set access

I have an application where, first, an std::vector<int> object is generated. Then, some operations need to be performed on this object viewed as an std::set<int> where the order does not matter and repetitions don't count.
At present, I explicitly construct an object of type std::set<int> from the std::vector<int> object. An example is presented below:
#include <cstdio>
#include <set>
#include <vector>
void printset(std::set<int>& Set) {
printf("Printing Set Elements: ");
for (std::set<int>::iterator siter = Set.begin(); siter != Set.end(); ++siter) {
int val = *siter;
printf("%d ", val);
}
printf("\n");
}
void printvec(std::vector<int>& Vec) {
printf("Printing Vec Elements: ");
for (size_t i = 0, szi = Vec.size(); i < szi; ++i) {
int val = Vec[i];
printf("%d ", val);
}
printf("\n");
}
int main()
{
std::vector<int> VecInt{ 6, 6, 5, 5, 4, 4 };
std::set<int> SetInt(VecInt.begin(), VecInt.end());
printvec(VecInt);
printset(SetInt);
}
I am trying to see if I can use Boost.MultiIndex for this purpose. One introduction to Boost.MultiIndex states:
Boost.MultiIndex can be used if elements need to be accessed in different ways and would normally need to be stored in multiple containers. Instead of having to store elements in both a vector and a set and then synchronizing the containers continuously, you can define a container with Boost.MultiIndex that provides a vector interface and a set interface.
and this is precisely what I am doing (using multiple containers and then creating one from the other constantly) while I would like to create a (multi-index) container once and then provide a vector interface and a set interface.
On looking through various examples, for e.g., here and here, it is not clear how those examples can be modified to the code example above.
Ideally, I would like to do the following in the code example above:
MultiIndexContainer vec_set_container;
vec_set_container.push_back(6);//or anything equivalent for the MultiIndexContainer
vec_set_container.push_back(6);
vec_set_container.push_back(5);
vec_set_container.push_back(5);
vec_set_container.push_back(4);
vec_set_container.push_back(4);
printvec(vec_set_container.Some_Function_That_Exposes_Vector_Interface());
printset(vec_set_container.Some_Function_That_Exposes_Set_Interface());
How can this be accomplished using Boost.MultiIndex ?
Random access index would match the "vector" interface.
An ordered unique index would match the "set" interface.
However, if you have a unique index, this will prevent insertion of duplicates. So, you would get:
Live On Compiler Explorer
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index_container.hpp>
#include <fmt/ranges.h>
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container< //
int,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct asVector>>,
bmi::ordered_unique<bmi::tag<struct asSet>, bmi::identity<int>>>>;
int main()
{
Table data{ 6, 6, 5, 5, 4, 4 };
fmt::print("As vec {}\nAs set {}\n", //
data.get<asVector>(), //
data.get<asSet>());
}
Printing
As vec {6, 5, 4}
As set {4, 5, 6}
Now, I think the "best" you could do with this is to make the order index non-unique (so, mimicking a std::multiset instead of std::set): Live On Compiler Explorer
bmi::ordered_non_unique<bmi::tag<struct asSet>, bmi::identity<int>>
Printing
As vec [6, 6, 5, 5, 4, 4]
As set {4, 4, 5, 5, 6, 6}
If you want to traverse unique elements, using a range adaptor would be minimally costly:
Using Boost Live
fmt::print("As vec {}\nAs set {}\n", //
data.get<asVector>(), //
data.get<asSet>() | boost::adaptors::uniqued);
Using RangeV3 Live
fmt::print("As vec {}\nAs set {}\n", //
data.get<asVector>(), //
data.get<asSet>() | ranges::views::unique);
Using Standard Ranges; I couldn't make this work but it should really be something like std::ranges::unique(data.get<asSet>())
All printing
As vec {6, 6, 5, 5, 4, 4}
As set {4, 5, 6}
Other Ideas
If you don't require random access, then sequenced index might be preferrable for you. And note that this interface comes with the handy unique() and sort() methods (just like std::list).
UPDATE To The Comments
Here's a rolled-in-one response to the comments:
Live On Compiler Explorer
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>
#include <fmt/ranges.h>
#include <random>
namespace bmi = boost::multi_index;
template <typename T>
using ListSet = bmi::multi_index_container< //
T,
bmi::indexed_by<
bmi::sequenced<bmi::tag<struct byInsertion>>, //
bmi::ordered_unique<bmi::tag<struct Ordered>, bmi::identity<T>> //
>>;
int main()
{
ListSet<int> data;
std::mt19937 prng{99}; // "random" seed
for (std::uniform_int_distribution d(1, 10); data.size() < 5;) {
int el = d(prng);
if (auto [it, unique] = data.push_back(el); not unique) {
fmt::print("Element {} duplicates index #{}\n", el,
std::distance(begin(data), it));
}
}
fmt::print("By insertion {}\nOrdered {}\n", data, data.get<Ordered>());
}
Prints
Element 9 duplicates index #3
Element 8 duplicates index #1
By insertion [7, 8, 5, 9, 1]
Ordered {1, 5, 7, 8, 9}

I don't understand how to use set_difference correctly

In the task it was said that it is necessary to get the "value" of the largest elements from the array. Then it should be compared with the second array, and duplicates should be excluded.
In the task it is necessary to use partial_sort_copy in vector, and set_difference.
The problem is that when you start the program crashes at all, even without showing what exactly the error is, that's why I am writing here
I looked at several sites with examples of using this function, but I used everything as there, and do not quite understand why it does not work and crashes.
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
int main()
{
int value = 5;
int A_ints[] { 1, 4, 12, 5, 1, 4, 6, 9, 0, 3 };
vector<int> A_vec(value);
vector<int> B_vec { 13, 12, 11, 10 };
vector<int> C_vec;
vector<int> D_vec {9, 6, 5, 4};
partial_sort_copy(A_ints, A_ints + 9, A_vec.begin(), A_vec.end(), greater<int>());
set_difference(A_vec.begin(), A_vec.end(), B_vec.begin(), B_vec.end(), C_vec.begin(), greater<int>());
if (С_vec == D_vec)
cout << "Success \n";
else
cout << "Failure \n";
system("pause");
return 0;
}
As a result, if set_difference will works correctly, then the last condition should return "Success".
The 5th argument to set_difference is the parameter that the results of the algorithm will be written to.
You've passed in C_vec.begin() which is an iterator pointing to an empty vector. It's undefined behavior to write to an empty vector's iterator.
You have several issues here, but one solution for this particular problem would be to replace C_vec.begin() with an insert_iterator:
inserter(C_vec, begin(C_vec))

How to order a list of numbers without changing the list [duplicate]

This question already has answers here:
Sorting a vector of custom objects
(14 answers)
Closed 4 years ago.
I am in need of ordering a list of numbers stored in a C++ vector:
#include <vector>
#include <iostream>
#include <algorithm>
struct A
{
};
bool compare(A i1, A i2)
{
if(i1.vec.size() > i2.vec.size())
return true;;
}
int main()
{
std::vector<A> ax;
ax.emplace_back(A{ 100, 300, 6, 123, 12, 451, 552});
ax.emplace_back(A{ 100, 300, 6, 123, 12, 451});
std::sort(ax.begin(), ax.end(), compare);
return 0;
}
As per the above code the ordering of ax vector should be:
{ 100, 300, 6, 123, 12, 451}
{ 100, 300, 6, 123, 12, 451, 552}
I am unable to get what needs to be added in compare function to achieve it?
your comparison is not based on the content of the vector but on their size
furthermore you pass Oid by value rather than by const reference in compare, this is expensive for nothing because they are copied each time

Finding vectors in C++

I have two vectors of vector<unsigned> namely: vector<vector<unsigned> > sbp, vector<vector<unsigned> > sp. I want to print all those vectors in sbp which are also in sp. Both vectors sbp and sp are stored (i) first by size; (ii) and when the size are equal, then the vectors are sorted lexicographically. I wrote the following code for doing the same. The code appears to be giving segmentation fault. I debugged the code (by printing out values), but I am not able to find the source of the error.
Can someone please help me find what could be the source of segmentation fault. Also if there is some algorithm which is faster than this, then that will be really great
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
vector<vector<unsigned> > sbp;
vector<vector<unsigned> > sp;
vector<vector<unsigned> >::iterator itSP=sp.begin();
for(vector<vector<unsigned> >::iterator itSbp=sbp.begin(),lSbp=sbp.end();itSbp!=lSbp;)
{
if(std::lexicographical_compare(((*itSbp)).begin(), ((*itSbp)).end(), (*itSP).begin(), (*itSP).end()))
{
itSbp++;
}else{
if((*itSbp)==(*itSP))
{
// cout<<(*itSbp)<<"\n";
itSbp++;
}else{
itSP++;
}
}
}
}
I am using C++11(gcc 4.8)
I want to print all those vectors in sbp which are also in sp.
Whenever there is a situation where you want to collate the common values that are in two containers, the algorithm that should spring to mind right away is std::set_intersection.
The caveat is that std::set_intersection requires that the containers contain sorted values (or a functor provided that describes the sort order). However, if you can meet that criteria, then the solution is trivial.
Here is an example:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
// test data
vector<vector<unsigned> > sbp = { { 1, 2, 3, 4, 6, 7 }, { 1, 2, 3, 6, 7 }, { 2, 3, 4, 6, 7 }};
vector<vector<unsigned> > sp = { { 1, 2, 3, 4, 6, 7 }, { 1, 2, 3, 4, 6, 7, 8 }, { 2, 3, 4, 6, 7 }};
// resulting vector
vector<vector<unsigned> > result;
// get the intersection of the two values
set_intersection(sbp.begin(), sbp.end(), sp.begin(), sp.end(), back_inserter(result));
// output the results
for_each(result.begin(), result.end(), [](const std::vector<unsigned>& v)
{copy(v.begin(), v.end(), ostream_iterator<unsigned>(cout, " ")); cout << "\n";});
}
Live Example
If the number of items are large, and there is a good possibility that the data contains duplicates, then a std::set can be used to store the data.
// resulting vector
std::set<vector<unsigned>> result;
// get the intersection of the two values
set_intersection(sbp.begin(), sbp.end(), sp.begin(), sp.end(), std::inserter(result, result.begin()));

C++ Easiest most efficient way to move a single element to a new position within a vector

Sorry for my potential nOOb'ness but have been trying to get this for hours and cant seem to find an elegant solution for c++ 98.
My question is, say i have a vector of strings { a,b,c,d,e,f } and i want to move 'e' to the 2nd element how would i do so? Obviously the expected output would now print out { a,e,b,c,d,f }
Ideally looking for a single operation that lets me do this just for efficiency reasons but would love to hear some suggestions on how to achieve this.
Thanks.
It's not possible to do this "efficiently" with std::vector<>, because it is stored in contiguous memory and you must therefore move everything between the old and new locations by one element. So it's linear time in the length of the vector (or at least the distance moved).
The naive solution would be to insert() then erase(), but that requires moving everything after the rightmost location you modified, twice! So instead you can do it "by hand", by copying b through d one position to the right (e.g. with std::copy(), then overwriting b. At least then you avoid shifting anything outside the modified range. It looks like you may be able to make std::rotate() do this, as #WhozCraig mentioned in a comment.
I'd try with std::rotate first and only try other manual stuff (or a container other than vector) if that turns out not be efficient enough:
#include <vector>
#include <iostream>
#include <algorithm>
int main()
{
// move 5 from 4th to 1st index
std::vector<int> v {1,2,3,4,5,6};
// position: 0 1 2 3 4 5
std::size_t i_old = 4;
std::size_t i_new = 1;
auto it = v.begin();
std::rotate( it + i_new, it + i_old, it + i_old + 1);
for (int i : v) std::cout << i << ' ';
}
Live demo.
EDIT As noted in the comments, the below code actually mimics std::rotate, which is of course preferred above my hand-rolled code in all cases.
You can accomplish this with K swaps where K is the distance between the elements:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string v = "abcdef"; // use string here so output is trivial
string::size_type insert_index = 1; // at the location of 'b'
string::size_type move_index = 4; // at the location of 'e'
while(move_index > insert_index)
{
std::swap(v[move_index], v[move_index-1]);
--move_index;
}
std::cout << v;
}
Live demo here. Note I used std::string, but the algorithm remains the same for std::vector. The same can be done with iterators, so you can generalize to containers that don't have operator[].
Expanding on jrok's answer, here's a wrapper around std::rotate() for moving a single element around. This is more general than jrok's example, in that it supports moving an element forward in the vector too (rather than only backward).
See the comments within rotate_single() explaining how you have to swap the logic around when moving the element forward versus back.
#include <vector>
#include <stdexcept> // for std::domain_error in range-checking assertion
#include <algorithm> // for std::rotate()
template<class ContiguousContainer>
void assert_valid_idx(ContiguousContainer & v, size_t index)
{
// You probably have a preferred assertion mechanism in your code base...
// This is just a sample.
if(index >= v.size())
{
throw std::domain_error("Invalid index");
}
}
template<class ContiguousContainer>
void rotate_single(ContiguousContainer & v, size_t from_index, size_t to_index)
{
assert_valid_idx(v, from_index);
assert_valid_idx(v, to_index);
const auto from_it = v.begin() + from_index;
const auto to_it = v.begin() + to_index;
if(from_index < to_index)
{
// We're rotating the element toward the back, so we want the new
// front of our range to be the element just after the "from" iterator
// (thereby making our "from" iterator the new end of the range).
std::rotate(from_it, from_it + 1, to_it + 1);
}
else if(to_index < from_index)
{
// We're rotating the element toward the front,
// so we want the new front of the range to be the "from" iterator.
std::rotate(to_it, from_it, from_it + 1);
}
// else the indices were equal, no rotate necessary
}
You can play with this in Compiler Explorer—there are (extensive) unit tests there, but here's an illustrative sample:
TEST_CASE("Handful of elements in the vector")
{
std::vector<int> v{1, 2, 3, 4, 5, 6}; // Note: this gets recreated for each SECTION() below
// position: 0 1 2 3 4 5
SECTION("Interior moves")
{
SECTION("Move 5 from 4th to 1st index")
{
rotate_single(v, 4, 1);
CHECK(v == std::vector<int>{1, 5, 2, 3, 4, 6});
}
SECTION("Move 2 from 1st to 4th index")
{
rotate_single(v, 1, 4);
CHECK(v == std::vector<int>{1, 3, 4, 5, 2, 6});
}
}
SECTION("Swap adjacent")
{
rotate_single(v, 4, 5);
rotate_single(v, 0, 1);
CHECK(v == std::vector<int>{2, 1, 3, 4, 6, 5});
}
}