push_back of STL list got bad performance? - c++

I wrote a simple program to test STL list performance against a simple C list-like data structure. It shows bad performance at "push_back()" line. Any comments on it?
$ ./test2
Build the type list : time consumed -> 0.311465
Iterate over all items: time consumed -> 0.00898
Build the simple C List: time consumed -> 0.020275
Iterate over all items: time consumed -> 0.008755
The source code is:
#include <stdexcept>
#include "high_resolution_timer.hpp"
#include <list>
#include <algorithm>
#include <iostream>
#define TESTNUM 1000000
/* The test struct */
struct MyType {
int num;
};
/*
* C++ STL::list Test
*/
typedef struct MyType* mytype_t;
void myfunction(MyType t) {
}
int test_stl_list()
{
std::list<mytype_t> mylist;
util::high_resolution_timer t;
/*
* Build the type list
*/
t.restart();
for(int i = 0; i < TESTNUM; i++) {
mytype_t aItem;
aItem->num = i;
mylist.push_back(aItem);
}
std::cout << " Build the type list : time consumed -> " << t.elapsed() << std::endl;
/*
* Iterate over all item
*/
t.restart();
std::for_each(mylist.begin(), mylist.end(), myfunction);
std::cout << " Iterate over all items: time consumed -> " << t.elapsed() << std::endl;
return 0;
}
/*
* a simple C list
*/
struct MyCList;
struct MyCList{
struct MyType m;
struct MyCList* p_next;
};
int test_simple_c_list()
{
struct MyCList* p_list_head = NULL;
util::high_resolution_timer t;
/*
* Build it
*/
t.restart();
struct MyCList* p_new_item = NULL;
for(int i = 0; i < TESTNUM; i++) {
p_new_item = (struct MyCList*) malloc(sizeof(struct MyCList));
if(p_new_item == NULL) {
printf("ERROR : while malloc\n");
return -1;
}
p_new_item->m.num = i;
p_new_item->p_next = p_list_head;
p_list_head = p_new_item;
}
std::cout << " Build the simple C List: time consumed -> " << t.elapsed() << std::endl;
/*
* Iterate all items
*/
t.restart();
p_new_item = p_list_head;
while(p_new_item->p_next != NULL) {
p_new_item = p_new_item->p_next;
}
std::cout << " Iterate over all items: time consumed -> " << t.elapsed() << std::endl;
return 0;
}
int main(int argc, char** argv)
{
if(test_stl_list() != 0) {
printf("ERROR: error at testcase1\n");
return -1;
}
if(test_simple_c_list() != 0) {
printf("ERROR: error at testcase2\n");
return -1;
}
return 0;
}
Oops, Yes.
I modified the code, and it show:
$ ./test2
Build the type list : time consumed -> 0.163724
Iterate over all items: time consumed -> 0.005427
Build the simple C List: time consumed -> 0.018797
Iterate over all items: time consumed -> 0.004778
So, my question is, why my "push_back" code got bad performance?

Well one thing is that in C, you have a linked list of objects but in C++, you have a linked list of pointers (so for one thing, you are doing twice as many allocations). To compare apples to apples, your STL code should be:
int test_stl_list()
{
std::list<MyType> mylist;
util::high_resolution_timer t;
/*
* Build the type list
*/
t.restart();
for(int i = 0; i < TESTNUM; i++) {
MyItem aItem;
aItem.num = i;
mylist.push_back(aItem);
}
std::cout << " Build the type list : time consumed -> " << t.elapsed() << std::endl;
return 0;
}

Your STL codes create a memory piece twice for each cell.
The following is from STL 4.1.1 on x86_64
void push_back(const value_type& __x)
{
this->_M_insert(end(), __x);
}
// Inserts new element at position given and with value given.
void _M_insert(iterator __position, const value_type& __x)
{
_Node* __tmp = _M_create_node(__x); // Allocate a new space ####
__tmp->hook(__position._M_node);
}
As you can see, also, push_back() function calls several more functions before returning to the caller, and
few pointer-value copying occurs everytime one of the functions is called.
Might be neligible because all the parameters are passed by const-reference though.

First, it looks like you're doing a push_front, not a push_back (in your own implementation, that is).
Second, you should also compare std::slist for a fair comparison as the std::list is double-linked.
Third, you need to use right compiler flags for a fair comparison. With gcc you should at least compile with -O2. Without optimization, STL always sucks because no inlining is done and there is lots of function call overhead.

It would seem your high_resolution_timer class is measuring more than just the routines you are trying to measure. I would refactor the code such that the only code between t.restart() and t.elapsed() is what you are keen on measuring. All other code therein could have unknown performance implications that could skew your results.

Related

openmpi/c++: defining a mpi data type for class with members of variable length (pointers pointing to malloced memory)?

i am currently learning to use openmpi, my aim is to parallelize a simple program whose code i will post bellow.
The program is for testing my concept of paralleling a much bigger program, i hope to learn all i need to know for my actual problem if i succeed with this.
Basically it is a definition of a simple c++ class for lists. A list consists of two arrays, one integer and one double. Entries with the same indicies belong together, in a way that the integer entry is some kind of list entry identifier (maybe an object ID) and the double entry is some kind of quantifier (maybe the weight if an object).
The basic purpose of the program is to add lists together (this is the task i want to parallelize). Adding works as follows: For each entry in one list it is checked if there is the same integer entry in the the other list, if so then the double entry gets added to the double entry in the other list, if there is no such entry in the other list then both the integer and the double entries gets added to the end of the list.
Basically each summand in this list addition represents a storage and each entry is a type of object with a given amount (int is the type and double is the amount), so adding two lists means putting the stuff from the second storage to the first.
The order of the list entries is irrelevant, this means that the addition of lists is not only associative but commutative too!
My plan is to add a very large number of such lists (a few billions) so parallelizing could be to let each thread add a subset of lists first and when this is finished distribute all such sublists (one for each thread) to all of the threads.
My current understanding of openmpi is that only the last step (distributing of finished sublists) needs any special non standard stuff. Basically i need a AllReduce but with a custom data type and a custom operaton.
The first problem i have is understanding how to create a fitting MPI data type. I came to the conclusion that i probably need MPI_Type_create_struct to create a struct type.
I found this site with a nice example: http://mpi.deino.net/mpi_functions/MPI_Type_create_struct.html
from which i learned a lot but the problem is, that in this case there are fixed member arrays. In my case i have lists with arbitrary sized member variables or better with pointers pointing to memory blocks of arbitrary size. So doing it like in the example would lead to creating a new MPI datatype for each list size (using fixed sized lists could help but only in this minimalistic case, but i want to learn how to do it with arbitrary sized lists are preparation for my actual problem).
So my question is: how to create a data type for this special case? What is the best way?
I even thought to maybe write some non mpi code to serialize my class/object, (which would be a lot of work for my real problem but in this example it should be easy) to a single block of bits. Then i could simply use a MPI function to distribute those blocks to all threads and then i just have to translate it back to the actual object, and then i could let each thread simply add the "number-of-threads" lists together to have the same full reduced list on all threads (because the operation is commutative it is not important if the order is the same on each thread in the end).
The problem is that i do not know which MPI function to use to distribute a such memory blocks to each thread so that in the end each thread has an array of "number-of-threads" such blocks (similar like AllReduce but with blocks).
But thats just another idea, i would like to hear from you whats the best way.
Thank you, here is my fully working example program (ignore the MPI parts thats just preparation, you can simply compile with: g++)
As you can see, i needed to create custom copy constructors because standard of the pointer members. I hope thats not a problem for MPI?
#include <iostream>
#include <cstdlib>
#if (CFG_MPI > 0)
#include <mpi.h>
#else
#define MPI_Barrier(xxx) // dummy code if not parallel
#endif
class list {
private:
int *ilist;
double *dlist;
int n;
public:
list(int n, int *il, double *dl) {
int i;
if (n>0) {
this->ilist = (int*)malloc(n*sizeof(int));
this->dlist = (double*)malloc(n*sizeof(double));
if (!ilist || !dlist) std::cout << "ERROR: malloc in constructor failed!" << std::endl;
} else {
this->ilist = NULL;
this->dlist = NULL;
}
for (i=0; i<n; i++) {
this->ilist[i] = il[i];
this->dlist[i] = dl[i];
}
this->n = n;
}
~list() {
free(ilist);
free(dlist);
ilist = NULL;
dlist = NULL;
this->n=0;
}
list(const list& cp) {
int i;
this->n = cp.n;
this->ilist = NULL;
this->dlist = NULL;
if (this->n > 0) {
this->ilist = (int*)malloc(this->n*sizeof(int));
this->dlist = (double*)malloc(this->n*sizeof(double));
if (!ilist || !dlist) std::cout << "ERROR: malloc in copy constructor failed!" << std::endl;
}
for (i=0; i<this->n; i++) {
this->ilist[i] = cp.ilist[i];
this->dlist[i] = cp.dlist[i];
}
}
list& operator=(const list& cp) {
if(this == &cp) return *this;
this->~list();
int i;
this->n = cp.n;
if (this->n > 0) {
this->ilist = (int*)malloc(this->n*sizeof(int));
this->dlist = (double*)malloc(this->n*sizeof(double));
if (!ilist || !dlist) std::cout << "ERROR: malloc in copy constructor failed!" << std::endl;
} else {
this->ilist = NULL;
this->dlist = NULL;
}
for (i=0; i<this->n; i++) {
this->ilist[i] = cp.ilist[i];
this->dlist[i] = cp.dlist[i];
}
return *this;
}
void print() {
int i;
for (i=0; i<this->n; i++)
std::cout << i << " : " << "[" << this->ilist[i] << " - " << (double)dlist[i] << "]" << std::endl;
}
list& operator+=(const list& cp) {
int i,j;
if(this == &cp) {
for (i=0; i<this->n; i++)
this->dlist[i] *= 2;
return *this;
}
double *dl;
int *il;
il = (int *) realloc(this->ilist, (this->n+cp.n)*sizeof(int));
dl = (double *) realloc(this->dlist, (this->n+cp.n)*sizeof(double));
if (!il || !dl)
std::cout << "ERROR: 1st realloc in operator += failed!" << std::endl;
else {
this->ilist = il;
this->dlist = dl;
il = NULL;
dl = NULL;
}
for (i=0; i<cp.n; i++) {
for (j=0; j<this->n; j++) {
if (this->ilist[j] == cp.ilist[i]) {
this->dlist[j] += cp.dlist[i];
break;
}
} if (j == this->n) {// no matching entry found in this
this->ilist[this->n] = cp.ilist[i];
this->dlist[this->n] = cp.dlist[i];
this->n++;
}
}
il = (int *) realloc(this->ilist, (this->n)*sizeof(int));
dl = (double *) realloc(this->dlist, (this->n)*sizeof(double));
if (!il || !dl)
std::cout << "ERROR: 2nd realloc in operator += failed!" << std::endl;
else {
this->ilist = il;
this->dlist = dl;
}
return *this;
}
};
int main(int argc, char **argv) {
int npe, myid;
#if (CFG_MPI > 0)
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD,&npe);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
#else
npe=1;
myid=0;
#endif
if (!myid) // reduce output
std::cout << "NPE = " << npe << " MYID = " << myid << std::endl;
int ilist[5] = {14,17,4,29,0};
double dlist[5] = {0.0, 170.0, 0.0, 0.0, 24.523};
int ilist2[6] = {14,117,14,129,0, 34};
double dlist2[6] = {0.5, 170.5, 0.5, 0.5, 24.0, 1.2};
list tlist(5, ilist, dlist);
list tlist2(6, ilist2, dlist2);
if (!myid) {
tlist.print();
tlist2.print();
}
tlist +=tlist2;
if (myid) tlist.print();
#if (CFG_MPI > 0)
MPI_Finalize();
#endif
return 0;
}

Accessibility for Vectors of Singly Linked Lists (or possibly a Linked List of Linked Lists)

Been wracking my mind all day trying to hammer out the underlying data structures for a challenge assignment in one of my programming classes.
The problem is as follows:
Given an assortment of objects (each of which includes an identifier and a weight) and a supply of containers (which have a fixed weight capacity), pack all the items using as few containers as possible without overloading any of them.
I have the logic aspects hammered out using a hodgepodge of arrays, but the dynamic nature of this assignment has me wanting to optimize things by using vectors and/or linked lists.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <math.h>
#include <time.h>
#include <conio.h>
#include <vector>
#include <algorithm>
using namespace std;
struct Item
{
int number;
double weight;
bool operator < (const Item& str) const
{
return (weight < str.weight);
}
};
class Node
{
int number;
double weight;
Node* next;
public:
Node()
{};
void SetID(int iNum)
{
number = iNum;
};
void SetWeight(double iWeight)
{
weight = iWeight;
};
void SetNext(Node* iNext)
{
next = iNext;
}
int GetID()
{
return number;
};
double GetWeight()
{
return weight;
};
Node* Next()
{
return next;
};
};
class List
{
Node* head;
double weight;
public:
List()
{
head = NULL;
weight = 0;
};
int Size()
{
Node* tmp;
int count = 0;
for (tmp = head; tmp != NULL; tmp = tmp->Next())
{
count++;
}
return count;
};
double Weight()
{
return weight;
};
void Print()
{
Node *tmp = head;
if ( tmp == NULL )
{
cout << " E M P T Y" << endl;
return;
}
do
{
cout << setw(8) << tmp->GetID() << " | " << setw(8) << tmp->GetWeight() << endl;
tmp = tmp->Next();
} while ( tmp != NULL );
};
void Append(int iNum, double iWeight)
{
Node* newNode = new Node();
newNode->SetID(iNum);
newNode->SetWeight(iWeight);
newNode->SetNext(NULL);
Node *tmp = head;
if ( tmp != NULL )
{
while ( tmp->Next() != NULL )
{
tmp = tmp->Next();
}
tmp->SetNext(newNode);
}
else
{
head = newNode;
}
weight += iWeight;
};
};
double ItemWeights(vector<Item> iVect)
{
double total = 0;
for(int i = 0; i < iVect.size(); i++)
{
total += iVect[i].weight;
}
return total;
}
int main()
{
const double MAX_WEIGHT = 20;
vector< Item > source;
//
// Segment of code which propagates the vector data
// works fine, but is excluded for the sake of brevity
//
double totalWeight = ItemWeights(source);
// Duplicate vector of items
vector< Item > items(source);
for(int i = 0; i < items.size(); i++)
{
cout << setw(8) << items[i].number << setw(8) << items[i].weight << endl;
}
cout << "\n Total weight = " << totalWeight << endl;
cout << "\n\n Press any key to continue... ";
getch();
// Solution A-Original
// vector< vector< Item > > boxesAO( vector< Item >);
// boxesAO[0].push_back({items[items.size()].number, items[items.size()].weight});
vector< List > boxesAO;
// boxesAO[0].Append(items[items.size()].number, items[items.size()].weight);
return 0;
}
I've left some of the methods I've tried in the code (commented out) - none of which worked. As I mentioned above, I've got it working with arrays of linked lists and with 2D arrays, but the vast range of potential input makes these problematic at best. Either a bunch of empty lists taking up space or, worse, not having enough.
I'm thinking that vector< List > is my best option, but I can't figure out how I'm supposed to access any of the List functionality.
If someone would be so helpful as to offer a suggestion for how to create a "dynamic 2D array" as well as a code example of how to access it, I would be most greatly appreciative. My deepest thanks in advance.
EDIT:
#jaredad7 ~ That's what I've been trying, but it keeps causing the program to crash.
List box;
box.Append(items[items.size()].number, items[items.size()].weight);
This works just fine - no problems whatsoever.
The earlier code propagates a 1D vector of Item structs, which also works properly.
vector< List > boxes;
boxes[0].Append(items[items.size()].number, items[items.size()].weight);
This compiles fine but crashes during execution, no matter what index is used. (I'm also using couts for debugging, and the issue most definitely lies with trying to access the List functions.)
I'm suspecting that .push_back or somesuch may be needed, but I haven't been able to find much information concerning vectors of List objects.
If you can, my first suggestion would be to go with the vector (if that is allowed). As for accessing functions/attributes of a member of a vector, it's done the same way as an array, that is:
vectorname[i].functionname(a,b,c);
The best way to do this without vectors would be to use your nodes as the item container (a struct), and handle node-creation, deletion, etc. in your list class. Then, you would only really need one container for as many objects of one type as you need. You can make the type dynamic (although it appears you only need doubles for this project) by adding a class template (use google if you are unfamiliar with templates in C++). This will allow your user to make a container for each type of data (much like a vector).

c++ odd behaviour of an array of iterators

So searching to see if someone has already asked this I see lots of questions about iterating over arrays. But what I've got is an array of iterators. Essentially here's what I'm up to:
I have a sorted std::list of a custom object. The object just contains an int and a double, and has methods for the sorts of things you would expect (constructors, setters, getters, operator< to make it sortable by the double, a toSting() method). That all works, including sorting.
Now I want a bunch of iterators that point into the list at different points. There will be one to the head of the list, one to the tail and several pointing into various points in the middle. I'm doing this using an old-style array (this may be the problem - I'll try it with a std::array, but I still want to understand why this hasn't worked). So I've got a subroutine that initializes this array. It almost works. I can build the array and output from within the subroutine and everything looks good. Outputting from outside the subroutine the last element of the array has changed and no longer appears to point into the list. Here's the relevant code:
using namespace std;
#include <iostream>
#include <list>
#include <cmath>
#include <algorithm>
#include "random.h"
#include "Double_list_struct.h"
/**********************************Subroutine declarations***************************/
template <typename Tplt>
void output_list(list<Tplt> to_out);
template <typename Tplt>
void initialize_list(list<Tplt> &alist, int size);
template <typename Tplt>
void initialize_iter_array(typename list<Tplt>::iterator* itar, int size, list<Tplt> alist);
/***************************************Main routine*******************************/
int main(void)
{
int list_size = 16;
// Make the list that will be tested.
list<Double_list_struct> list_to_play_with;
initialize_list(list_to_play_with, list_size);
list_to_play_with.sort();
cout << "Sorted list is: " << endl;
output_list(list_to_play_with);
// Make an array of list<Double_list_struct>::iterator of size floor(sqrt(N))
int iter_array_size = floor(sqrt(list_size));
list<Double_list_struct>::iterator* iter_array;
iter_array = new list<Double_list_struct>::iterator[iter_array_size];
// Initialize the iterators in iter_array to point to roughly evenly spaced locations in the list
initialize_iter_array(iter_array, iter_array_size, list_to_play_with);
for (int i = 0; i < iter_array_size; i++)
{
cout << "In main routine, iter_array[" << i << "]:" << (*(iter_array[i])).toString() << endl;
}
cout << "Reset it, and redo the output loop??" << endl;
iter_array[iter_array_size-1] = list_to_play_with.end();
iter_array[iter_array_size-1]--;
for (int i = 0; i < iter_array_size; i++)
{
cout << "In main routine, iter_array[" << i << "]:" << (*(iter_array[i])).toString() << endl;
}
}
/************************************************Subroutine code**************************************/
// Output all elements of a list to cout.
template <typename Tplt>
void output_list(list<Tplt> to_out)
{
...not important here
}
template <typename Tplt>
void initialize_list(list<Tplt> &alist, int size)
{
...not important here
}
template <typename Tplt>
void initialize_iter_array(typename list<Tplt>::iterator* itar, int size, list<Tplt> alist)
{
itar[0] = alist.begin();
itar[size-1] = alist.end();
itar[size-1]--; // Recall that .end() makes an iterator point *past* the end...
// Find out how big the list is
int listsize = 0;
for (typename list<Tplt>::iterator it = itar[0]; it != itar[size-1]; it++)
{
listsize = listsize + 1;
}
int spacing = floor(listsize/(size-1));
cout << "In initialize_iter_array(): created itar[0]: " << (*itar[0]).toString() << endl;
for (int i = 1; i < size-1 ; i++)
{
itar[i] = itar[i-1];
for (int j = 0; j < spacing; j++)
{
itar[i]++;
}
cout << "In initialize_iter_array(): created itar[" << i << "]: " << (*itar[i]).toString() << endl;
}
cout << "In initialize_iter_array(): created itar[" << size-1 << "]: " << (*itar[size-1]).toString() << endl;
}
This generates output
Sorted list is:
struct[15] = 0.135837
struct[1] = 0.200995
struct[12] = 0.217693
...SNIP...
struct[8] = 0.863816
struct[14] = 0.887851
struct[2] = 0.893622
struct[10] = 0.925875
In initialize_iter_array(): created itar[0]: struct[15] = 0.135837
In initialize_iter_array(): created itar[1]: struct[5] = 0.314127
In initialize_iter_array(): created itar[2]: struct[11] = 0.704419
In initialize_iter_array(): created itar[3]: struct[10] = 0.925875
In main routine, iter_array[0]:struct[15] = 0.135837
In main routine, iter_array[1]:struct[5] = 0.314127
In main routine, iter_array[2]:struct[11] = 0.704419
In main routine, iter_array[3]:struct[-1] = 6.21551e-71
Reset it, and redo the output loop??
In main routine, iter_array[0]:struct[15] = 0.135837
In main routine, iter_array[1]:struct[5] = 0.314127
In main routine, iter_array[2]:struct[11] = 0.704419
In main routine, iter_array[3]:struct[10] = 0.925875
So, you see, iter_array[3] is correct inside the initialization subroutine, but has "moved" after the subroutine exits. I then reset it from outside the subroutine, but obviously I'd like to not have to do that...
My best guess is that there is something subtle going on here with how the assignment operator works for iterators. But I'm very puzzled.
initialize_iter_array takes the list by value, which means it's putting iterators that point into the parameter copy of the list, not the original list. You probably meant to pass the list by const& instead.

Check if element found in array c++

How can I check if my array has an element I'm looking for?
In Java, I would do something like this:
Foo someObject = new Foo(someParameter);
Foo foo;
//search through Foo[] arr
for(int i = 0; i < arr.length; i++){
if arr[i].equals(someObject)
foo = arr[i];
}
if (foo == null)
System.out.println("Not found!");
else
System.out.println("Found!");
But in C++ I don't think I'm allowed to search if an Object is null so what would be the C++ solution?
In C++ you would use std::find, and check if the resultant pointer points to the end of the range, like this:
Foo array[10];
... // Init the array here
Foo *foo = std::find(std::begin(array), std::end(array), someObject);
// When the element is not found, std::find returns the end of the range
if (foo != std::end(array)) {
cerr << "Found at position " << std::distance(array, foo) << endl;
} else {
cerr << "Not found" << endl;
}
You would just do the same thing, looping through the array to search for the term you want. Of course if it's a sorted array this would be much faster, so something similar to prehaps:
for(int i = 0; i < arraySize; i++){
if(array[i] == itemToFind){
break;
}
}
There are many ways...one is to use the std::find() algorithm, e.g.
#include <algorithm>
int myArray[] = { 3, 2, 1, 0, 1, 2, 3 };
size_t myArraySize = sizeof(myArray) / sizeof(int);
int *end = myArray + myArraySize;
// find the value 0:
int *result = std::find(myArray, end, 0);
if (result != end) {
// found value at "result" pointer location...
}
Here is a simple generic C++11 function contains which works for both arrays and containers:
using namespace std;
template<class C, typename T>
bool contains(C&& c, T e) { return find(begin(c), end(c), e) != end(c); };
Simple usage contains(arr, el) is somewhat similar to in keyword semantics in Python.
Here is a complete demo:
#include <algorithm>
#include <array>
#include <string>
#include <vector>
#include <iostream>
template<typename C, typename T>
bool contains(C&& c, T e) {
return std::find(std::begin(c), std::end(c), e) != std::end(c);
};
template<typename C, typename T>
void check(C&& c, T e) {
std::cout << e << (contains(c,e) ? "" : " not") << " found\n";
}
int main() {
int a[] = { 10, 15, 20 };
std::array<int, 3> b { 10, 10, 10 };
std::vector<int> v { 10, 20, 30 };
std::string s { "Hello, Stack Overflow" };
check(a, 10);
check(b, 15);
check(v, 20);
check(s, 'Z');
return 0;
}
Output:
10 found
15 not found
20 found
Z not found
One wants this to be done tersely.
Nothing makes code more unreadable then spending 10 lines to achieve something elementary.
In C++ (and other languages) we have all and any which help us to achieve terseness in this case. I want to check whether a function parameter is valid, meaning equal to one of a number of values.
Naively and wrongly, I would first write
if (!any_of({ DNS_TYPE_A, DNS_TYPE_MX }, wtype) return false;
a second attempt could be
if (!any_of({ DNS_TYPE_A, DNS_TYPE_MX }, [&wtype](const int elem) { return elem == wtype; })) return false;
Less incorrect, but looses some terseness.
However, this is still not correct because C++ insists in this case (and many others) that I specify both start and end iterators and cannot use the whole container as a default for both. So, in the end:
const vector validvalues{ DNS_TYPE_A, DNS_TYPE_MX };
if (!any_of(validvalues.cbegin(), validvalues.cend(), [&wtype](const int elem) { return elem == wtype; })) return false;
which sort of defeats the terseness, but I don't know a better alternative...
Thank you for not pointing out that in the case of 2 values I could just have just if ( || ). The best approach here (if possible) is to use a case structure with a default where not only the values are checked, but also the appropriate actions are done.
The default case can be used for signalling an invalid value.
You can use old C-style programming to do the job. This will require little knowledge about C++. Good for beginners.
For modern C++ language you usually accomplish this through lambda, function objects, ... or algorithm: find, find_if, any_of, for_each, or the new for (auto& v : container) { } syntax. find class algorithm takes more lines of code. You may also write you own template find function for your particular need.
Here is my sample code
#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
using namespace std;
/**
* This is old C-like style. It is mostly gong from
* modern C++ programming. You can still use this
* since you need to know very little about C++.
* #param storeSize you have to know the size of store
* How many elements are in the array.
* #return the index of the element in the array,
* if not found return -1
*/
int in_array(const int store[], const int storeSize, const int query) {
for (size_t i=0; i<storeSize; ++i) {
if (store[i] == query) {
return i;
}
}
return -1;
}
void testfind() {
int iarr[] = { 3, 6, 8, 33, 77, 63, 7, 11 };
// for beginners, it is good to practice a looping method
int query = 7;
if (in_array(iarr, 8, query) != -1) {
cout << query << " is in the array\n";
}
// using vector or list, ... any container in C++
vector<int> vecint{ 3, 6, 8, 33, 77, 63, 7, 11 };
auto it=find(vecint.begin(), vecint.end(), query);
cout << "using find()\n";
if (it != vecint.end()) {
cout << "found " << query << " in the container\n";
}
else {
cout << "your query: " << query << " is not inside the container\n";
}
using namespace std::placeholders;
// here the query variable is bound to the `equal_to` function
// object (defined in std)
cout << "using any_of\n";
if (any_of(vecint.begin(), vecint.end(), bind(equal_to<int>(), _1, query))) {
cout << "found " << query << " in the container\n";
}
else {
cout << "your query: " << query << " is not inside the container\n";
}
// using lambda, here I am capturing the query variable
// into the lambda function
cout << "using any_of with lambda:\n";
if (any_of(vecint.begin(), vecint.end(),
[query](int val)->bool{ return val==query; })) {
cout << "found " << query << " in the container\n";
}
else {
cout << "your query: " << query << " is not inside the container\n";
}
}
int main(int argc, char* argv[]) {
testfind();
return 0;
}
Say this file is named 'testalgorithm.cpp'
you need to compile it with
g++ -std=c++11 -o testalgorithm testalgorithm.cpp
Hope this will help. Please update or add if I have made any mistake.
If you were originally looking for the answer to this question (int value in sorted (Ascending) int array), then you can use the following code that performs a binary search (fastest result):
static inline bool exists(int ints[], int size, int k) // array, array's size, searched value
{
if (size <= 0) // check that array size is not null or negative
return false;
// sort(ints, ints + size); // uncomment this line if array wasn't previously sorted
return (std::binary_search(ints, ints + size, k));
}
edit: Also works for unsorted int array if uncommenting sort.
You can do it in a beginners style by using control statements and loops..
#include <iostream>
using namespace std;
int main(){
int arr[] = {10,20,30,40,50}, toFind= 10, notFound = -1;
for(int i = 0; i<=sizeof(arr); i++){
if(arr[i] == toFind){
cout<< "Element is found at " <<i <<" index" <<endl;
return 0;
}
}
cout<<notFound<<endl;
}
C++ has NULL as well, often the same as 0 (pointer to address 0x00000000).
Do you use NULL or 0 (zero) for pointers in C++?
So in C++ that null check would be:
if (!foo)
cout << "not found";

getting mergesort to work on linked-list?

Apologies if this is a silly / simple question.. but I'm very lost. I'm having trouble getting this program to run. I've written this program to read in 2 values, the first being a number of elements in a linked list, and the second to be the maximum random value that can be put into each element.
It should then use the merge sort algorithm included to sort and reprint the sorted list.
Ok, so I'm getting errors like:
base operand of `->' has non-pointer type `LIST'
and
request for member `element' in `conductor', which is of non-aggregate type `LIST *'
...(and a few others).
Yes this is for a class.. I've written the program but I'm not sure what I've done wrong here or why I'm getting errors? Any help is appreciated! Thank you
#include <cstdlib>
#include <iostream>
#include <math.h>
#include <sys/time.h>
using namespace std;
typedef struct LIST {
int element;
LIST *next;
};
LIST split(LIST list)
{
LIST pSecondCell;
if (list == NULL)
return NULL;
else if (list.next == NULL)
return NULL;
else {
pSecondCell = list.next;
list.next = pSecondCell.next;
pSecondCell.next = split(pSecondCell->next);
return pSecondCell;
}
}
LIST merge(LIST list1, LIST list2)
{
if (list1 == NULL)
return list2;
else if (list2 == NULL)
return list1;
else if (list1.element <= list2.element) {
list1.next = merge(list1.next, list2);
return list1;
} else {
list2.next = merge(list1, list2.next);
}
}
LIST MergeSort(LIST list)
{
LIST SecondList;
if (list == NULL)
return NULL;
else if (list.next == NULL)
return list;
else {
SecondList = split(list);
return merge(MergeSort(list), MergeSort(SecondList));
}
}
int main(int argCount, char *argVal[])
{
int i, number, max;
struct timeval time1;
struct timeval time2;
//check for correct number of arguments
if (argCount != 3) {
cout << "Incorrect number of arguments" << endl;
return 0;
}
// initialize read in n and max values
number = atoi(argVal[1]);
max = atoi(argVal[2]);
// create list and fill with random numbers
LIST *conductor;
LIST *root = new LIST;
conductor = root;
for (i = 0; i < number; i++) {
conductor.element = rand() % max;
conductor.next = new LIST;
conductor = conductor.next;
}
// time how long it takes to sort array using mergeSort
gettimeofday(&time1, NULL);
mergeSort(root);
gettimeofday(&time2, NULL);
// print name, sorted array, and running time
cout << "Heather Wilson" << endl;
conductor = root;
for (i = 0; i < number - 2; i++) {
cout << conductor.element << ", ";
conductor = conductor.next;
}
double micro1 = time1.tv_sec * 1000000 + time1.tv_usec;
double micro2 = time2.tv_sec * 1000000 + time2.tv_usec;
cout << conductor.element << endl;
cout << "Running time: " << micro2 - micro1 << " microseconds" << endl;
return 0;
}
For base operand of->' has non-pointer type LIST'
Replace the -> with a .. You want to access a member of a local LIST, not a member of a pointed at object.
request for memberelement' in conductor', which is of non-aggregate type LIST *
This is the opposite. Replace the . with a ->. You want to access a member of the pointed at LIST, not a member of the pointer.
For clarification, I didn't read the code. There's too much of it. But those are the usual ways to address those specific errors. parapura seems to have actually read the code.
First: you should never have let the code grow this big with so many errors. You should start small and simple, then build up, testing at every stage, and never add to code that doesn't work.
Here's a stripped-down beginning of your code, with some bugs fixed:
#include <iostream>
using namespace std;
typedef struct LIST{
int element;
LIST *next;
};
int main(){
int i, number, max;
number = 5;
max = 100;
// create list and fill with random numbers
LIST *conductor;
LIST *root = new LIST;
conductor = root;
for(i=0; i<number; i++){
conductor->element = rand() % max;
cout << "element " << i << " is " << conductor->element << endl;
conductor->next = new LIST;
conductor = conductor->next;
}
conductor = root; // Forgot this, didn't you!
for(i=0; i<number-2;i++){
cout << conductor->element << ", ";
conductor = conductor->next;
}
return 0;
}
Take a look at this, verify that it works, make sure you understand the changes I made, then you can take a crack at implementing your split, merge and MergeSort functions and the I/O (one at a time, and testing at every stage, naturally).
I think all the places you are passing
LIST merge ( LIST list1 , LIST list2 )
it should be
LIST* merge ( LIST* list1 , LIST* list2 )