交换 std::list 中的相邻元素

Swap neighbouring elements in std::list

本文关键字:元素 std list 交换      更新时间:2023-10-16

我想在std::list中更改相邻元素的位置

列表和值的示例

A B C D E F G
3 2 1 2 1 3 2

我期望在排序后收到什么:

A B D C F E G
3 2 2 1 3 1 2

因此,简单的A > B = 无事可做,但 C < D = 交换它们并转到E比较。

我不知道如何交换邻居元素。

所以,我想前进到1个步骤good元素

您可以使用两个迭代器轻松完成此操作:

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;
    }
}

现场示例

注意:如果您不使用 C++11,因此调用 size() 可能会产生很大的开销,您可以将其替换为以下内容(当然,将 auto 的所有用法替换为显式类型):

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
}

您可以使用标准算法std::adjacent_find查找一对元素,首先<第二个元素,然后交换它们。>

例如

#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;
} 

输出为

3 2 1 2 1 3 2 
3 2 2 1 1 3 2 

或者,如果您想在第一次<第二次处理所有这些情况,则可以使用以下代码>

#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;
} 

输出为

3 2 1 2 1 3 2 
3 2 2 1 3 2 1

这给出了所需的结果,并按照您的要求切换了"好"元素的比较:

#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;
}

执行结果:

3 2 1 2 1 3 2 
3 2 2 1 3 1 2

如果您没有 C++11 支持,使用 2 个迭代器的简单 C++03 解决方案可能是:

#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++;
    }
}

然后(根据您的示例)如果您这样做:

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);
}

然后对于:

A B C D E F G
3 2 1 2 1 3 2

将有以下比较: A < B ?(否) C < D ?(是的,掉期) E < F ?(是的,交换也是)产生输出:

3 2 2 1 3 1 2 

如果您只想成对遍历并在第一个元素小于第二个元素时交换元素,那么您可以例如使用这样的std::adjacent_find

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));
}

这将导致3 2 1 2 1 3 2数字列表排列为:

3 2 2 1 3 2 1

但是,这与你的预期结果不同,3 2 2 1 3 1 2我不明白你为什么不想像其他人一样交换最后一对1 2

如果您想要的是一个不稳定的排序模式,那么就没有简单的解决方案。相反,您必须对单个元素使用特殊处理。