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》源碼

發佈了155 篇原創文章 · 獲贊 2 · 訪問量 2350
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章