iterate over vector of unrodered set - c++

I'm still learning c++ and do not understand one thing that I encountered today.
I see that an adjacency_list_ if defined by
std::vector<std::unordered_set<int> > bla::blaa::adjacency_list_
I believe that it is an vector of unordered set.
I want to know:
What is this data-structure, vector of unordered set?
How can I traverse it to get the adjacency list, please provide a general MWE for traversal of such data-structures?
Thanks in advance for teaching me this new thing.
A minimum (not) working example:
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
int main()
{
vector<unordered_set<int> > my_sets;
for (int i=0; i<5; i++){
my_sets[i].insert(i*2);
}
for(int i=0;i<my_sets.size();i++)
{
for(unordered_set<int> :: iterator it = my_sets[i].begin(); it != my_sets[i].end();++it)
{
cout << *it;
}
}
return 0;
}

You have a problem in your code, your vector is empty, yet you're trying to access indices from 0 to 4. you should set the size of the vector first before iterating. Also you can use range based for loop to avoid writing alot of boilerplate code.
This code is correct and I think it does what you want:
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
int main()
{
vector<unordered_set<int>> my_sets(5);
// ^^^
// number 5 here initializes the vector with the size of 5
for (int i = 0; i < 5; i++)
my_sets[i].insert(i*2);
for (auto &my_set : my_sets)
for (auto num : my_set)
cout << num;
return 0;
}
output:
02468

An adjacency list
is a collection of unordered lists. Each list describes the set of neighbors.
Translating into C++:
std::vector<std::unordered_set<int> > adjlist;
The collection (vector) of a set of neighbours (unordered_set).
Traversing depends on what you want to achieve.
If it is just visiting each node, this can be as simple as
for (int node = 0; node < adjlist.size(); ++node) {
// do something with node
}
or
for (auto &neighbours : adjlist) {
// do something with each node's neighbours
}
If you want to navigate from one node to another node, you must look at the neighbours of a node
std::vector<std::unordered_set<int> > adjlist = {{2, 5}, {2, 3}, {0, 1}, {1, 4}, {3}, {0}};
for (int i = 0; i < adjlist.size(); ++i) {
auto &neighbours = adjlist[i];
for (auto n : neighbours) {
std::cout << i << "->" << n << '\n';
}
}
Since each neighbour points back to each other, this poses the problem of loops and keeping track of already visited nodes.

Related

how to access set elements by index like vector?

I have made a code that construct a set of sets. However, I want to access set index like vector *(vec.begin()+i) .Is it possible like accessing vector? I got an error,Please help me, Is there any solution
#include <iostream>
#include <set>
using namespace std;
int main ()
{
int myints[] = {75,23,65,42,13};
std::set<int> myset (myints,myints+5);
std::cout << "myset contains:";
for (int i = 0; i < myset.size(); i++) {
cout<<*(myset.begin()+i);
}
std::cout << '\n';
return 0;
}
You can with std::next. But it's not a good idea for std::set because it must linearly increment the iterator.
auto third = std::next(myset.begin(), 2);

Get number of same values in arrays in C++

I need a function int countDifferentNumbers(int v[], int n) which counts how many different values the array v with n entries contains.
Example:
It should return the result 3 for the array v = {1, 5, 5, 8, 1, 1} because the array contains only 3 different values.
This is how the code looks like so far:
int countDifferentNumbers(int v[], int n)
{
int counter = 0;
for(int i = 0; i < n; ++i)
{
for(int j = i; j < n; ++j)
{
if(v[i] == v[j + 1])
{
cout << "match" << endl;
counter++;
cout << v[i] << endl;
}
}
}
return counter;
}
I would appreciate an explanation of what is wrong in my function and how I need to redesign it.
Note: Unfortunately, I have not found a suitable thread for this either. All threads with my problems were solved in Java and Python languages.
Recently I see more and more answers here on SO that lead users in the wrong direction by giving bad answers.
Also, for C++, the question has already been answered in the comment by Igor Tandetnik, and that should finally be used.
But let me answer the question of the OP as asked. What is wrong with my function? OK, there are several aspects. Let us first look at the style.
You have 0 lines of comments, so the code quality is 0. If you would write comments, then you would already find most bugs by yourself, because then, you need to explain your own wrong statements.
Then please see your source code with my amendments. I added the problems as comment.
// This is just a dumped function and not a minimum reproducible example
// All header files are messing
// Obviously "using namespace std;" was used that should NEVER be done
// The function should retrun an unsigned value, best size_t, because a count can never be negative
// Same for n, that is the size of an array. Can also never be negative
// C-sytle arrays should NEVER be used in C++. NEVER. Use std::vector or std::array instead
int countDifferentNumbers(int v[], int n)
{
int counter = 0; // Now in C++ we can use braced initialzation instead of assignement
for (int i = 0; i < n; ++i)
{
for (int j = i; j < n; ++j)
{
if (v[i] == v[j + 1]) // Accessing out of bounds element
{
cout << "match" << endl; // Now endl needed here. Can all be done in one cout statement in one line
counter++; // Always counting up the same counter for all kind of double numbers.
cout << v[i] << endl;
}
}
}
return counter;
That was one point of the answer. But now the second point. Evene more important. The algorithm or the design is wrong. And finding the correct solution, this thinking before codingt, you need to do, before you write any line of code.
You obviously want to find the count of unique numbers in an array.
Then you could look what is already there on Stackoverflow. You would probaly find 20 answers already that coud give you a hint.
You could use std::unique. Please see here for a description. This function sounds like it does what you want, right? Some example implementation:
#include <iostream>
#include <unordered_map>
#include <vector>
#include <algorithm>
// If you want to keep the original data, remove the reference-specifier &
size_t countDifferentNumbers(std::vector<int>& v) {
std::sort(v.begin(), v.end()); // Sorting is precondition for std::unique
v.erase(std::unique(v.begin(), v.end()), v.end()); // Erase all non-unique elements
return v.size(); // Return the result
}
int main() {
std::vector test{ 1, 5, 5, 8, 1, 1 }; // Some test data
std::cout << countDifferentNumbers(test) << '\n'; // SHow result to user
return 0;
}
Then, we could count the occurence of each number in a std::map or std::unordered_map. And the number of counters will be the result. Example:
#include <iostream>
#include <unordered_map>
#include <vector>
#include <algorithm>
// If you want to keep the original data, remove the reference-specifier &
size_t countDifferentNumbers(std::vector<int>& v) {
std::unordered_map<int, size_t> counter{}; // Here we will count all occurences of different numbers
for (const int i : v) counter[i]++; // Iterate over vector and count different numbers
return counter.size(); // Count of different numbers
}
int main() {
std::vector test{ 1, 5, 5, 8, 1, 1 }; // Some test data
std::cout << countDifferentNumbers(test) << '\n'; // Show result to user
return 0;
}
But, then, thinking further, about what conatiners we could use, we will find out the answer from Igor Tandetnik. There are 2 containers that can hold unique values only. No double values. And these are: std::set and std::unordered_set., So, we can simply copy the data into one of those containers, and, only unique values will be stored there.
There are many ways to get the data into a set. But the simplest one is to use its range constructor. Then, we have unique elements, and, the containers size function will give the result:
See here: Constructor Number 2.
The result will be a function with one line like this
#include <iostream>
#include <unordered_set>
#include <vector>
// If you want to keep the original data, remove the reference-specifier &
size_t countDifferentNumbers(std::vector<int>& v) {
return std::unordered_set<int>(v.begin(), v.end()).size();
}
int main() {
std::vector test{ 1, 5, 5, 8, 1, 1 }; // Some test data
std::cout << countDifferentNumbers(test) << '\n'; // Show result to user
return 0;
}
And since functions with one line are often not so usefull, we can also write the final solution:
#include <iostream>
#include <unordered_set>
#include <vector>
int main() {
std::vector test{ 1, 5, 5, 8, 1, 1 }; // Some test data
std::cout << std::unordered_set<int>(test.begin(), test.end()).size() << '\n'; // Show result to user
return 0;
}
So, by analyzing the problem and choosing the right algorithm and container and using C++, we come to the most easy solution.
Please enable C++17 for your compiler.
first sort the array v. if n >0 then initially there must be one number which is unique so just increment the value of counter once. then with loop check if the two consecutive number are same or not. if same do nothing else increment the value of counter.
if you are writing code in c then use qsort. #include <stdlib.h> add this in header and. use qsort() func
here is the code:
#include <bits/stdc++.h>
using namespace std;
int countDifferentNumbers(int v[] , int n)
{
int counter = 0;
sort(v, v+ n); // if you are writing code in c then just write a decent sort algorithm.
if (n>0 ){
printf("%d\n", v[0]);
counter ++;
}
for(int i = 0; i < n-1; ++i)
{
if(v[i] == v[i+1]){
continue;
} else {
printf("%d\n", v[i+1]);
counter++;
}
}
return counter;
}
int main()
{
int v[] = {1, 5, 5, 8, 1, 1};
int result = countDifferentNumbers(v,6);
printf("unique number %d", result );
return 0;
}

How to fix the error on erasing element from a vector?

I want to erase a particular element from a vector and I tried the following code. Actually I want to build a adjacency list and I want to delete an element from the adjacency list and to delete all edges connected to deleted element.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<vector<int> > tree(20);
void addEdge(int u, int v)
{
tree[u].push_back(v);
tree[v].push_back(u);
}
void printGraph(vector<vector<int>> tree [], int V)
{
vector<vector<int>>::iterator it;
int j;
for (it = tree.begin(); it != tree.end(); )
{
cout << "\n Adjacency list of vertex ";
for (j = 0; j < (*it).size(); j++)
{
cout << j << "\n head ";
cout << "-> " << (*it)[j];
}
cout << endl;
if (j==2) it = tree.erase(it);
}
}
int main()
{
int n = 5;
addEdge(1, 2);
addEdge(3, 2);
addEdge(4, 2);
addEdge(2, 5);
printGraph(tree, n);
}
How to fix the error on erasing element from a vector?
For your immediate needs, use
for (it = tree.begin(); it != tree.end(); ) // loops on the entire tree
{
for (int j = 0; j < (*it).size(); j++) // loops through adjacent vertices in the current node
cout << ' ' << (*it)[j];
cout << endl;
it = tree.erase(it); // erase current node (same thing as it = tree.erase(it.begin()))
}
to print your tree and linearly delete each row.
Original Answer before question was updated:
as a static array of `std::vector<int</code>'s, we won't be able to use `std::vector<></code> member functions directly on tree (e.g. `tree.begin()</code> generates an error because there is no `.begin()</code> member function for a static array).>
An alternative is to use std::begin(tree) and std::end(tree) defined from the <iterator> header file.
But since, you're wanting to delete (erase) parts of the array, a better way of structuring this data is to use std::vector<std::vector<int>> tree(20) which will create a 2D array. Here, the .erase() member function is valid.
Alternative to Storing Data (Helpful)
Also I believe adjacency matrices usually have static size? For example:
A B C
A 0 1 0
B 1 0 1
C 0 1 0
would show that there are 3 nodes (A, B, C) and there are two edges (AB, BC).
Removing an edge would just be as simple as changing the edge from 1 to 0. Here, you can use std::vector<int> tree[20] or better, bool tree[20][20] (should use bool since we're only dealing with 1's and 0's). Then you would need to reimplement the addEdge function, but that should be in your scope of understanding.
Hope this helps.

How to decrease key for a particular edge in a priority_queue<PI, vector<PI> ,greater<PI> >,trying to implement prim's algorithm?

#include <bits/stdc++.h>
using namespace std;
#define fast ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define LL long long int
#define pb push_back
#define mp make_pair
#define PI pair<int,int>
#define PL pair<LL,LL>
#define PIS pair< int,string>
#define test int t;cin>>t;while(t--)
#define ff first
#define ss second
#define INF 1000000000
#define input(a,n) for(i=1;i<=n;i++)cin>>a[i];
#define output(a,n) for(i=1;i<=n;i++)cout<<a[i]<<" ";
vector< vector<LL> >v(3002, vector<LL>(3002,-1));
priority_queue<PI, vector<PI> ,greater<PI> > pp;
LL w=0;
int vis[3002]={0};
/*void deck(int a ,int b, int *k)
{
while(!pp.empty())
{
i=pp.top.ss;
if(i==a)
pp.top
}
}*/
void prim(LL s, LL *k, LL *p,LL n)
{
pp.push(mp(0,s));
k[s]=0;
LL i,x,a,b,c=0;
vector<PI >::iterator it;
while(true)
{
if(c==n)
break;
i=pp.top().ss;
//cout<<i<<" ";
if(vis[i]!=1)
w=w+pp.top().ff;
vis[i]=1;
c++;
pp.pop();
for(x=1;x<=n;x++)
{
if(v[i][x]!=-1)
{
a=x;
b=v[i][x];
if(!vis[a] && b<k[a])
{
k[a]=b;
p[a]=i;
pp.push(mp(b,a));
}
}
}
}
}
int main()
{
fast
LL n,m,x,i,j,r,s;
/*pp.push(mp(2,3));
pp.push(mp(3,4));*/
cin>>n>>m;
LL k[n+1],p[n+1];
v.resize(n+1);
for(x=1;x<n+1;x++)
{
k[x]=INF;
p[x]=-1;
}
for(x=0;x<m;x++)
{
cin>>i>>j>>r;
/*v[i].pb(mp(j,r));
v[j].pb(mp(i,r));*/
if(v[i][j]!=-1)
{
if(v[i][j]>r)
{
v[i][j]=r;
v[j][i]=r;
}
}
else
{
v[i][j]=r;
v[j][i]=r;
}
}
cin>>s;
prim(s,k,p,n);
cout<<w;
//cout<<pp.top().ss;
}
I was not able to implement the function which searches a particular
value i.e the vertex and changes it's key value instead I pushed the
changed pair, using
pp.push(mp(b,a));
I was able to get some test cases right by using the if statement
if(c==n)
break;
where 'c' represents the count of vertexes visited.
The standard std::priority_queue does not allow to peak inside of it so changing priority keys is not possible. It is a classic queue implementation with pushing elements at one side and popping them back at the other. So probably you should look for a more general implementation of the heap data structure.
If you insist on using std::priority_queue you might need to do something as ugly as popping the full queue content to a vector, updating elements and restoring the queue.
There are three ways I know of.
If you insist on using the standard library's priority_queue, you can insert each vertex multiple times, but ignore it every time you see it except the first. In your code, you can change if(vis[i]!=1) w=w+pp.top().ff; into if(vis[i]==1) continue; (perhaps; didn't test). The downside is that your priority_queue can grow to O(|E|) memory.
You can also use the standard library's set instead of priority_queue. Then, whenever you want to insert a pair (distance, vertex), first you have to find and remove the pair (old_distance, vertex) if it is in the set. To know old_distance to each vertex at all times, you have to maintain an array (or vector) with the current distances. This way, you keep memory to O(|V|), but set has a greater constant factor than priority_queue.
Finally, you can implement a priority queue which allows deletion. Let's say you implement the priority queue as a binary heap. Then, you will have to maintain an inverse permutation of elements in the priority queue: for each element v, store and track what is the current heap index of v. One of the other answers looks like it implements this approach, the inverse permutation being index_map.
priority_queue in C++ does not provide the functionality of decrease key operation which means we cannot find a key in priority_queue and decrease its value. One way I know to achieve this is to implement a priority queue ourselves and then maintain another structure (a vector or a map) which would store the indices of keys in the priority queue. Try to understand the code below which uses this idea.
// C++11 code
#include <iostream>
#include <vector>
#include <cstring>
#define SIZE 5 // number of vertices.
#define INF 100000000
/* This vector will contain a pair of integers where the first integer in
the pair is value(cost) and the second is the vertex.
This will be our priority queue.
*/
std::vector <std::pair <int, int> > pq (SIZE);
int size = SIZE; // size of priority queue
int index_map[SIZE];
// Shift up the key with lower value.
void sift_up(int index) {
int parent = (index-1)/2;
while(index >= 0 && pq[index].first < pq[parent].first) {
index_map[pq[index].second] = parent;
index_map[pq[parent].second] = index;
std::swap(pq[index], pq[parent]);
index = parent;
parent = (index - 1)/2;
}
}
// Shift down the key with higher value.
void sift_down(int index) {
int left = 2*index+1, right = 2*index+2;
int min_index = index;
if(left < size && pq[left].first < pq[min_index].first)
min_index = left;
if(right < size && pq[right].first < pq[min_index].first)
min_index = right;
if(min_index != index) {
index_map[pq[index].second] = min_index;
index_map[pq[min_index].second] = index;
std::swap(pq[index], pq[min_index]);
sift_down(min_index);
}
}
// Extract the minimum element from priority queue.
std::pair <int, int> extract_min() {
index_map[pq[0].second] = size-1;
index_map[pq[size-1].second] = 0;
std::swap(pq[0], pq[size-1]);
size -= 1;
sift_down(0);
return pq[size];
}
// Change the value at index 'index' to 'value'.
void decrease_key(int index, int value) {
int temp = pq[index].first;
pq[index].first = value;
if(value < temp)
sift_up(index);
else
sift_down(index);
}
// Initialise and heapify the priority queue.
void make_heap(int start_index) {
for(int i = 0; i < SIZE; i++) {
pq[i].first = INF;
pq[i].second = i;
}
pq[0].first = 0;
pq[start_index].second = start_index;
for(int i = SIZE-1; i >= 0; i--)
sift_down(i);
}
int main() {
/* Graph is represent using adjacency list. It takes the following form:
graph[u] = {{v_1, c_1}, {v_2, c_2}, ..., {v_n, c_n}};
The above line means that there is an undirected edge
between vertices 'u' and 'v_1' with cost 'c_1'.
Similarly for (u, v_2, c_2), ..., (u, v_n, c_n).
*/
std::vector <std::vector <std::pair <int, int> > > graph (SIZE);
graph[0] = {{1, 20}, {2, 50}, {3, 70}, {4, 90}};
graph[1] = {{0, 20}, {2, 30}};
graph[2] = {{0, 50}, {1, 30}, {3, 40}};
graph[3] = {{0, 70}, {2, 40}, {4, 60}};
graph[4] = {{0, 90}, {3, 60}};
int visited[SIZE];
memset(visited, 0, sizeof(visited));
visited[0] = 1;
make_heap(0); // Assuming algorithm to start from vertex 0.
for(int i = 0; i < SIZE; i++)
index_map[pq[i].second] = i;
int answer = 0;
while(size != 0) {
std::pair <int, int> p = extract_min();
/* p.first will contain the cost of the next edge to be added in our
answer and p.second will give the vertex number.
*/
visited[p.second] = 1;
answer += p.first;
for(int i = 0; i < graph[p.second].size(); i++) {
if(!visited[graph[p.second][i].first]) {
if(graph[p.second][i].second < pq[index_map[graph[p.second][i].first]].first) {
decrease_key(index_map[graph[p.second][i].first], graph[p.second][i].second);
}
}
}
}
std::cout << answer << "\n";
}
I found a way to implement the algorithm using
std::priority_queue
By changing approach, would like to share my code
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<limits.h>
#include<map>
#include<stack>
#include<stdio.h>
#include<queue>
#include<cmath>
#include<string.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define PII pair<int,int>
vector<PII> v[3001];
bool vis[3001];
int sum=0;
void prim(int s)
{
int y,x,i;
PII p;
priority_queue<PII, vector<PII> , greater<PII> > q;
q.push(mp(0,s));
while(!q.empty())
{
p = q.top();
q.pop();
x = p.ss;
if(vis[x]==true)
continue;
sum+=p.ff;
vis[x]=true;
for(i=0;i<v[x].size();i++)
{
y = v[x][i].ss;
if(vis[y]==false)
q.push(v[x][i]);
}
}
}
int main() {
fast
int f1=0,max=0,y,a1,x,j,w=0,f=0,l,m,b,c1=0,r=0;
char t,a[4][4],c;
int n,i=0,d=1,k;
cin>>n>>k;
for(x=0;x<k;x++)
{
cin>>i>>j>>r;
v[i].pb(mp(r,j));
v[j].pb(mp(r,i));
}
cin>>i;
prim(i);
cout<<sum;
return 0;
}

how can I find repeated elements in a vector [duplicate]

This question already has answers here:
Checking for duplicates in a vector [duplicate]
(5 answers)
Closed 9 years ago.
I have a vector of int which can include maximum 4 elements and minimum 2, for example :
std::vector<int> vectorDATA(X); // x means unknown here
What I want to do is to erase the elements that are repeated for example :
vectorDATA{1,2,2} to vectorDATA{1,2}
vectorDATA{1,2,3} to nothing changes
vectorDATA{2,2,2} to vectorDATA{2}
vectorDATA{3,2,1,3} to vectorDATA{3,2,1}
vectorDATA{1,2,1,2} to vector{1,2}
and so on
here a code simple :
cv::HoughLines(canny,lineQ,1,CV_PI/180,200);
std::cout << " line Size "<<lineQ.size()<< std::endl;
std::vector<int> linesData(lineQ.size());
std::vector<int> ::iterator it;
if(lineQ.size() <=4 && lineQ.size() !=0 ){
if(lineQ.size()==1){
break;
}else {
for ( int i = 0; i<lineQ.size();i++){
linesData[i] = lineQ[i][1]; // my comparison parameter is the lineQ[i][1]
}
// based on the answer I got I'm trying this but I really don't how to continue ?
std::sort(lineQ.begin(),lineQ.end(),[](const cv::Vec2f &a,const cv::Vec2f &b)
{
return ????
}
I tried use a for and do while loop, but I didn't get it, and the function std::adjacent_find this has a condition that the elements should be consecutive.
Maybe it's easy but I just don't get it !
thanks for any help !
The easy way is sort then unique-erase, but this changes order.
The c++11 order preserving way is to create an unordered_set<int> s; and do:
unordered_set<int> s;
vec.erase(
std::remove_if( vec.begin(),vec.end(), // remove from vector
[&](int x)->bool{
return !std::get<1>(s.insert(x)); // true iff the item was already in the set
}
),
vec.end() // erase from the end of kept elements to the end of the `vec`
);
which is the remove-erase idiom using the unordered_set to detect duplicates.
I didn't see a sort-less source code in the already mentioned answers, so here it goes. Hash table for checking duplicates, shifting unique elements towards the front of the vector, note that src is always >= dst and dst is the number of copied, i.e. unique elements at the end.
#include <unordered_set>
#include <vector>
#include <iostream>
void
uniq (std::vector<int> &a) {
std::unordered_set<int> s;
size_t dst = 0;
for (size_t src = 0; src < a.size(); ++src) {
if (s.count (a[src]) == 0) {
s.insert (a[src]);
a[dst++] = a[src];
}
}
a.resize (dst);
}
int
main () {
std::vector<int> a = { 3, 2, 1, 3, 2, 1, 2, 3, 4, 5 ,2, 3, 1, 1 };
uniq (a);
for (auto v : a)
std::cout<< v << " ";
std::cout << std::endl;
}
If you want to realy remove repeated elements, you may try something like this:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main () {
int data[] = {1,2,3,2,1};
vector<int> vectorDATA = (&data[0], &data[0] + 5);
sort(vectorDATA.begin(),vectorDATA.end());
for(int i = 0; i < vectorDATA.size()-1; ++i)
{
if(vectorDATA[i] == vectorDATA[i+1])
vectorDATA.erase(vectorDATA.begin()+i+1);
}
for(int i = 0; i < vectorDATA.size();++i)
{
cout << vectorDATA[i] << " ";
}
cout << endl;
return 0;
}
Lack of of this method is then elements lost his order.