Here I have simple code, it works for std::vector, but don't work for std::list.
Is it wrong because elements in list doesn't alighned?
Edit:
Ok, what is the best way to put list in func? Convert it to vector?
for example I need it when put data in PolyPolyLine
#include <iostream>
#include <vector>
#include <list>
using namespace std;
vector<int> func(int* buf)
{
vector<int> t;
t.push_back(buf[0]);
t.push_back(buf[1]);
return t;
}
int main() {
list<int> ls;
vector<int> v;
ls.push_back(2);
ls.push_back(111111);
v.push_back(12);
v.push_back(11);
vector<int> t1= func(&v[0]);
vector<int> t2= func(&ls.front());
cout<<t1[0]<<t1[1];
cout<<t2[0]<<t2[1];
return 0;
}
The std::list<T> is a linked list, so its memory is not contiguous. You cannot use regular pointers with it to do pointer arithmetic - it's undefined behavior.
If you change your program to take iterators instead, and use std::next to access elements beyond the current one, your program would produce the behavior that you expect.
template <typename T>
vector<int> func(T buf)
{
vector<int> t;
t.push_back(*next(buf, 0));
t.push_back(*next(buf, 1));
return t;
}
...
vector<int> t1= func(v.begin());
vector<int> t2= func(ls.begin());
Demo.
You can't take the address of an item in a list and use it as an array. std::list is a doubly linked list with dynamically allocated nodes. Unlike a vector, the elements in the list are not contiguous.
The only container that guarantees continuous memory allocation is std::vector (and std::array). You don't have any sort of guarantee like that with a std::list, which is why this approach can't possibly work.
Related
I need a data structure like std::vector or std::list whose elements will be unique. In most of time I will call push_back on it, sometimes maybe erase. When I insert an element which is already there, I need to be notified either by some boolean or exception.
And the most important property it should have: the order of insertions. Each time I iterate over it, it should return elements in the order they were inserted.
We can think other way: a queue which guarantees the uniqueness of elements. But I don't want to pop elements, instead I want to iterate over them just like we do for vector or list.
What is the best data structure for my needs?
You can use a std::set
It will return a pair pair<iterator,bool> when the insert method is called. The bool in the pair is false when the element already exists in the set (the element won't be added in that case).
Use a struct with a regular std::vector and a std::set.
When you push, check the set for existence of the element. When you need to iterate, iterate over the vector. If you need to erase from the vector, also erase from the set.
Basically, use the set as an aside, only for fast "presence of an element" check.
// either make your class a template or use a fixed type of element
class unique_vector
{
public:
// implement the various operator you need like operator[]
// alternatively, consider inheriting from std::vector
private:
std::set<T> m_set; // fast lookup for existence of elements
std::vector<T> m_vector; // vector of elements
};
I would prefer using std::unordered_set to stores existing elements in a std::vector and it has faster lookup time of O(1), while the lookup time of std::set is O(logn).
You can use Boost.MultiIndex for this:
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
using namespace boost::multi_index;
template<typename T>
using unique_list=multi_index_container<
T,
indexed_by<
sequenced<>,
hashed_unique<identity<T>>
>
>;
#include <iostream>
int main()
{
unique_list<int> l;
auto print=[&](){
const char* comma="";
for(const auto& x:l){
std::cout<<comma<<x;
comma=",";
}
std::cout<<"\n";
};
l.push_back(0);
l.push_back(1);
l.push_back(2);
l.push_back(0);
l.push_back(2);
l.push_back(4);
print();
}
Output
0,1,2,4
I am trying to understand how the std::transform function works, but I'm having a bit of trouble with the following code. I want to take a multiset ms, add 1 to the contents of each element and store them in a new multiset msc. Here is what I have:
int op_increase(int i) { return ++i; }
int main()
{
std::multiset<int> ms = {1,1,2,2,3};
std::multiset<int> msc;
std::transform(ms.begin(), ms.end(), msc.begin(), op_increase);
return 0;
}
However I get the following error:
C3892: _Dest: you cannot assign to a variable that is const
Your code was not utilizing the correct argument to std::transform that allows insertion into an empty container. This requires using an iterator that is intelligent enough to call the appropriate function that calls the container's insert() function.
The solution is to provide std::transform the std::inserter iterator that automatically inserts into the empty multiset. Here is an example:
#include <set>
#include <algorithm>
#include <iterator>
int op_increase(int i) { return ++i; }
int main()
{
std::multiset<int> ms = {1,1,2,2,3};
std::multiset<int> msc;
std::transform(ms.begin(), ms.end(), std::inserter(msc, msc.begin()), op_increase);
// msc now contains 2,2,3,3,4
}
Note the std::inserter is used, and not merely msc.begin(). The inserter will automatically insert the items into the map.
Live Example
The problem here is that std::multiset<T>::begin() returns a std::_Tree_const_iterator type. That's why you cannot change its value. This behavior is sensible: the std::multiset, like std::set, is a sorted container typicaly implemented as a red-black tree, and thus change of a value of one element may require update of the whole data structure. If user really wants to do this, he may erase a node and add it back.
To better understand the std::transform behavior, you may use std::vector container instead of std::multiset. Cplusplus.com contains a good example of code using std::transform.
Also, as far as I understand from your code, you try to add the resulting data into the initially empty std::multiset. To achieve this functionality, you may use std::insert_iterator (Cplusplus.com), like this:
int op_increase(int i) { return ++i; }
int main()
{
std::multiset<int> ms = {1,1,2,2,3};
std::multiset<int> msc;
std::transform(ms.begin(), ms.end(), inserter(msc, msc.begin()), op_increase);
return 0;
}
I'm directly posting my code which I've written on collabedit under 5 minutes (including figuring out the algorithm) thus even though with the risk of completely made of fun in terms of efficiency I wanted to ask my fellow experienced stack overflow algorithm enthusiasts about the problem;
Basically removing duplicate elements from an array. My Approach: Basically using the std::map as my hash table and for each element in duplicated array if the value has not been assigned add it to our new array. If assigned just skip. At the end return the unique array. Here is my code and the only thing I'm asking in terms of an interview question can my solution be more efficient?
#include <iostream>
#include <vector>
#include <map>
using namespace std;
vector<int>uniqueArr(int arr[],int size){
std::map<int,int>storedValues;
vector<int>uniqueArr;
for(int i=0;i<size;i++){
if(storedValues[arr[i]]==0){
uniqueArr.push_back(arr[i]);
storedValues[arr[i]]=1;
}
}
return uniqueArr;
}
int main()
{
const int size=10;
int arr[size]={1,2,2,4,2,5,6,5,7,1};
vector<int>uniArr=uniqueArr(arr,size);
cout<<"Result: ";
for(int i=0;i<uniArr.size();i++) cout<<uniArr[i]<<" ";
cout<<endl;
return 0;
}
First of all, there is no need for a map, a set is conceptually more correct, since you don't want to store any values, but only the keys.
Performance-wise, it might be a better idea to use a std::unordered_set instead of a std::set, as the former is hashed and can give you O(1) insert and lookup in best case, whereas the latter is a binary search tree, giving you only O(log n) access.
vector<int> uniqueArr(int arr[], int size)
{
std::unordered_set<int> storedValues;
vector<int> uniqueArr;
for(int i=0; i<size; ++i){
if(storedValues.insert(arr[i]).second)
uniqueArr.push_back(arr[i]);
return uniqueArr;
}
But if you are allowed to use the C++ standard library more extensively, you may also consider the other answers using std::sort and std::unique, although they are O(n log n) (instead of the above ~O(n) solution) and destroy the order of the elements.
If you want to use a more flexible and std-driven approach but with ~O(n) complexity and without destroying the order of the elements, you can transform the above routine into the following std-like algorithm, even if being a bit too far-fetched for a simple interview question:
template<typename ForwardIterator>
ForwardIterator unordered_unique(ForwardIterator first, ForwardIterator last)
{
typedef typename std::iterator_traits<ForwardIterator>::value_type value_type;
std::unordered_set<value_type> unique;
return std::remove_if(first, last,
[&unique](const value_type &arg) mutable -> bool
{ return !unique.insert(arg).second; });
}
Which you can then apply like std::unique in the usual erase-remove way:
std::vector<int> values(...);
values.erase(unordered_unique(values.begin(), values.end()), values.end());
To remove the unique values without copying the vector and without needing to sort it beforehand.
Since you are asking in terms of an interview question, I will say that you don't get the job.
const int size=10;
int arr[size]={1,2,2,4,2,5,6,5,7,1};
std::sort( &arr[0], &arr[size] );
int* new_end = std::unique( &arr[0], &arr[size] );
std::copy(
&arr[0], new_end,
, std::ostream_iterator< int >( std::cout, " " )
);
No temporary maps, no temporary vectors, no dynamic memory allocations, a lot less code written so its easier both to write and to mantain.
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> vec({1,2,3,2,4,4,5,7,6,6});
std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
// vec = {1,2,3,4,5,6,7}
return 0;
}
//works with C++11
// O(n log n)
In-place removal's nice for speed - something like this (returning the new size):
template <typename T, size_t N>
size_t keep_unique(T (&array)[N])
{
std::unordered_set<T> found;
for (size_t i = 0, j = 0; i < N; ++i)
if (found.insert(array[i]).second))
if (j != i) // (optional) avoid copy to self, as may be slower or unsupported by T
array[j++] = array[i];
else
++j;
return j;
}
(For larger objects, or those that can't be safely copied, may be necessary and/or faster and more space efficient to store T*s in the unordered_set - must also provide a dereferencing comparison operator and hash function.)
To visualise how this works, consider processing the following input:
1 3 6 3 5 6 0 2 1
<--+<----+ |
<-----+
The arrows above represent the minimal in-place compaction necessary to produce the answer:
1 3 6 5 0 2
That's precisely what the algorithm above does, looking at all the elements at [i], and keeping track of where they need to be copied to (and how many non-duplicates there are) in [j].
I am stuck on trying to figure out how to insert a vector for a value in a map. For example:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{
map <int, vector<int> > mymap;
mymap.insert(pair<int, vector<int> > (10, #put something here#));
return 0;
}
I don't know what syntax to use insert a vector for value. I tried {1,2}, but that failed. What syntax should I use?
Everything works if I declare a vector in advance and give it a name, but I don't want to do that, as I want to have a map with a lot of vectors.
Thank You in Advance
If you want an empty vector you could do:
mymap.insert(pair<int,vector<int> >(10, vector<int>()));
You could then add whatever elements you want with something like:
mymap[10].push_back(1);
mymap[10].push_back(2);
Edit: Removed incorrect assertion that the vectors would be copied if/when the map grows. As the commenters pointed out, this is not true for std::map, which is node-based.
Basically your question is not about inserting std::vector into a std::map. Your question is how can you easily create an anonymous std::vector with arbitrary initial element values.
In ISO C++03, you can't. C++11 allows using initialization lists for this, however.
If you are stuck with a C++03 compiler, you possibly could create a helper function to return a vector with specified elements:
std::vector<int> make_vector(int a, int b)
{
std::vector<int> v;
v.push_back(a);
v.push_back(b);
return v;
}
If the vectors you're inserting are of different sizes, you could use a variadic function, although doing so would require that you either pass along the number of elements or have a reserved sentinel value.
If you are using C++11 you can use vector's initialization list constructor (the last constructor in that list) which would look like this:
mymap.insert(pair<int, vector<int> > (10, {1, 2, 3}));
If you can only use C++03, vector has a constructor that takes a size and a default value for each element that might be enough for you. Otherwise you will have to construct the vector and then insert it. If you want to avoid an unnessicary copy of the vector when inserting you could swap it in like so:
vector<int> myvec;
myvec.push_back(1);
myvec.push_back(2);
mymap[10].swap(myvec);
This way the vector won't need to be copied. You'll get an extra vector default construction but that's not very expensive.
#put something here# = vector<int>{1,2}
I'm surprised though that {1,2} didn't work. Are you not using a C++11 compiler? If not then you can only create the vector with default constructor there (no values), or fill it with values first and stick it in.
This should work in C++2003 compilers.
#include <iostream>
#include <vector>
#include <map>
#include <cassert>
using namespace std;
std::vector<int> make_vector(int a, int b) {
std::vector<int> result;
result.push_back(a);
result.push_back(b);
return result;
}
int main()
{
map <int, vector<int> > mymap;
mymap.insert(make_pair(10, make_vector(1,2)));
// Or, alternatively:
// mymap[10] = make_vector(1,2);
assert(mymap[10][0] == 1);
assert(mymap[10][1] == 2);
return 0;
}
C++03 does not have initializer lists, which can be a pain to initialize collections.
If you cannot upgrade to a more modern version of the compiler, you can always use the Boost.Assignment library. It has a list_of function precisely for this.
#put something here# -> boost::assign::list_of(1)(2)
Why it says 'push_back' has not been declared ?
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <int> v(30);
v[0].push_back(0);
return 0;
}
v[0] is a reference to the initial element in the vector; it isn't the vector itself. The element is of type int, which is not a class type object and therefore has no member functions.
Are you looking for v.push_back(0);?
Note that vector<int> v(30); creates the vector with 30 elements in it, each with a value of zero. Calling v.push_back(0); will increase the size of the vector to 31. This may or may not be the behavior your want; if it isn't, you'll need to clarify what, exactly, you are trying to do.
You need to do v.push_back(0) as push_back is the method of the vector not its element.
Try this:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <int> v(30);
v.push_back(0);
return 0;
}
The problem is that v[0] is the first element in vector, which is an int. The name of the vector is v.
Just use v.push_back(0); You have to push_back into a vector. Not into a specific element of a vector.
You have the wrong type.
v is of type Vector. v[0] is NOT a vector, rather, it is a reference to the first element (which will be an int).
As a result, v[0] does not have a push_back method.
Only the vector itself (v) has the method.
use v.push_back(0) as v[0] is an int and not a vector.