简体   繁体   中英

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM