Swap neighbouring elements in std::list - c++

I want to change places of neighbouring elements in the std::list
Example of the list and values
A B C D E F G
3 2 1 2 1 3 2
What I expect to receive after sorting:
A B D C F E G
3 2 2 1 3 1 2
So, simple A > B = nothing to do, but C < D = swap them and go to E comparison.
I have no idea about how to swap neighbor elements.
So, I want to move forward to 1 step good elements

You can easily do this by using two iterators:
void biswap(std::list<int> &l)
{
if (l.size() < 2)
return;
auto it2 = l.begin();
auto it1 = it2++;
auto e = l.end();
for (;;)
{
if (*it1 < *it2)
std::swap(*it1, *it2);
it1 = it2++;
if (it2 == e)
return;
it1 = it2++;
if (it2 == e)
return;
}
}
Live example
Note: in case you're not using C++11 and thus calling size() might present a significant overhead, you can replace it with this (and of course replace all usage of auto with explicit types):
void biswap(std::list<int> &l)
{
auto it2 = l.begin();
auto e = l.end();
if (it2 == e)
return;
auto it1 = it2++;
if (it2 == e)
return;
for (;;)
// ... the rest as before
}

You can use standard algorithm std::adjacent_find to find a pair of elements for which first < second and then swap them.
For example
#include <iostream>
#include <algorithm>
#include <list>
#include <functional>
#include <iterator>
int main()
{
std::list<int> l = { 3, 2, 1, 2, 1, 3, 2 };
for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;
auto it = std::adjacent_find( l.begin(), l.end(), std::less<int>() );
if ( it != l.end() ) std::swap( *it, *std::next( it ) );
for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;
}
The output is
3 2 1 2 1 3 2
3 2 2 1 1 3 2
Or if you want to process all such situations when first < second then you can use the following code
#include <iostream>
#include <algorithm>
#include <list>
#include <functional>
#include <iterator>
int main()
{
std::list<int> l = { 3, 2, 1, 2, 1, 3, 2 };
for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;
std::list<int>::iterator it = l.begin();
while ( ( it = std::adjacent_find( it, l.end(), std::less<int>() ) ) != l.end() )
{
std::swap( *it, *std::next( it ) );
}
for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;
}
The output is
3 2 1 2 1 3 2
3 2 2 1 3 2 1

This gives the desired result and it switches the comparison for "good" elements, exactly as you asked:
#include <list>
#include <iostream>
using namespace std;
template<typename Type>
void print(const list<Type> & l)
{
for (auto element : l) cout << element << " ";
cout << endl;
}
int main(int argc, const char *argv[])
{
list<int> l = {3,2,1,2,1,3,2};
print(l);
auto it = l.begin();
while(std::next(it) != l.end())
{
if (*it < *std::next(it))
{
std::swap(*it, *std::next(it));
++it;
}
++it;
}
print(l);
return 0;
}
Executing results with:
3 2 1 2 1 3 2
3 2 2 1 3 1 2

In case you don't have C++11 support, simple C++03 solution using 2 iterators could be:
#include <iostream>
#include <algorithm>
#include <list>
void swapNeighbours(std::list<int>& l) {
std::list<int>::iterator it = l.begin();
std::list<int>::iterator prev = it++;
while (prev != l.end() && it != l.end()) {
// swap if needed:
if (*prev < *it)
std::swap(*prev, *it);
// move 2 times forward:
if (++it == l.end())
break;
prev = it++;
}
}
Then (based on your example) if you do:
void print(const std::list<int>& l) {
std::list<int>::const_iterator i;
for (i = l.begin(); i != l.end(); ++i) {
std::cout << *i << ' ';
}
std::cout << std::endl;
}
int main() {
std::list<int> l;
l.push_back(3); l.push_back(2); l.push_back(1); l.push_back(2);
l.push_back(1); l.push_back(3); l.push_back(2);
print(l);
swapNeighbours(l);
print(l);
}
then for the:
A B C D E F G
3 2 1 2 1 3 2
there will be following comparisons: A < B? (no) C < D? (yes, swaps) E < F? (yes, swaps too) yielding the output:
3 2 2 1 3 1 2

If all you want to do is a pairwise traversal and swap elements if the first one is less than the second then you can e.g. use std::adjacent_find like this:
using std::swap;
for (auto it = std::begin(l); it != std::end(l); it = std::adjacent_find(it, std::end(l), std::less<int>{})) {
swap(*it, *std::next(it));
}
This will cause the list of numbers 3 2 1 2 1 3 2 to be arranged as:
3 2 2 1 3 2 1
But, this is not the same as your expected result 3 2 2 1 3 1 2 and I don't undestand why you do not want to swap the last pair 1 2 like the others?
If what you want is an erratic pattern for sorting then there can be no simple solution. Instead you must use special handling of individual elements.

Related

The conditional operator is not allowing the program to terminate

I just learnt about conditional operators and was doing an introductory exercise stating:
Write a program to use a conditional operator to find the elements in
a vector<int> that have odd value and double the value of each such
element.
Here is the code that I wrote:
int main()
{
vector<int> nums = { 1,2,3,4,5,6,7,8,9 };
int i;
auto beg = nums.begin();
while (*beg > 0) // This will always evaluate to true.
{
((*beg) % 2 == 0 && (beg < nums.end()) ? i = 0 : *beg = 2 * (*(beg++)));
/*If the number is even the program will just assign 0 to i*/
}
}
The program terminates AND gives you the correct output if you change the last line to:
((*beg)%2 == 0 && (beg < nums.end()) ? i = 0 : *beg = 2*(*(beg)));
++beg;
Why is this happening?
It stuck because, if the condition ((*beg)%2 == 0 && (beg < nums.end()) is true, the iterator will not increment for checking further. You have only setting i=0. You should increment the iterator as well.
You can use comma operator for this:
while (beg != nums.end() && *beg > 0)
{
(*beg) % 2 == 0 ? (beg++, i): (*beg = 2 * (*beg) , beg++, ++i );
}
Also note that the count i should be initialized before-hand, not in the while loop.
The complete working code as per the requirement would be:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> nums = { 1,2,3,4,5,6,7,8,9 };
int i{0};
auto beg = nums.begin();
while (beg != nums.end() && *beg > 0)
{
(*beg) % 2 == 0 ? (beg++, i): (*beg = 2 * (*beg) , beg++, ++i );
}
for (const int ele : nums)
std::cout << ele << " ";
std::cout << "\ncount: " << i << "\n";
}
Output:
2 2 6 4 10 6 14 8 18
count: 5
That being said, IMO using comma operator along with conditional operator like the above(the task) is not a good coding manner, which will only make confusions for the future readers of your codebase.
Also read: Why is "using namespace std;" considered bad practice?
If you want to double some values and not others, just do it:
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int& num : nums)
num = num % 2 ? 2 * num : num;
for (int num : nums)
std::cout << num << ' ';
std::cout << '\n';
return 0;
}
A conditional expression is an expression; you use it to compute a value. The code in the question does not do that; it uses the conditional expression as a way of selecting side effects, which is better done with an ordinary if statement.

Combinations in a range of numbers in C++

I would like to build a C++ program that show all the possible combinations depending on the number of elements taken by a N factor.
Let's suppose a vector vec[6] with elements 1 2 3 4 5 6 on it.
Using the combination formula, 6! / 4! (6 - 4)! = 15 possibilities
I want to generate a function which gives the result of all 15 possibilities taken 4 by 4 with no repetition, as example:
1 2 3 4
1 2 3 5
1 2 3 6
2 3 4 5
and so on...
I am using this code for now, but i want to use numbers from my vector (v[6]).
#include <algorithm>
#include <iostream>
#include <string>
void comb(int N, int K)
{
std::string bitmask(K, 1); // K leading 1's
bitmask.resize(N, 0); // N-K trailing 0's
// print integers and permute bitmask
do {
for (int i = 0; i < N; ++i) // [0..N-1] integers
{
if (bitmask[i]) std::cout << " " << i;
}
std::cout << std::endl;
} while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}
int main()
{
comb(6, 4);
}
Would you please guys give me a help? I'd like to know where i could change the code so that i can use my own vector.
i'm generating this vector v[i] and sorting it with a bubble sort, like this:
void order (int d[], int n){
int i, j;
for (i = 1; i < n; i++)
for (j = 0; j < n-1; j++)
if (d[j] > d[j+1])
swap (d[j],d[j+1]);
for (i = 0; i < n; i++)
cout << d[i] << " ";
}
after that sorting, i want to put my vector into the comb function.
how could i make it is possible?
Here's a C++14 solution that uses a free, open source library to do the work:
#include "combinations"
#include <iomanip>
#include <iostream>
#include <vector>
int
main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6};
int state = 0;
for_each_combination(v.begin(), v.begin() + 4, v.end(),
[&state](auto first, auto last)
{
std::cout << std::setw(2) << ++state << " : ";
while (true)
{
std::cout << *first;
if (++first == last)
break;
std::cout << ' ';
}
std::cout << '\n';
return false;
});
}
This outputs:
1 : 1 2 3 4
2 : 1 2 3 5
3 : 1 2 3 6
4 : 1 2 4 5
5 : 1 2 4 6
6 : 1 2 5 6
7 : 1 3 4 5
8 : 1 3 4 6
9 : 1 3 5 6
10 : 1 4 5 6
11 : 2 3 4 5
12 : 2 3 4 6
13 : 2 3 5 6
14 : 2 4 5 6
15 : 3 4 5 6
The source code for the library can be copy/pasted from the above link and inspected for how it works. This library is extremely high performance compared to solutions using std::prev_permutation. The implementation is relatively simple for this function, but the library also contains more functionality that grows increasingly complicated to implement (but just as easy to use):
template <class BidirIter, class Function>
Function
for_each_combination(BidirIter first,
BidirIter mid,
BidirIter last,
Function f);
template <class BidirIter, class Function>
Function
for_each_permutation(BidirIter first,
BidirIter mid,
BidirIter last,
Function f);
template <class BidirIter, class Function>
Function
for_each_reversible_permutation(BidirIter first,
BidirIter mid,
BidirIter last,
Function f);
template <class BidirIter, class Function>
Function
for_each_circular_permutation(BidirIter first,
BidirIter mid,
BidirIter last,
Function f);
template <class BidirIter, class Function>
Function
for_each_reversible_circular_permutation(BidirIter first,
BidirIter mid,
BidirIter last,
Function f);
The library has several pleasant features including:
Your input sequence (vector or whatever) need not be sorted.
You can prematurely break out of the loop at any time by returning true.
If you don't break out of the loop early, the sequence is always returned to its original state.
The functor always receives iterators to the first k elements of the sequence, so it is possible to also operate on the elements not selected if you tell the functor about the total length of the sequence.
Feel free to use the library as is, or study and take what you need from its implementation. The link above contains a tutorial-like description, and a detailed specification of each function.
Start with subset S = {1,2,3,...,k}, that's the first subset. Generate the next subset by examining elements from the right (start with the last), and increment it if you can (if it is < N), and return that as the next subset. If you can't increment it, look at the element to the left until you find one you can increment. Increment it, and set the elements to the right sequentially from that point. Below are the 3 element subsets of {1,2,3,4,5} (N=5,k=3,there are 10 subsets):
{1,2,3}, {1,2,4}, {1,2,5}, {1,3,4}, {1,3,5}, {1,4,5}, {2,3,4}, {2,3,5}, {2,4,5}, {3,4,5}
#include <iostream>
#include <vector>
std::ostream& operator<<(std::ostream& o, std::vector<int>& a)
{
o << "{";
for (std::vector<int>::const_iterator it = a.begin(); it != a.end(); ++it) {
o << *it;
if (it + 1 < a.end()) o << ",";
}
return o << "}";
}
int main()
{
const int N = 7;
const int k = 4;
std::vector<int> A(k);
// initialize
for (int i = 0; i < k; ++i) {
A[i] = i + 1;
}
std::cout << A << std::endl;
int h = 0;
bool done = false;
do {
++A[k-h-1];
for (int t = k - h; t < k; ++t) {
A[t] = A[t-1] + 1;
}
if (A[k-h-1] < N - h) {
// last element can be incremented, stay there...
h = 0;
} else {
// last element at max, look back ...
++h;
}
done = (A[0] == N - k + 1);
std::cout << A << std::endl;
} while (!done);
}
Pretty simple recursive implementation:
struct Combs
{
vector<int> scombs;
template <typename F>
void call_combs(int n, int k, F f)
{
if (k == 0) {
f();
}
else {
scombs.push_back(n - 1);
call_combs(n - 1, k - 1, f);
scombs.resize(scombs.size() - 1);
if (k < n) {
call_combs(n - 1, k, f);
}
}
}
};
...
Combs combs;
const auto& coco = combs.scombs;
combs.call_combs(6, 4, [&coco](){
copy(coco.cbegin(), coco.cend(), ostream_iterator<int>(cout));
cout << endl;
});

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

Erasing an element from 2D vector c++

I have a unsymmetrical vector in 2D.
vector< vector<int> > Test
where Test =
2 4 6 5 7
6 5 7 9 10
5 9 10
9 10
I am reading the row 1 and if any element of this is present in other rows then delete it.
for eaxmple.. After reading row 1, i have to remove 6, 5, and 7 from other rows.
However, It is not working
Here is the code i am trying
Test[i].erase(Test[i].begin()+j);
where i = row and j is col.
My code is :
for (i =0; i < Test.size();i++)
{
for (j=0; j < Test[i].size();j++)
{
// removed repeated element
if (i >0)
{
Test[i].erase(Test[i].begin() +j);
}
}
}
Maybe it is nor very nice but it works
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<std::vector<int>> v =
{
{ 2, 4, 6, 5, 7 },
{ 6, 5, 7, 9, 10 },
{ 5, 9, 10 },
{ 9, 10 }
};
for ( const auto &row : v )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
std::cout << std::endl;
if ( !v.empty() )
{
for ( auto it = std::next( v.begin() ); it != v.end(); ++it )
{
auto is_present = [&]( int x )
{
return std::find_if( v.begin(), it,
[x]( const std::vector<int> &v1 )
{
return std::find( v1.begin(), v1.end(), x ) != v1.end();
} ) != it;
};
it->erase( std::remove_if( it->begin(), it->end(), is_present ),
it->end() );
}
}
for ( const auto &row : v )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The output is
2 4 6 5 7
6 5 7 9 10
5 9 10
9 10
2 4 6 5 7
9 10
You can place the values encountered in each row in a set, and then query every element in a new row for existence in that set. Such a function would look like this :
void RemoveRowDuplicates(vector<vector<int>> &v)
{
std::set<int> vals;
for(auto &vec : v)
{
vec.erase(remove_if(vec.begin(), vec.end(), [&](int k){
return vals.find(k) != vals.end();
}), vec.end());
vals.insert(vec.begin(), vec.end());
}
}
What exactly do you think is Test[i].begin()+j? Is ist a set of elements you want to erase? I don't think so. It should be just an iterator, that points to a single element, but you want to delete all elements, that are already in your datastructure.
If I understood, what you want to do, try:
for(int j = 0; j < Test.size(); j++){ //iterate over other rows
if(j == i)
continue;
for(int k = 0; k < Test[j].size(); k++){ //iterate over elements of the rows
int elementToRemove = (Test[j])[k];
vector<int>::iterator it = Test[i].begin();
while (it != Test[i].end()) { //iterate over row i
if((*it) == elementToRemove){ //erase the element if it matches the actual
it = Test[i].erase(it);
}else{
it++;
}
}
}
}
You could execute the code for every possible i. Maybe start form i = 0 to n. If I refer to your code, that you added put the code above in between your
for (i =0; i < Test.size();i++){
//my code here...
}
Edit: Used iterator now to delete. The first version was not correct.
Edit2: Changed the index of the first loop and added continue statement.
This works for me:
int i = 0;
for ( int j = i+1; j < Test.size(); ++j )
{
for ( int k = 0; k < Test[i].size(); ++k )
{
std::vector<int>::iterator iter = Test[j].begin();
std::vector<int>::iterator end = Test[j].end();
for ( ; iter != end; )
{
if ( *iter == Test[i][k] )
{
iter = Test[j].erase(iter);
}
else
{
++iter;
}
}
}
}
Consider the following 2D vector
myVector=
1 2 3 4 5 -6
6 7 8 -9
8 -1 -2 1 0
Suppose we want to delete the element myVector[row][column] for appropriate row and column indices.
Look at the following code:
void delete_element(vector<int>& temp, col)
{
temp.erase(temp.begin()+col);
}
int main()
{
//Assume that the vector 'myVector' is already present.
cin>>row>>column;
delete_element(myVector[row],column);
}
What we basically do is,we get the row and column of the element to be deleted. Now as this 2D vector is a vector of vectors, we pass the vector(the row containing the element to be deleted) and the column as parameters to a function. Note that the row-vector is passed as a reference ('&' in vector parameter).
Now the problem becomes quite as simple as deleting an element from a 1D vector.
Hope this helps!

Dividing an STL list container to elements greater than value and elements lower than value

I'm making a function that recieves as parameter a list and a value K the function should divide the list to two parts the first part, in the same list without using another container contains the elements that are lower than the value K, the second part contains elements that are greater or equal to K, here's my attempt:
template <class T>
void dividie_list(list<T> & mylist, T k){
list<int>::iterator it;
it = mylist.begin();
while(it != mylist.end()){
if(*it >= k){
mylist.push_back(*it);
it = mylist.erase(it);
}
else
++it;
}
}
Input output example:
Input : mylist={1,3,4,14,11,9,7,16,25,19,7,8,9 } y k=8
Output: {1, 3, 4, 7, 7,9, 11, 16, 25, 19, 14, 8, 9}
It seems that the function gets stuck in an infinite loop and doesn't end, I can't figure that out, final exams are close guys, help is appreciated.
Edit: i tried something else based on a suggested solution but i can't tell for sure if it's valid, can someone confirm it :
template <class T>
void dividie_list(list<T> & mylist, T k)
{
typename list<T>::iterator first = mylist.begin();
typename list<T>::iterator last = mylist.end();
--last;
while(first != last){
if(*first >= k){
swap(*first,*last);
--last;
}
else
++first;
}
}
If you want the implementation of the method instead of calling a function to do the job, here is what you want, based on the code on this page.
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
template <class T>
void dividie_list(list<T> & mylist, T k)
{
typename list<T>::iterator first = mylist.begin();
typename list<T>::iterator last = mylist.end();
while (first!=last)
{
while (*first < k)
{
++first;
if (first==last) return;
}
do
{
--last;
if (first==last) return;
} while (!(*last < k));
swap (*first,*last);
++first;
}
return ;
}
Driver program to test above function:
int main()
{
int a[] = {1,3,4,14,11,9,7,16,25,19,7,8,9 };
list<int> l(a, a + sizeof(a) / sizeof(int) );
copy(l.begin(), l.end(), ostream_iterator<int>(cout, ", ") );
cout<<'\n';
dividie_list(l, 8);
copy(l.begin(), l.end(), ostream_iterator<int>(cout, ", ") );
}
the output is as below:
1, 3, 4, 14, 11, 9, 7, 16, 25, 19, 7, 8, 9,
1, 3, 4, 8, 7, 7, 9, 16, 25, 19, 11, 14, 9,
You need to return an iterator instead of void so that you can know where is the boundary between the first part and second.
There is no need to push or pop items anywhere. Enumerating the list and swapping elements as needed is all that is required.
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <list>
// iterator based parition implementation.
template<typename Iter>
Iter divide_list(Iter begin, Iter end,
const typename std::iterator_traits<Iter>::value_type& val)
{
Iter p = begin;
for (Iter it = begin; it != end; ++it)
{
if (*it < val)
{
if (it != p)
{
std::cout << "Swapping " << *it << " and " << *p << '\n';
std::iter_swap(it, p);
}
++p;
}
}
return p;
}
// generic container wrapper
template<template<typename, typename...> class V, typename T, typename... Args>
void divide_list(V<T,Args...>& seq, const T& arg)
{
divide_list(std::begin(seq), std::end(seq), arg);
}
int main()
{
std::list<int> lst { {1,3,4,14,11,9,7,16,25,19,7,8,9 } };
for (auto x : lst)
std::cout << x << ' ';
std::cout << std::endl;
divide_list(lst, 8);
for (auto x : lst)
std::cout << x << ' ';
std::cout << '\n' << std::endl;
// also works with vector (and deque)
std::vector<int> vec { {6,4,9,14,11,2,7,9,25,16,7,8,3 } };
for (auto x : vec)
std::cout << x << ' ';
std::cout << std::endl;
divide_list(vec, 8);
for (auto x : vec)
std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
Output
1 3 4 14 11 9 7 16 25 19 7 8 9
Swapping 7 and 14
Swapping 7 and 11
1 3 4 7 7 9 14 16 25 19 11 8 9
6 4 9 14 11 2 7 9 25 16 7 8 3
Swapping 2 and 9
Swapping 7 and 14
Swapping 7 and 11
Swapping 3 and 9
6 4 2 7 7 3 14 9 25 16 11 8 9
As a bonus, I modified the iterator algorithm to return the iterator position p as the function result, thereby knowing the first element in the resulting sequence that is greater-than or equal-to the test value (may come in handy). This allow you to have a start/end of the low-sequence (lst.begin(), p) and for the high sequence (p, lst.end()). The generic container support was solely because I was bored.