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.
- 返回值为指向不满足一元判断式的第一个元素迭代器
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
每个类别的相对顺序是未变的。