Calculating Prime Numbers using Sets, C++ - c++

I am trying to calculate the prime numbers using a set but when I do the calculation my iterator is jumping randomly.
I am trying to implement this method for an value of N=10.
Choose an integer n. This function will compute all prime numbers up
to n. First insert all numbers from 1 to n into a set. Then erase all
multiples of 2 (except 2); that is, 4, 6, 8, 10, 12, .... Erase all
multiples of 3, that is, 6, 9, 12, 15, ... . Go up to sqrt(n) . The
remaining numbers are all primes.
When I run my code, it erases 1 and then pos jumps to 4? I am not sure why this happens instead of it going to the value 2 which is the 2nd value in the set?
Also what happens after I erase a value that the iterator is pointing to, what does the iterator point to then and if I advance it where does it advance?
Here is the code:
set<int> sieveofEratosthenes(int n){ //n = 10
set<int> a;
set<int>::iterator pos = a.begin();
//generate set of values 1-10
for (int i = 1; i <= n; i++) {
a.insert(i);
if(pos != a.end())
pos++;
}
pos = a.begin();
//remove prime numbers
while (pos != a.end())
{
cout << "\nNew Iteration \n\n";
for (int i = 1; i < sqrt(n); i++) {
int val = *pos%i;
cout << "Pos = " << *pos << "\n";
cout << "I = " << i << "\n";
cout << *pos << "/" << i << "=" << val << "\n\n";
if (val == 0) {
a.erase(i);
}
}
pos++;
}
return a;
}

Your implementation is incorrect in that it is trying to combine the sieve algorithm with the straightforward algorithm of trying out divisors, and it does so unsuccessfully. You do not need to test divisibility to implement the sieve - in fact, that's a major contributor to the beauty of the algorithm! You do not even need multiplication.
a.erase(1);
pos = a.begin();
while (pos != a.end()) {
int current = *pos++;
// "remove" is the number to remove.
// Start it at twice the current number
int remove = current + current;
while (remove <= n) {
a.erase(remove);
// Add the current number to get the next item to remove
remove += current;
}
}
Demo.

When erasing elements inside a loop you have to be carefull with the indices. For example, when you erase the element at position 0, then the next element is now at position 0. Thus the loop should look something like this:
for (int i = 1; i < sqrt(n); /*no increment*/) {
/* ... */
if (val == 0) {
a.erase(i);
} else {
i++;
}
}
Actually, you also have to take care that the size of the set is shrinking while you erase elements. Thus you better use iterators:
for (auto it = a.begin(); i != a.end(); /*no increment*/) {
/* ... */
if (val == 0) {
a.erase(it);
} else {
it++;
}
}
PS: the above is not exactly what you need for the sieve, but it should be sufficient to demonstrate how to erase elements (I hope so).

Related

Arranging odd and even numbers in a vector C++

I have this problem: Given a vector with n numbers, sort the numbers so that the even ones will be on odd positions and the odd numbers will be on even positions. E.g. If I have the vector 2 6 7 8 9 3 5 1, the output should be 2 7 6 9 8 3 5 1 . The count should start from 1. So on position 1 which is actually index 0 should be an even number, on position 2 which is actually index 1 should be an odd number and so on. Now this is easy if the odd and even numbers are the same, let's say 4 even number and 4 odd numbers in the vector, but what if the number of odd numbers differs from the number of even numbers like in the above example? How do I solve that. I attached the code with one of the tries I did, but it doesn't work. Can I get some help please. I ask you to keep it simple that means only with vectors and such. No weird methods or anything cause I'm a beginner and I only know the basics. Thanks in advance!
I have to mention that n initial is globally declared and is the number of vector elements and v_initial is the initial vector with the elements that need to be rearranged.
The task says to add the remaining numbers to the end of the vector. Like if there are 3 odd and 5 even numbers, The 2 extra even numbers should be thrown at the end of the vector
void vector_pozitii_pare_impare(int v_initial[])
{
int v_pozitie[50],c1=0,c2=1;
for (i = 0; i < n_initial; i++)
{
if (v_initial[i] % 2 == 0)
{
bool isTrue = 1;
for (int k = i + 1; k < n_initial; k++)
{
if (v_initial[k] % 2 != 0)
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c1] = v_initial[i];
c1++;
}
else
{
v_pozitie[c1] = v_initial[i];
c1 += 2;
}
}
else
{
bool isTrue = 1;
for (int j = i + 1; j < n_initial; j++)
{
if (v_initial[j] % 2 == 0)
{
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c2] = v_initial[i];
c2++;
}
else
{
v_pozitie[c2] = v_initial[i];
c2 += 2;
}
}
}
}
This may not be a perfect solution and it just popped out right off my mind without being tested or verified, but it's just to give you an idea.
(Let A,B,C,D be odd numbers and 0,1,2 even numbers correspondingly)
Given:
A 0 B C D 1 2 (random ordered list of odd/even numbers)
Wanted:
A 0 B 1 C 2 D (input sequence altered to match the wanted odd/even criteria)
Next, we invent the steps required to get from given to wanted:
// look at 'A' -> match, next
// Result: A 0 B C D 1 2
// look at '0' -> match, next
// Result: A 0 B C D 1 2
// look at 'B' -> match, next
// Result: A 0 B C D 1 2
// look at 'C' -> mismatch, remember index and find first match starting from index+1
// Result: A 0 B C D ->1<- 2
// now swap the numbers found at the remembered index and the found one.
// Result: A 0 B 1 D C 2
// continue until the whole list has been consumed.
As I said, this algorithm may not be perfect, but my intention is to give you an example on how to solve these kinds of problems. It's not good to always think in code first, especially not with a problem like this. So you should first think about where you start, what you want to achieve and then carefully think of how to get there step by step.
I feel I have to mention that I did not provide an example in real code, because once you got the idea, the execution should be pretty much straight forward.
Oh, and just a small remark: Almost nothing about your code is C++.
A simple solution, that is not very efficient would be to split the vector into 2 vectors, that contain even and uneven numbers and then always take one from the even, one from the uneven and then the remainder, from the one that is not completely entered.
some c++ (that actually uses vectors, but you can use an array the same way, but need to change the pointer arithmetic)
I did not test it, but the principle should be clear; it is not very efficient though
EDIT: The answer below by #AAAAAAAAARGH outlines a better algorithmic idea, that is inplace and more efficient.
void change_vector_even_uneven(std::vector<unsigned>& in_vec){
std::vector<unsigned> even;
std::vector<unsigned> uneven;
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if ((*it) % 2 == 0)) even.push_back(*it);
else uneven.push_back(*it);
}
auto even_it = even.begin();
auto uneven_it = uneven.begin();
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if (even_it == even.end()){
(*it) = (*uneven_it);
uneven_it++;
continue;
}
if (uneven_it == uneven.end()){
(*it) = (*even_it);
even_it++;
continue;
}
if ((it - in_vec.begin()) % 2 == 0){
(*it) = (*even_it);
even_it++;
}
else{
(*it) = (*uneven_it);
uneven_it++;
}
}
}
The solutions is simple. We sort the even and odd values into a data structure. In a loop, we iterate over all source values. If they are even (val & 2 == 0) we add them at the end of a std::deque for evens and if odd, we add them to a std::deque for odds.
Later, we we will extract the the values from the front of the std::deque.
So, we have a first in first out principle.
The std::deque is optimized for such purposes.
Later, we make a loop with an alternating branch in it. We, alternatively extract data from the even queue and then from the odd queue. If a queue is empty, we do not extract data.
We do not need an additional std::vector and can reuse the old one.
With that, we do not need to take care for the same number of evens and odds. It will of course always work.
Please see below one of millions of possible solutions:
#include <iostream>
#include <vector>
#include <deque>
int main() {
std::vector testData{ 2, 6, 7, 8, 9, 3, 5, 1 };
// Show initial data
std::cout << "\nInitial data: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
// We will use a deques to store odd and even numbers
// With that we can efficiently push back and pop front
std::deque<int> evenNumbers{};
std::deque<int> oddNumbers{};
// Sort the original data into the specific container
for (const int number : testData)
if (number % 2 == 0)
evenNumbers.push_back(number);
else
oddNumbers.push_back(number);
// Take alternating the data from the even and the odd values
bool takeEven{ true };
for (size_t i{}; !evenNumbers.empty() && !oddNumbers.empty(); ) {
if (takeEven) { // Take even numbers
if (not evenNumbers.empty()) { // As long as there are even values
testData[i] = evenNumbers.front(); // Get the value from the front
evenNumbers.pop_front(); // Remove first value
++i;
}
}
else { // Now we take odd numbers
if (not oddNumbers.empty()) { // As long as there are odd values
testData[i] = oddNumbers.front(); // Get the value from the front
oddNumbers.pop_front(); // Remove first value
++i;
}
}
// Next take the other container
takeEven = not takeEven;
}
// Show result
std::cout << "\nResult: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
return 0;
}
Here is yet another solution (using STL), in case you want a stable result (that is, the order of your values is preserved).
#include <algorithm>
#include <vector>
auto ints = std::vector<int>{ 2, 6, 7, 8, 9, 3, 5, 1 };
// split list to even/odd sections -> [2, 6, 8, 7, 9, 3, 5, 1]
const auto it = std::stable_partition(
ints.begin(), ints.end(), [](auto value) { return value % 2 == 0; });
auto results = std::vector<int>{};
results.reserve(ints.size());
// merge both parts with equal size
auto a = ints.begin(), b = it;
while (a != it && b != ints.end()) {
results.push_back(*a++);
results.push_back(*b++);
}
// copy remaining values to end of list
std::copy(a, it, std::back_inserter(results));
std::copy(b, ints.end(), std::back_inserter(results));
The result ist [2, 7, 6, 9, 8, 3, 5, 1]. The complexity is O(n).
This answer, like some of the others, divides the data and then reassembles the result. The standard library std::partition_copy is used to separate the even and odd numbers into two containers. Then the interleave function assembles the result by alternately copying from two input ranges.
#include <algorithm>
#include <iostream>
#include <vector>
template <typename InIt1, typename InIt2, typename OutIt>
OutIt interleave(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest)
{
for (;;) {
if (first1 == last1) {
return std::copy(first2, last2, dest);
}
*dest++ = *first1++;
if (first2 == last2) {
return std::copy(first1, last1, dest);
}
*dest++ = *first2++;
}
}
void reorder_even_odd(std::vector<int> &data)
{
auto is_even = [](int value) { return (value & 1) == 0; };
// split
std::vector<int> even, odd;
std::partition_copy(begin(data), end(data), back_inserter(even), back_inserter(odd), is_even);
// merge
interleave(begin(even), end(even), begin(odd), end(odd), begin(data));
}
int main()
{
std::vector<int> data{ 2, 6, 7, 8, 9, 3, 5, 1 };
reorder_even_odd(data);
for (int value : data) {
std::cout << value << ' ';
}
std::cout << '\n';
}
Demo on Compiler Explorer
As suggested, I am using vectors and STL.
No need to be a great mathematician to understand v_pozitie will start with pairs of odd and even and terminate with the integers not in the initial pairs.
I am then updating three iterators in v_positie (no need of temporary containers to calculate the result) : even, odd and end,(avoiding push_back) and would code this way :
#include <vector>
#include <algorithm>
void vector_pozitii_pare_impare(std::vector<int>& v_initial, std::vector<int>& v_pozitie) {
int nodd (0), neven (0);
std::for_each (v_initial.begin (), v_initial.end (), [&nodd] (const int& n) {
nodd += n%2;
});
neven = v_initial.size () - nodd;
int npair (neven < nodd ?neven:nodd);
npair *=2;
std::vector<int>::iterator iend (&v_pozitie [npair]), ieven (v_pozitie.begin ()), iodd (&v_pozitie [1]);
std::for_each (v_initial.begin (), v_initial.end (), [&iend, &ieven, &iodd, &npair] (const int& s) {
if (npair) {
switch (s%2) {
case 0 :
*ieven++ = s;
++ieven;
break;
case 1 :
*iodd++ = s;
++iodd;
break;
}
--npair;
}
else *iend++ = s;
});
}
int main (int argc, char* argv []) {
const int N = 8;
int tab [N] = {2, 6, 7, 8, 9, 3, 5, 1};
std::vector<int> v_initial (tab, (int*)&tab [N]);
std::cout << "\tv_initial == ";
std::for_each (v_initial.begin (), v_initial.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
std::vector<int> v_pozitie (v_initial.size (), -1);
vector_pozitii_pare_impare (v_initial, v_pozitie);
std::cout << "\tv_pozitie == ";
std::for_each (v_pozitie.begin (), v_pozitie.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
}

Taking pairs of numbers representing begin/end, and removing overlaps

I have an array of pairs that represent a range of [begin,end). The array can be assumed to already sorted by the 'begin' field.
I want to generate a new array with all of the overlaps removed, and additional pairs created, as needed.
For example, let's say the array contained the following pairs:
[1,3],[2,5],[7,15],[8,9],[12,19]
The output should be as follows:
[1,2],[2,3],[3,5],[7,8],[8,9],[9,12],[12,15],[15,19]
Ultimately, the output array should contain no overlaps at all.
What's the most optimal solution that takes no more than O(m), where m is the number of entries needed in the output array? I think I see a way to do it in O(n^2), where n is the number of entries in the input array, but there's got to be a better way.
The final implementation will be in C++11, using vectors of pairs of doubles, although pseudocode solutions are fine.
EDIT:
I appreciate all responses, but I would politely request in advance to please not post any solutions that depend on particular frameworks or libraries unless such frameworks are part of standard c++11.
First I'll solve a related problem; generate merged intervals that cover the same area with no adjacency or overlap.
Walk the input array. Start with the first element. Record highwater (end of interval) and lowater (start of interval).
Proceed forward. Each element, if it overlaps the interval, extend highwater. If not, output highwater and lowater as an interval, then record a new high and lowater.
This takes O(n) time on input.
Every element of input must be read, because any of them could go from their start location to the end and change the result. So this is O-optimal.
This merges intervals into the largest contiguous one you can make; you want to save all of the "edges" or "seams" in the original intervals. To solve your spec, simply keep track of seams (in order) and break the generated intervals at those seams. "Lowater" seams will always come with increasing values; highwater seams may not. So an ordered set of seams should work. This is O(nlgn) sadly due to the set.
// half open
struct interval {
int lowater = 0;
int highwater = 0;
bool empty() const {
return lowater == highwater;
}
friend std::ostream& operator<<( std::ostream& os, interval i ) {
return os << "[" << i.lowater << "," << i.highwater << "]";
}
};
template<class Range, class Out>
void build_intervals( Range&& in, Out out ) {
std::optional<interval> current;
std::set<int> seams;
auto dump_interval = [&](interval i){
if (i.empty()) return;
*out = i;
};
auto dump_current = [&]{
if (!current) return;
// std::cout << "Dumping " << *current << " with seams: {";
for (int seam:seams) {
// std::cout << seam << ",";
dump_interval({ current->lowater, seam });
current->lowater = seam;
}
// std::cout << "}\n";
dump_interval( *current );
current = std::nullopt;
seams.clear();
};
for (auto&& e : in) {
if (current && e.lowater <= current->highwater) {
seams.insert(e.lowater);
seams.insert(e.highwater);
// std::cout << "No gap between " << *current << " and " << e << "\n";
current->highwater = (std::max)(e.highwater, current->highwater);
// std::cout << "Combined: " << *current << "\n";
continue;
}
if (!current) {
// std::cout << "New current " << e << "\n";
} else {
// std::cout << "Gap between " << *current << " and " << e << "\n";
dump_current();
}
current = e;
seams.insert(e.lowater);
seams.insert(e.highwater);
}
dump_current();
}
live example.
I came up with something like this, by adding just couple of if it is done in O(n) time. I'm just not sure about last elements, my output:
[1 : 2], [2 : 3], [3 : 5], [7 : 8], [8 : 9], [9 : 12], [12 : 15], [15 : 19]
Maybe its something that would help:
std::vector<std::pair<int, int>> noOverlaps(std::vector<std::pair<int, int>>& input) {
if (input.size() <= 1) {
return input;
}
std::vector<std::pair<int, int>> result;
result.push_back(input[0]);
for (int i = 1; i < input.size(); ++i) {
//If overlap
if (input[i].first < result.back().second) {
auto lastOne = result.back();
result.pop_back();
result.push_back(std::make_pair(lastOne.first, input[i].first));
if (lastOne.second > input[i].second) {
result.push_back(std::make_pair(input[i].first, input[i].second));
result.push_back(std::make_pair(input[i].second, lastOne.second));
} else {
result.push_back(std::make_pair(input[i].first, lastOne.second));
result.push_back(std::make_pair(lastOne.second, input[i].second));
}
} else {
result.push_back(input[i]);
}
}
return result;
}
Update 1
As pointed out in the comment above will not work with multiple overlapping intervals, so the above solution can be improved by swallowing intervals that are containing each other and run the same algorithm:
std::vector<std::pair<int, int>> noOverlaps(std::vector<std::pair<int, int>>& origInput) {
if (origInput.size() <= 1) {
return origInput;
}
std::vector<std::pair<int, int>> result;
std::vector<std::pair<int, int>> input;
input.push_back(origInput[0]);
for (int i = 1; i < origInput.size(); ++i) {
if (input[i-1].first <= origInput[i].first && input[i-1].second >= origInput[i].second) {
continue;
}
input.push_back(origInput[i]);
}
result.push_back(input[0]);
for (int i = 1; i < input.size(); ++i) {
//If overlap
if (input[i].first < result.back().second) {
auto lastOne = result.back();
result.pop_back();
result.push_back(std::make_pair(lastOne.first, input[i].first));
if (lastOne.second > input[i].second) {
result.push_back(std::make_pair(input[i].first, input[i].second));
result.push_back(std::make_pair(input[i].second, lastOne.second));
} else {
result.push_back(std::make_pair(input[i].first, lastOne.second));
result.push_back(std::make_pair(lastOne.second, input[i].second));
}
} else {
result.push_back(input[i]);
}
}
return result;
}
But this requires 2xO(n) space complexity and code is not nice.
So I just wonder would that not be enough:
std::vector<std::pair<int, int>> noOverlaps2(std::vector<std::pair<int, int>>& origInput) {
if (origInput.size() <= 1) {
return origInput;
}
int low = origInput[0].first, high = origInput[0].second;
std::vector<std::pair<int, int>> result;
for (int i = 1; i < origInput.size(); ++i) {
if (high < origInput[i].first) {
result.emplace_back(low, high);
low = origInput[i].first;
high = origInput[i].second;
} else {
high = std::max(origInput[i].second, high);
}
}
result.emplace_back(low, high);
return result;
}
For your data it gives output:[1 : 5], [7 : 19] but it get rid of overlaps.

Recursive function that returns a sum of all elements in a vector

I am confused on how to get this function to add the last element in the vector. I cannot modify the functions parameters.
long vectorSum(const std::vector<int>& data, unsigned int position)
{
if (position == data.size()-1)
{
return 0;
}
else
{
return (vectorSum(data, position+1) + data[position]);
}
}
int main()
{
//vectorSum test
std::vector<int> data = { 1,2,3,4,5};
unsigned int pos = 0;
std::cout << "expected: 15, " << "actual: " << vectorSum(data, pos) << std::endl;
}
when you stop at data.size() -1 you are returning 0 for vectorSum(data, data.size()-1) without counting the value of the last entry
long vectorSum(const std::vector<int>& data, unsigned int position)
{
if (position == data.size()) // You were stopping early
{
return 0;
}
else
{
return (vectorSum(data, position+1) + data[position]);
}
}
int main()
{
//vectorSum test
std::vector<int> data = { 1,2,3,4,5};
unsigned int pos = 0;
std::cout << "expected: 15, " << "actual: " << vectorSum(data, pos) << std::endl;
}
When you're looking at the last element, you have this condition:
if (position == data.size()-1)
At this point, position is 4, and data.size() is 5. So the condition matches and the recursion ends.
You need to change the == to >, or drop the -1
There are always two parts to a recursive function: a stop condition and a recursion. A simple stop condition here is: when there are no elements in the vector, the sum is 0. The recursion is: the sum of the elements of a non-empty vector is the value of its first element plus the sum of the remaining elements. In code, the stop condition looks like this:
if (position == data.size())
return 0;
In code, the recursion looks like this:
else
return data[position] + vectorSum(data, position + 1);
A slightly more sophisticated stop condition would be: when there is exactly one element in the vector, the sum is the value of that element. In code:
if ( position == data.size() - 1)
return data[position];
Compared to the first one, this has one fewer levels of recursion. But it doesn't work for empty vectors. So pick your poison.
The problem with the original code is that its stop condition isn't implemented correctly. It inter-mixes these two stop conditions.

C++ Primer 5th Edition exercise 3.24 - iterators in vectors

I just started learning C++ by myself using Lippman, Lajoie & Moo's C++ Primer Fifth Edition (5th printing, may 2014) in september 2014. Some exercises in that book I could do, some I had to look here for help and at this one I'm stuck for days. I searched Google, blogs and other forums and got nothing, so I ask you for help. It is the exercise 3.24 at page 113, which asks the same as the exercise 3.20 in page 105, but using iterators:
Read a set of integers into a vector. Print the sum of each pair of adjacent elements. Change your program so that it prints the sum of the first and last elements, followed by the sum of the second and second-to-last, and so on.
Using iterators as it asked, I could do the first part:
#include <iostream>
#include <vector>
using std::cin; using std::cout; using std::endl; using std::vector;
int main()
{
vector<int> lista;
int num_entra = 0;
while (cin >> num_entra)
lista.push_back(num_entra);
cout << "Sum of adjacent pairs: " << endl;
for (auto it = lista.begin(); it != lista.end() - 1; ++it)
{
*it += *(it + 1);
cout << *it << ' ';
}
return 0;
}
The code above works as intended, but the part where I need to sum the first and last, second and second to last... etc. has an issue I just can't solve:
int main()
{
vector<int> lista;
int num_entra = 0;
while (cin >> num_entra)
lista.push_back(num_entra);
auto ult = lista.end();
cout << "Sum of the first and last elements until the center: " << endl;
for (auto it = lista.begin(); it != lista.end() - 1; ++it)
{
*it = *it + *(--ult);
cout << *it << ' ';
}
return 0;
}
If the user enters 1 2 3 4 5 6, the program adds 1 + 6, 2 + 5 and 3 + 4 as it should,
but then it adds the last result (7) with 5 and then with 6 and I can't seem to find a way to stop this behavior. What can I do so the program shows only one sum for each pair until the center of the list?
Thank you in advance.
One way to do this would be to use two iterators
auto front = lista.begin(); // start at front and increment
auto back = lista.end() - 1; // start at back and decrement
for (;
back > front; // stop when the iterators cross each other
++front, --back)
{
int total = *front + *back;
std::cout << total << ' ';
}
The problem with your code is that you're modifying the vector as you compute the sums by dereferencing the iterator (might not be a problem but it's a likely unwanted side effect) and you're not even stopping the cycle when you've "surpassed" the middle of the vector.
A simple version could be
auto front = lista.begin();
auto back = lista.end() - 1;
for (; back > front; ++front, --back)
{
int total = *front + *back;
std::cout << total << ' ';
}
but this doesn't handle an odd number of elements like 1 2 3 4 5 6 7 (the central 4 isn't printed). If you don't want any "same element" couple, this is fine and this solution will handle every case you need, otherwise go ahead.
A fixed version could be
auto front = lista.begin();
auto back = lista.end() - 1;
for (; back >= front; ++front, --back)
{
if (front == back)
cout << *front;
else {
int total = *front + *back;
std::cout << total << ' ';
}
}
but this doesn't handle a null list [].
This solution handles both although it's more complex:
auto it = lista.begin();
auto ult = lista.rbegin();
size_t dist;
for ( ; it != lista.end() && // I have a valid front iterator
ult != lista.rend() && // I have a valid back iterator
(dist = std::distance(it,ult.base()), dist) > 0; // Their distance is greater than 0 (1 is included)
++it,++ult ) {
if (dist == 1)
cout << *it;
else
cout << *it + *ult << ' ';
}
In addition to incrementing one iterator while decrementing another, I think the best way is to use a reverse iterator.
auto it = list.begin();
auto rit = list.rbegin(); // a "reverse iterator"
while (it < rit.base()) {
cout << *it++ + *rit++ << ' ';
}
Using a reverse iterator means you don't have to worry about any "off-by-one" adjustments due to the asymmetry between begin and end.
Here is also one approach where mid is an iterator closest to the middle of the array, which is also commonly used in binary search implementation:
auto e = lista.end() - 1;
auto mid = lista.end() + (lista.begin() - lista.end()) / 2;
for (auto i = lista.begin(); i != mid; ++i, --e){
cout << *i << "+" << *e << " = " << (*i)+(*e) << endl;
}
Input: 1 2 3 4 5 6 7 8 9;
Positions/index: 0 1 2 3 4 5 6 7 8 9
Where mid = (0 - 10) / 2 => -5 + 10 => 5 The loop stops after reading number five.
And at index 5 is number 6. Therefore the loop stops when it hits the iterator closest to the middle:
i != mid;
/*Output*/
1+9 = 10
2+8 = 10
3+7 = 10
4+6 = 10
5+5 = 10
PS. I recommend you do checks to see if the vector is empty.
My five cents. Only instead of the explicitly initialized vector you should enter values for it as you did.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
if ( !v.empty() )
{
auto first = v.cbegin(), last = v.cend();
do
{
std::cout << *first + *--last;
} while ( first++ != last );
}
return 0;
}
The output is
666
This approach you also can use for example with std::list
If you need to skip the middle odd element then the general approach for containers that have no random access iterator is the following
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
for ( auto first = v.cbegin(), last = v.cend();
first != last && first != --last;
++first )
{
std::cout << *first + *last;
}
std::cout << std::endl;
return 0;
}
As vectors have random acces iterators then the code can be rewritten using operator <
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
if ( !v.empty() )
{
for ( auto first = v.cbegin(), last = v.cend();
first < --last;
++first )
{
std::cout << *first + *last;
}
std::cout << std::endl;
}
return 0;
}
In both cases the output will be
66

identifying duplicate values in linked list C++

I want to identify which ones and how many values are duplicate in a linked list that was user's input. And this is the code I wrote for it:
int count;
int compare, compare2;
for (p = first; p != NULL; p = p->next){
compare = p->num;
for (j = first; j != NULL; j = j->next){
if (compare == j->num){
compare2 = j->num;
count++;
}
}
if (count > 1){
cout << "There are at least 2 identical values of: " << compare2 << " that repeat for: " << count << "times" << endl;
}
}
Basically the idea of it was that I take the first element in the first loop and compare it to all the elements in the second loop and count if there are cases of them being similar, and print the result after - then I take next element and so on.
However the output is all the elements and it doesn't count correctly either. I'm just lost at how to adjust it.
I tried using the same p variable in both loops as it is the same list I want to loop, but then the .exe failed as soon as I'd finished input.
I saw a few examples around where there was function for deleting duplicate values, but the comparison part run through with while loop, and I'm just wondering - what am I doing wrong on this one?!
Your O(N*N) approach :
// Pick an element
for (p = first; p != NULL && p->next !=NULL ; p = p->next)
{ // Compare it with remaining elements
for (j = p->next ; j != NULL; j = j->next)
{
if ( p->num == j->num)
{
count++;
}
if( cout > 1 )
{
std::cout << p->num << " occurs "<< count << times << '\n' ;
}
}
Its better to use a HashMap to solve this is O(N) time with N extra space
std::unordered_map<int, int> m ;
for( p = first; p != NULL ; p = p->next )
{
m[ p->num ]++;
}
for (const auto &pair : m )
{
if( pair.second > 1 )
std::cout << pair.first << ": " << pair.second << '\n';
}
Your logic is flawed since both p and j iterate over the entire list. When p == j, the values are bound to match.
Change the block
if (compare == j->num){
compare2 = j->num;
count++;
}
to
if (p != j && compare == j->num){
compare2 = j->num;
count++;
}
Also, you don't need the line
compare2 = j->num;
since compare2 will be equal to compare.
You can reduce the number of tests by changing the inner for loop a bit. Then, you won't need the p != j bit either.
for (j = p->next; j != NULL; j = j->next){
if (compare == j->num){
count++;
}
}
The problem is that you don't exclude element you compare to (compare). So for every element it found at least one duplicate - itself!
Try to compare element in inner loop only followed by current (p).