Print adjacency list by using multimap c++ - c++

I constructed an adjacency list based on the following link: Adjacency list
struct Node
{
string name;
int id;
};
typedef std::multimap<Node,Node> Graph;
Graph g;
g.insert (Graph::value_type(node1, node3));
g.insert (Graph::value_type(node1, node4));
g.insert (Graph::value_type(node1, node5));
g.insert (Graph::value_type(node2, node6));
g.insert (Graph::value_type(node3, node6));
How can I print the multimap by following the structure of the following image (Adjacency list)?

Graph::const_iterator it = g.begin();
while (it != g.end())
{
std::pair<Graph::const_iterator, Graph::const_iterator> range
= g.equal_range(it->first);
std::cout << it->first << ": "; // print vertex
for (; range.first != range.second; ++range.first)
{
std::cout << range.first->second << ", "; // print adjacent vertices
}
std::cout << std::endl;
it = range.second;
}
Output:
1: 3, 4, 5,
2: 6,
3: 6,
4: 7,
5: 7, 8, 9,
9: 5,
DEMO
If you don't want that redundant equal_range call, you can operate with a single iterator as long as two adjacent elements are equal in terms of ordering:
Graph::key_compare cmp = g.key_comp();
Graph::const_iterator it = g.begin(), itEnd = g.end(), prev;
while (it != itEnd)
{
std::cout << it->first << ": "; // print vertex
do
{
std::cout << it->second << ", "; // print adjacent vertices
prev = it++;
}
while (it != itEnd && !cmp(prev->first, it->first));
std::cout << std::endl;
}
DEMO 2

The following alternative solution makes use of C++11's range-based for loop. It iterates through all entries regardless the source node, and compares the current source node with the previous one. If they're different, start a new line in the output.
Compared to the solution using equal_range, this alternative is a little bit more cache-friendly: it only iterates over the whole graph once in the order of the nodes. equal_range first searches for the end of the range with the same source node, and then the loop iterates again over these elements. My alternative solution avoids this. (Of course, I did no benchmark and this is not to be meant as the ultimate fastest solution, but I just wanted to provide an alternative.)
std::ostream& operator<<(std::ostream& os, const Graph& g)
{
auto prev = g.begin()->first;
os << prev << ": ";
for (auto e : g) {
if (e.first < prev || prev < e.first)
os << std::endl << (prev = e.first) << ": ";
os << e.second << ", ";
}
return os << std::endl;
}
Live demo
If you implement operator!= for your Node type, the if-line can be simplified to a more readable comparison:
std::ostream& operator<<(std::ostream& os, const Graph& g)
{
auto prev = g.begin()->first;
os << prev << ": ";
for (auto e : g) {
if (e.first != prev) // <--- now more readable
os << std::endl << (prev = e.first) << ": ";
os << e.second << ", ";
}
return os << std::endl;
}

Related

vector how find first and last current value

Task: find first and last current values.
Example:
vector = {1,2,3,1,6,2,1};
need value 1 =>
first index = 0, last = 6; (index/position);
vector<int>::iterator it = find(v.begin(), v.end(), 1);
if (it != v.end())
{
cout << "Element Found" << std::endl;
// Get index of element from iterator
int index = distance(v.begin(), it);
int lastindex = distance(v.end(), it); // bad try to find
cout <<"Index of first element in vector : "<<index<<" last elem ";
// bad code <<lastindex - index <<endl;
}
else
{
cout << "Element Not Found" << std::endl;
}
I found first position but, I can't find last position.
Need help)
You can use reverse iterator to find the last element as follows:
DEMO
int main()
{
std::vector<int> v = {1,2,3,1,6,2,1};
const int currentVal = 1;
const auto itf = std::find(v.cbegin(), v.cend(), currentVal);
const auto itb = std::find(v.crbegin(), v.crend(), currentVal);
if(itf != v.cend()){
std::cout << "front pos: " << std::distance(v.cbegin(), itf) << std::endl;
std::cout << "back pos : " << (v.size() - std::distance(v.crbegin(), itb) - 1) << std::endl;
}
else{
std::cout << currentVal << " is not found." << std::endl;
}
return 0;
}
You can use "rbegin" and "rend" to reverse the list and find the last occurrence by using the same code you have now.
vector = {1,2,3,1,6,2,1};
need value 1 =>
first index = 0, last = 6; (index/position);
vector<int>::iterator it = find(v.begin(), v.end(), 1);
vector<int>::iterator it_reverse = find(v.rbegin(), v.rend(),1);
if (it != v.end() && it_reverse != v.rend())
{
cout << "Element Found" << std::endl;
// Get index of element from iterator
int index = distance(v.begin(), it);
int lastindex = distance(v.rend(), it_reverse); // bad try to find
cout <<"Index of first element in vector : "<<index<<" last elem ";
}
else
{
cout << "Element Not Found" << std::endl;
}

Printing a list of lists C++ STL list

I have a top list that stores inner lists. I'm using the standard template library list template.
I am attempting to print the values of the inner lists.
The top list is "L" and the inner list is "I".
void ListofLists::dump()
{
list<list<IntObj>>::iterator itr;
for (itr = L.begin(); itr != L.end(); itr++)
{
list<IntObj>::iterator it;
for (it = I.begin(); it != I.end(); it++)
{
cout << *it << " ";
}
cout << endl << "End" << endl;
}
}
My IDE doesn't like the line cout << *it << " ";and I'm not really sure how to change it while having the program do what I want it to do, which is print the data inside of the lists.
It red underlined the “<<“ operator and says “no operator “<<“ matches these operands.”
Can someone help me as to why? I've looked and can't really find what I'm looking for. I'm not understanding something correctly. I know it is adding the data to the data structure correctly because my IDE enables me to view my locals.
Thanks to anyone who helps! Means a lot.
Try to use :
list<IntObj>::const_iterator i;
instead the one you are using to avoid compiling error.
The inner loop does not make sense.
If you want to use iterators then the function can be defined like
void ListofLists::dump() /* const */
{
for (list<list<IntObj>>::iterator itr = L.begin(); itr != L.end(); itr++)
{
for ( list<IntObj>::iterator it = itr->begin(); it != itr->end(); it++)
{
cout << *it << " ";
}
cout << endl << "End" << endl;
}
}
However it will be simpler to use the range-based for loop. For example
void ListofLists::dump() /* const */
{
for ( const auto &inner_list : L )
{
for ( const auto &item : inner_list )
{
cout << item << " ";
}
cout << endl << "End" << endl;
}
}
Take into account that you have to define the operator << for the class IntObj.
Its declaration should look like
std::ostream & operator <<( std::ostream &, const IntObj & );

C++ printing a list of sets

I'm trying to print out a list of sets but I'm confused with the syntax. I want each set to be on a new line. Here is my code:
set<int> set1 = { 2, 4, 5 };
set<int> set2 = { 4, 5 };
list<set<int>> list1;
list<set<int>>::iterator it = list1.begin();
list1.insert(it, set1);
list1.insert(it, set2);
cout << "List contents:" << endl;
for (it = list1.begin(); it != list1.end(); ++it)
{
cout << *it; //error is here
}
I'm getting an error when trying to print the pointer to the iterator. Pretty sure its because I'm using a set inside of the list, but I don't know the proper syntax for outputting this list.
Do you want to print as following?
for (it = list1.begin(); it != list1.end(); ++it)
{
for (set<int>::iterator s = it->begin(); s != it->end(); s++) {
cout << *s << ' ';
}
cout << endl;
}
output:
List contents:
2 4 5
4 5
There is no overload of operator << for std::set, you have to write the loop yourself (and possibly creating a function for that)
With for range, you may simply do:
for (const auto& s : list1) {
for (int i : s) {
std::cout << i << ' ';
}
std::cout << std::endl;
}

Binary search on strings instead of numbers

I am reading up on binary search on an array of numbers and I believe I know how it works and how to implement it. Now I need to know how to do binary search on an array of strings ? I know binary search requires the array to be sorted already. suppose I have an array of strings already sorted how do I implement binary search on it ? I know if it was an array of numbers I would go to the middle index of the array and determin if the required search no is on the left or the right and do that recursively. How would i do that for strings?
As long as the concept of "it is equal to" and "it is less than" are defined for the type you are working on, you can implement the algorithm. It does not matter if the values are numbers, letters, or custom objects. The following example demonstrates this concept:
template<typename Iterator>
Iterator search(Iterator initial, Iterator final, const typename Iterator::value_type& value) {
if(value < *initial) {
// bail out immediately
return final;
}
while(initial != final) {
auto mid = std::next(initial, std::distance(initial, final) / 2);
if(*mid == value) {
return mid;
} else if(*mid < value) {
initial = std::next(mid);
} else {
final = std::prev(mid);
}
}
return final;
}
As long as the operations *mid == value and *mid < value are defined, I can search in a container of any type (another requirement is that I must be able to randomly access my iterator).
This is by no means a full answer, and there are many more details involved, but hopefully you get the idea.
Full sample program:
#include <vector>
#include <list>
#include <iostream>
template<typename Iterator>
Iterator search(Iterator initial, Iterator final, const typename Iterator::value_type& value) {
if(value < *initial) {
// bail out immediately
return final;
}
while(initial != final) {
auto mid = std::next(initial, std::distance(initial, final) / 2);
if(*mid == value) {
return mid;
} else if(*mid < value) {
initial = std::next(mid);
} else {
final = std::prev(mid);
}
}
return final;
}
int main() {
{
std::vector<int> v {1, 2, 3, 4, 5};
auto it = search(v.begin(), v.end(), 3);
if(it == v.end()) {
std::cout << "Not Found!" << std::endl;
} else {
std::cout << "Found in position: " << std::distance(v.begin(), it)
<< " (value is : " << *it << ")" << std::endl;
}
}
{
std::vector<char> v {'a', 'b', 'c', 'd', 'e'};
auto it = search(v.begin(), v.end(), 'd');
if(it == v.end()) {
std::cout << "Not Found!" << std::endl;
} else {
std::cout << "Found in position: " << std::distance(v.begin(), it)
<< " (value is : " << *it << ")" << std::endl;
}
}
{
std::list<float> v {-1, 0, 1, 2, 3, 4};
auto it = search(v.begin(), v.end(), 0);
if(it == v.end()) {
std::cout << "Not Found!" << std::endl;
} else {
std::cout << "Found in position: " << std::distance(v.begin(), it)
<< " (value is : " << *it << ")" << std::endl;
}
}
{
std::vector<char> v {'a', 'b', 'c', 'd', 'e'};
auto it = search(v.begin(), v.end(), 'f');
if(it == v.end()) {
std::cout << "Not Found!" << std::endl;
} else {
std::cout << "Found in position: " << std::distance(v.begin(), it)
<< " (value is : " << *it << ")" << std::endl;
}
}
}
Sample Run:
Found in position: 2 (value is : 3)
Found in position: 3 (value is : d)
Found in position: 1 (value is : 0)
Not Found!
A naive approach would be to assign a unique value to each letter (if you're doing English, that's easy; only 26 values), and compare the values of the first letter of each string. If the letters are the same, then you compare the second letter, and so on.
If you use array of std::string, it just the same since you have all compare operators.
so you just need to replace the type of the array and you can do the search as is for numbers.
Exact same way. If you use std::string, it already has operator== and operator < which are all you need for binary search. If you just have character pointers, you can use strcmp, where a negative value is less than and 0 is equal.

How to detect first or last element iterating over a container?

How to do the following in more stylish/short way?
for(i=container.begin(); i!=container.end(); ++i) {
if (i!=container.begin()) {
cout << ", ";
}
cout << *i;
j=i;
if (++j==container.end()) {
cout << "!" << endl;
}
}
Solutions like foreach are acceptable (actions on first and last elements need to be configurable, though).
P.S.
There are many answers that are handling first element, but not last. Here is what I mean by handling last element:
for(i=container.begin(); i!=container.end(); ++i) {
j=i;
if (i==container.begin()) {
cout << "[" << *i << "]" << endl;
} else if (++j==container.end()) {
cout << ", (" << *i << ")" << "!" << endl;
} else {
cout << ", " << *i;
}
}
Don't you think it's very easy to handle first element outside the cycle body? The real problem is the last one! I'm sorry for not being able to clarify the important point asking the question. I think I'll just accept the top ranked answer eventually.
Boost has next / prior which can sometimes help in such situations.
for(i=container.begin(); i!=container.end(); ++i) {
if (boost::next(i) == container.end()) {
std::cout << "!" << std::endl;
}
}
Although for this specific case, I'd simply output the first element, loop from second till last while always outputting the ',' and then output the '!' after the loop has ended. (as others have suggested already)
I don't see the point in moving the special cases inside the loop, and then checking inside the loop for them....
My advice here would be: there is no point in detecting anything within this loop !
Since your special cases are at the beginning and the end of your container, it is easy to remove their processing from within the loop.
The following function will print the contents of any container class whose elements can be <<'ed to an std::ostream:
template < class Container >
void print(Container const & container)
{
typename Container::const_iterator current = container.begin();
typename Container::const_iterator const end = container.end();
if (current != end)
{
std::cout << *current;
for (++current; current != end; ++current)
{
std::cout << ", " << *current;
}
std::cout << "!" << std::endl;
}
}
In your code,
if (i==container.end()) {
cout << "!" << endl;
}
will never happen.
My own approach would be to use the container size (I think size() is now constant time for all Standard Library containers). Maintain a count in the loop and you are at the end when count == size() - 1, and at the beginning when count == 0, obviously.
As container is not defined by you, I used the simplest - vector
template <class T>
string vector_join( const vector<T>& v, const string& token ){
ostringstream result;
for (typename vector<T>::const_iterator i = v.begin(); i != v.end(); i++){
if (i != v.begin()) result << token;
result << *i;
}
return result.str();
}
//usage
cout << vector_join( container, ", " ) << "!";
Shift the ++i a bit:
i = container.begin();
while(i != container.end()) {
if (i != container.begin()) {
cout << ", ";
}
cout << *i;
if (++i == container.end()) {
cout << "!" << endl;
}
}
template < class TContainerType>
void print(TContainerType const & i_container)
{
typename TContainerTypeconst ::const_iterator current = i_container.begin();
typename TContainerTypeconst ::const_iterator const end = i_container.end();
if(current != end)
{
std::cout << *current++;
while(current != end)
std::cout << ", " << *current++;
}
std::cout << "!" << std::endl;
}
Take the second part out of the loop.
for(i=container.begin(); i!=container.end(); ++i) {
if (i != container.begin()) {
cout << ", ";
}
cout << *i;
}
cout << "!" << endl;