next_permutation和pre_permutation源码解析

排列和组合在数学上特别的常见,同时,在编程比赛当中也会经常碰到。STL封装了特别高效的排列组合函数:next_permutation和pre_permutation,理解它们实现的思想,才能更好地运用。

1.next_permutation

实现思想:首先,从最尾端开始往前寻找两个相邻元素,令第一元素为*i,第二元素为*ii,且满足*i < *ii,找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个大于*i的元素,令为*j,将i,j元素对调,在将ii之后的所有元素颠倒。

具体实现:

template <class BidirectionalIterator>
bool next_permutation(BidirectionalIterator first,
                      BidirectionalIterator last) {
  if (first == last) return false; //空数组
  BidirectionalIterator i = first;
  ++i;
  if (i == last) return false; //只有一个元素
  i = last;
  --i;

  for(;;) {
    BidirectionalIterator ii = i;
    --i;
    if (*i < *ii) { //查找一对相邻的元素,且*i < *ii
      BidirectionalIterator j = last;
      while (!(*i < *--j)); //从最尾端开始,查找第一个大于*i的数
      iter_swap(i, j); //交换*j和*i
      reverse(ii, last); //将迭代器[first, last]范围内的数据颠倒
      return true;
    }
    if (i == first) { //进行到最前面
      reverse(first, last); //重新开始排
      return false;
    }
  }
}

template <class BidirectionalIterator>
inline void reverse(BidirectionalIterator first, BidirectionalIterator last) {
  __reverse(first, last, iterator_category(first));
}
template <class RandomAccessIterator>
void __reverse(RandomAccessIterator first, RandomAccessIterator last,
               random_access_iterator_tag) {
  while (first < last) iter_swap(first++, --last); //将迭代器[first, last]范围内的数据颠倒
}

2.pre_permutation

实现思想:首先,从最尾端开始往前寻找两个相邻元素,令第一元素为*i,第二元素为*ii,且满足*i > *ii,找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个小于*i的元素,令为*j,将i,j元素对调,在将ii之后的所有元素颠倒。

具体实现:

template <class BidirectionalIterator>
bool prev_permutation(BidirectionalIterator first,
                      BidirectionalIterator last) {
  if (first == last) return false; //空数组
  BidirectionalIterator i = first;
  ++i;
  if (i == last) return false; //只有一个元素
  i = last;
  --i;

  for(;;) {
    BidirectionalIterator ii = i;
    --i;
    if (*ii < *i) { //查找一组相邻的元素,且*i > *ii
      BidirectionalIterator j = last;
      while (!(*--j < *i)); //从最尾端开始,查找第一个小于*i的数
      iter_swap(i, j); //交换
      reverse(ii, last); //将迭代器[first, last]范围内的数据颠倒
      return true;
    }
    if (i == first) { //进行到最前面
      reverse(first, last); //从头开始排
      return false;
    }
  }
}
template <class BidirectionalIterator>
inline void reverse(BidirectionalIterator first, BidirectionalIterator last) {
  __reverse(first, last, iterator_category(first));
}
template <class RandomAccessIterator>
void __reverse(RandomAccessIterator first, RandomAccessIterator last,
               random_access_iterator_tag) {
  while (first < last) iter_swap(first++, --last); //将迭代器[first, last]范围内的数据颠倒
}

3.具体运用 

https://leetcode.com/problems/next-greater-element-iii/

1.《STL库源码解析》------侯捷

2.《STL3.0》源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值