zoukankan      html  css  js  c++  java
  • C++变量和STL容器的交换

    变量交换

    现在有两个int型变量xy,需要将xy的值进行交换

    临时变量版

    这样显然是不行的:

    x=y;
    y=x;
    

    因为当x被赋值为y,那么xy所表示的均为原来y的值,原来x表示的数据将丢失

    不难想到使用一个临时变量tmp暂存其中一方的数据:

    int tmp=x;
    x=y;
    y=tmp;
    

    算术运算版

    之前的方法需要使用额外的变量来实现,那么有没有不使用额外变量的方法呢?当然是有的:

    x=x+y;
    y=x-y;
    x=x-y;
    

    语句非常对称也非常精妙,第一句将x赋值为xy的和,这样原来的x仍然可以通过x-y表示出来,而交换后的y就是原来的x,所以第二句赋值语句就将y赋值成了原来的x,此时x仍然表示原来两个变量的和,所以交换后的x也即原来的y的值就是x-y

    位运算版

    x^=y;
    y^=x;
    x^=y;
    

    这个可以说是 xor 艺术了,原理与上一种类似,但是由于是位运算,运算速度要优于前面一种

    汇编版

    __asm
    {
        mov eax,[x]
        xchg eax,[y]
        mov [x],eax
    }
    

    同样也是三行,不过之前的如果编译成汇编语言肯定不止三行,所以这个版本在性能和占用空间上碾压前三者

    不过应该不会有人这么用的,仅供观赏,要慎用

    函数版

    C++中提供了用于变量交换的swap函数,只需要把两个变量传入即可:

    swap(x,y)
    

    swap函数的内部实现:

    template <class _Ty>
    _NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept { // forward _Arg as movable
        return static_cast<remove_reference_t<_Ty>&&>(_Arg);
    }
    
    #if _HAS_CXX17
    template <class _Ty, enable_if_t<is_move_constructible_v<_Ty> && is_move_assignable_v<_Ty>, int> _Enabled>
    #else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv
    template <class _Ty, int _Enabled>
    #endif // _HAS_CXX17
    _CONSTEXPR20 void swap(_Ty& _Left, _Ty& _Right) noexcept(
        is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) {
        _Ty _Tmp = _STD move(_Left);
        _Left    = _STD move(_Right);
        _Right   = _STD move(_Tmp);
    }
    

    可以发现其内部机理与第一种方法类似,只是用了泛型并且增加了一些修饰

    STL容器交换

    两个对象之间的交换,我们就没必要考虑时间复杂度的常数问题,而应该考虑与数据量的相关性

    首先先考虑两个普通的int数组x[1048576]y[1048576]的交换,朴素的做法是对其中的每一个元素做一次交换:

    for(int i=0;i<1048576;i++) swap(x[i],y[i]);
    

    swap函数也提供了两个数组交换的接口,与上面的实现过程一致

    swap(x,y)
    

    这样的时间复杂度是 (O(n)) ,换个角度思考,两个数组事实上只是两块内存中的连续单元,不像同一个数组中两个元素进行交换会影响结果,它们交换与否丝毫不影响算法的正确性,内容的交换等效于对它们的变量名进行交换,但是C++又不支持动态更改变量名,所以我们需要使用指针或引用,交换时也仅需交换指针或引用:

    int *p1=x,*p2=y;
    swap(p1,p2);
    

    正是基于这个思想,stl的许多容器进行swap操作的时间复杂度都是 (O(1)),包括:vectorlistmapsetdeque
    priority_queuequeuestack 在开C++11时为 (O(1)),否则为 (O(n))

    参考资料

  • 相关阅读:
    在Visual Studio中使用NUnit
    C#调用Exe
    网页用chrome打开为乱码
    ctags最基本用法
    Facebook Connect
    SVM初体验
    python中可恶的回车符
    初识PowerDesigner
    Mysql中文乱码问题解决
    stat函数
  • 原文地址:https://www.cnblogs.com/fenggwsx/p/15163611.html
Copyright © 2011-2022 走看看