四、c++中的算法--变动性算法---排列

8.排列

介绍三种操作
- 排列元素:排序方式为字典式“正规”排序
- 重排元素,对容器内元素随机排序。形式一:符合均匀分布随机的排序。形式二:按指定规则打乱容器的元素次序。
- 将元素向前搬移,按指定的一元判断式向前搬移元素,函数返回值是使一元判断式为“false”的第一个元素的位置。

1.排列元素

  • next_permutation
    函数模板:
template<class BidirIt>
bool next_permutation(BidirIt first, BidirIt last)
{
    if (first == last) return false;//空
    BidirIt i = last;
    if (first == --i) return false;//一个元素

    while (1) {
        BidirIt i1, i2;

        i1 = i;//i指向最后一个元素
        if (*--i < *i1) { //小于的话
            i2 = last;
            while (!(*i < *--i2)) //寻找大于后面值的前面最近元素
                ;
            std::iter_swap(i, i2);//将大的值交换到前面
            std::reverse(i1, last);//将后面的降序逆转
            return true;
        }
        if (i == first) {//到达开头位置,整个序列为降序,没有更大的序列,返回false
            std::reverse(first, last);//逆转整个序列
            return false;
        }
    }
}

//形式二
template< class BidirIt, class Compare >
bool next_permutation( BidirIt first, BidirIt last, Compare comp );

说明:
1. 形式一:按照operator<排序,即升序,如果新的排列大于旧的排列,返回true,如果达到最高排列,返回false
2. 形式二:按照comp函数比较,返回值一样。

例子:

----------省略--------------
vector<int> vec1 = {1,3,4,2};
do{
    cout << "vec1: ";
    for_each(vec1.begin(), vec1.end(), printItem);
    cout << endl;

} while (next_permutation(vec1.begin(),vec1.end()));
----------省略--------------

输出结果为:

vec1: 1   3   4   2
vec1: 1   4   2   3
vec1: 1   4   3   2
vec1: 2   1   3   4
vec1: 2   1   4   3
vec1: 2   3   1   4
vec1: 2   3   4   1
vec1: 2   4   1   3
vec1: 2   4   3   1
vec1: 3   1   2   4
vec1: 3   1   4   2
vec1: 3   2   1   4
vec1: 3   2   4   1
vec1: 3   4   1   2
vec1: 3   4   2   1
vec1: 4   1   2   3
vec1: 4   1   3   2
vec1: 4   2   1   3
vec1: 4   2   3   1
vec1: 4   3   1   2
vec1: 4   3   2   1

简单分析一下:
在平常的operator<比较中,如果两个序列,相对应的元素,
1.如果第一个序列的元素小于第二个序列的对应元素,返回true.
2.如果对应元素相等,比较下一个元素,如果两个序列相等,返回false
因此。我们可以知道1234<1324
这个函数的作用就是每个回合返回比旧序列大一点的序列,逐步变大,直到最后的序列为降序的时候,就为最大的序列,此时返回false,例子中的循环就结束。即4321

【相关文档】
1.C++STL的next_permutation

2.重排元素

  • random_shuffle
    函数模板为:
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );

//
template<class RandomIt, class RandomFunc>
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
{
//迭代器距离类型,有符号整数类型
    typename std::iterator_traits<RandomIt>::difference_type i, n;
    n = last - first;
    for (i = n-1; i > 0; --i) {
        using std::swap;
        swap(first[i], first[r(i+1)]);//随机交换【值】
    }
}


template< class RandomIt, class URNG >
void shuffle( RandomIt first, RandomIt last, URNG&& g );

说明:在给定的范围内进行重新排序元素[first, last)等,
1. 形式一: 随机数生成器是实现定义的,但经常使用的功能std::rand.
2. 形式二: 随机数生成器的功能是对象r.
3. 形式三: 随机数生成器的功能是对象g.
r - 函数对象作为iterator_traits::difference_type如果调用返回一个随机选择的类型的值转换为r(n)在区间[0,N)

例子:

class MyRand
{
public:
    int operator()(int index)
    {
        return  rand() % index;
    }
};
---------省略------------
vector<int> vec1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
vector<int> vec2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

//默认随机排列
random_shuffle(vec1.begin(), vec1.end());

random_shuffle(vec1.begin(), vec1.end(),MyRand());
---------省略--------

输出结果为:

vec1: 9   2   0   3   1   6   8   4   5   7
vec2: 1   2   3   4   5   6   7   8   9   0

3.将元素向前搬移

  • partition
  • stable_partition

函数模板为:


template<class BidirIt, class UnaryPredicate>
BidirIt partition(BidirIt first, BidirIt last, UnaryPredicate p)
{
    while (1) {
        while ((first != last) && p(*first)) {//查找不满足p的元素
            ++first;
        }
        if (first == last--) break;//等于last,break
        while ((first != last) && !p(*last)) {
        //从后往前查找满足p的元素
            --last;
        }
    //前面是满足p的元素,后面是不满足的元素,顺序不变,直接返回
        if (first == last) break;
        //否则交换元素,继续遍历
        std::swap(*first++, *last);
    }
    return first;
}

std::partition会将区间[first,last)中的元素重新排列,满足判断条件pred的元素会被放在区间的前段,不满足pred的元素会被放在区间的后段。该算法不能保证元素的初始相对位置,如果需要保证初始相对位置,应该使用stable_partition.

  1. 返回值为指向不满足一元判断式的第一个元素迭代器

stable_partition
重新排序的范围[first, last)在这样一种方式中的元素。元素的相对顺序被保存.
函数声明为:

template< class BidirIt, class UnaryPredicate >
BidirIt stable_partition( BidirIt first, BidirIt last, UnaryPredicate p );

例子:

bool op(int elem1){
    return   elem1>3;
}
-----------------------省略-----------------
    vector<int> vec1 = { 1, 2, 3, 6, 5, 4 };
    vector<int> vec2 = { 4,1, 2, 3, 5, 6 };
    -----------------------省略-----------------
    partition(vec1.begin(), vec1.end(),op);
    stable_partition(vec2.begin(), vec2.end(), op);
    -----------------------省略-----------------

输出为:

vec1: 4   5   6   3   2   1
vec2: 4   5   6   1   2   3

采用stable_partition每个类别的相对顺序是未变的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值