1. 程式人生 > >STL源代碼剖析——STL算法之set集合算法

STL源代碼剖析——STL算法之set集合算法

amp -s out 返回 計算 post ret 差集 ack

前言

本節介紹set集合的相關算法,各自是並集set_union,差集set_difference,交集set_intersection
和對稱差集
set_symmetric_difference。這是個函數都提供了兩個版本號的函數原型:第一個版本號是採用默認的排序比較方式operator<;第二個版本號是用戶通過仿函數comp自行指定排序方式。註意:這四個算法接受的輸入區間都是有序的,輸出也是有序的。

以下對set算法進行剖析,詳細凝視詳見源代碼,同一時候給出樣例說明該算法的功能。本文源代碼摘自SGI STL中的<stl_algo.h>文件。

set算法源代碼剖析

/*
下面是計算set集合的相關算法,各自是並集set_union。差集set_difference,交集set_intersection
和對稱差集set_symmetric_difference。這是個函數都提供了兩個版本號的函數原型
第一個版本號是採用默認的排序比較方式 operator<
第二個版本號是用戶通過comp自行指定排序方式
註意:這四個算法接受的輸入區間都是有序的,輸出也是有序的
*/

// Set algorithms: includes, set_union, set_intersection, set_difference,
// set_symmetric_difference.  All of these algorithms have the precondition
// that their input ranges are sorted and the postcondition that their output
// ranges are sorted.

// 推斷[first1, last1)是否包括[first2, last2),  
// 註意: 兩個區間要保證有序,默認排序方式是operator<。若要自行定義排序方式,則調用第二版本號;
template <class _InputIter1, class _InputIter2>
bool includes(_InputIter1 __first1, _InputIter1 __last1,
              _InputIter2 __first2, _InputIter2 __last2) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
                 _LessThanComparable);
  while (__first1 != __last1 && __first2 != __last2)//遍歷兩個區間
    if (*__first2 < *__first1)//first2小於first1表示不包括
      return false;//返回FALSE
    else if(*__first1 < *__first2)//若first1小於first2 
      ++__first1;//尋找第一個區間下一個位置
    else
      ++__first1, ++__first2;//若first2等於first1,遍歷兩區間的下一位置

  return __first2 == __last2;//若第二個區間先到達尾端。則返回TRUE
}

//版本號二:用戶通過comp自行指定排序方式
template <class _InputIter1, class _InputIter2, class _Compare>
bool includes(_InputIter1 __first1, _InputIter1 __last1,
              _InputIter2 __first2, _InputIter2 __last2, _Compare __comp) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool,
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  while (__first1 != __last1 && __first2 != __last2)
    if (__comp(*__first2, *__first1))
      return false;
    else if(__comp(*__first1, *__first2)) 
      ++__first1;
    else
      ++__first1, ++__first2;

  return __first2 == __last2;
}

//兩個集合區間的並集。相同也有兩個版本號
//求存在於[first1, last1)或存在於[first2, last2)內的全部元素
//註意:輸入區間必須是已排序
/*
default (1)	:默認是operator<操作的排序方式
	template <class InputIterator1, class InputIterator2, class OutputIterator>
	OutputIterator set_union (InputIterator1 first1, InputIterator1 last1,
                            InputIterator2 first2, InputIterator2 last2,
                            OutputIterator result);
custom (2)	:用戶指定的排序方式
	template <class InputIterator1, class InputIterator2,
          class OutputIterator, class Compare>
	OutputIterator set_union (InputIterator1 first1, InputIterator1 last1,
                            InputIterator2 first2, InputIterator2 last2,
                            OutputIterator result, Compare comp);
*/
//版本號一:默認是operator<操作的排序方式
template <class _InputIter1, class _InputIter2, class _OutputIter>
_OutputIter set_union(_InputIter1 __first1, _InputIter1 __last1,
                      _InputIter2 __first2, _InputIter2 __last2,
                      _OutputIter __result) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
                 _LessThanComparable);
  //兩個區間都尚未到達區間尾端,運行下面操作
  while (__first1 != __last1 && __first2 != __last2) {
	  /*
	  在兩區間內分別移動叠代器,首先將元素較小者(如果為A區)記錄在目標區result
	  移動A區叠代器使其前進。同一時候還有一個區的叠代器不變。然後進行一次新的比較,
	  記錄較小值,移動叠代器...直到兩區間中有一個到達尾端。若兩區間存在元素相等,
	  默認記錄第一區間的元素到目標區result.
	  */
    if (*__first1 < *__first2) {//first1小於first2
      *__result = *__first1;//則result初始值為first1
      ++__first1;//繼續第一個區間的下一個元素位置
    }
    else if (*__first2 < *__first1) {//first2小於first1
      *__result = *__first2;//第二區間元素值記錄到目標區
      ++__first2;//移動第二區間的叠代器
    }
    else {//若兩區間存在相等的元素,把第一區間元素記錄到目標區
		//同一時候移動兩個區間的叠代器
      *__result = *__first1;
      ++__first1;
      ++__first2;
    }
    ++__result;//更新目標區位置。以備進入下一次記錄操作操作
  }
  /*
  僅僅要兩區間之中有一個區間到達尾端。就結束上面的while循環
  下面將尚未到達尾端的區間剩余的元素復制到目標區
  此刻,[first1, last1)和[first2, last2)至少有一個是空區間
  */
  return copy(__first2, __last2, copy(__first1, __last1, __result));
}
//版本號二:用戶依據仿函數comp指定排序規則
template <class _InputIter1, class _InputIter2, class _OutputIter,
          class _Compare>
_OutputIter set_union(_InputIter1 __first1, _InputIter1 __last1,
                      _InputIter2 __first2, _InputIter2 __last2,
                      _OutputIter __result, _Compare __comp) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool,
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  while (__first1 != __last1 && __first2 != __last2) {
    if (__comp(*__first1, *__first2)) {
      *__result = *__first1;
      ++__first1;
    }
    else if (__comp(*__first2, *__first1)) {
      *__result = *__first2;
      ++__first2;
    }
    else {
      *__result = *__first1;
      ++__first1;
      ++__first2;
    }
    ++__result;
  }
  return copy(__first2, __last2, copy(__first1, __last1, __result));
}
/*樣例:
	#include <iostream>     // std::cout
	#include <algorithm>    // std::set_union, std::sort
	#include <vector>       // std::vector

	int main () {
	  int first[] = {5,10,15,20,25};
	  int second[] = {50,40,30,20,10};
	  std::vector<int> v(10);                      // 0  0  0  0  0  0  0  0  0  0
	  std::vector<int>::iterator it;

	  std::sort (first,first+5);     //  5 10 15 20 25
	  std::sort (second,second+5);   // 10 20 30 40 50

	  it=std::set_union (first, first+5, second, second+5, v.begin());
												   // 5 10 15 20 25 30 40 50  0  0
	  v.resize(it-v.begin());                      // 5 10 15 20 25 30 40 50

	  std::cout << "The union has " << (v.size()) << " elements:\n";
	  for (it=v.begin(); it!=v.end(); ++it)
		std::cout << ‘ ‘ << *it;
	  std::cout << ‘\n‘;

	  return 0;
	}
	Output:
	The union has 8 elements:
	5 10 15 20 25 30 40 50
*/

 //兩個集合區間的交集,相同也有兩個版本號
//求存在於[first1, last1)且存在於[first2, last2)內的全部元素
//註意:輸入區間必須是已排序,輸出區間的每一個元素的相對排序和第一個區間相對排序相同
/*
default (1)	:默認是operator<操作的排序方式
		template <class InputIterator1, class InputIterator2, class OutputIterator>
		OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1,
                                   InputIterator2 first2, InputIterator2 last2,
                                   OutputIterator result);


custom (2)	:用戶指定的排序方式
		template <class InputIterator1, class InputIterator2,
          class OutputIterator, class Compare>
		OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1,
                                   InputIterator2 first2, InputIterator2 last2,
                                   OutputIterator result, Compare comp);
*/
//版本號一:默認是operator<操作的排序方式
template <class _InputIter1, class _InputIter2, class _OutputIter>
_OutputIter set_intersection(_InputIter1 __first1, _InputIter1 __last1,
                             _InputIter2 __first2, _InputIter2 __last2,
                             _OutputIter __result) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
                 _LessThanComparable);
  //若兩個區間都尚未到達尾端。則運行下面操作
  while (__first1 != __last1 && __first2 != __last2) 
	//在兩個區間分別移動叠代器,直到遇到相等元素。記錄到目標區
	//繼續移動叠代器...直到兩區間之中有到達尾端
    if (*__first1 < *__first2) //第一個區間元素小於第二區間元素
      ++__first1;//移動第一區間的叠代器。此時第二區間的叠代器不變
    else if (*__first2 < *__first1) //第二區間的元素小於第一區間元素
      ++__first2;//移動第二區間元素,此時第一區間的叠代器不變
    else {//若第一區間元素等於第二區間元素
      *__result = *__first1;//按第一區間的相對排序記錄到目標區
	  //分別移動兩區間的叠代器
      ++__first1;
      ++__first2;
	  //更新目標區叠代器,以便繼續記錄元素
      ++__result;
    }
	//若有區間到達尾部,則停止while循環
	//此時,返回目標區
  return __result;
}
//版本號二:用戶依據仿函數comp指定排序規則
template <class _InputIter1, class _InputIter2, class _OutputIter,
          class _Compare>
_OutputIter set_intersection(_InputIter1 __first1, _InputIter1 __last1,
                             _InputIter2 __first2, _InputIter2 __last2,
                             _OutputIter __result, _Compare __comp) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool,
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);

  while (__first1 != __last1 && __first2 != __last2)
    if (__comp(*__first1, *__first2))
      ++__first1;
    else if (__comp(*__first2, *__first1))
      ++__first2;
    else {
      *__result = *__first1;
      ++__first1;
      ++__first2;
      ++__result;
    }
  return __result;
}
/*樣例:
	#include <iostream>     // std::cout
	#include <algorithm>    // std::set_intersection, std::sort
	#include <vector>       // std::vector

	int main () {
	  int first[] = {5,10,15,20,25};
	  int second[] = {50,40,30,20,10};
	  std::vector<int> v(10);                      // 0  0  0  0  0  0  0  0  0  0
	  std::vector<int>::iterator it;

	  std::sort (first,first+5);     //  5 10 15 20 25
	  std::sort (second,second+5);   // 10 20 30 40 50

	  it=std::set_intersection (first, first+5, second, second+5, v.begin());
												   // 10 20 0  0  0  0  0  0  0  0
	  v.resize(it-v.begin());                      // 10 20

	  std::cout << "The intersection has " << (v.size()) << " elements:\n";
	  for (it=v.begin(); it!=v.end(); ++it)
		std::cout << ‘ ‘ << *it;
	  std::cout << ‘\n‘;

	  return 0;
	}
	Output:
	The intersection has 2 elements:
	10 20
*/

 //兩個集合區間的差集。相同也有兩個版本號
//求存在於[first1, last1)但不存在於[first2, last2)內的全部元素
//註意:輸入區間必須是已排序。輸出區間的每一個元素的相對排序和第一個區間相對排序相同
/*
default (1)	:默認是operator<操作的排序方式
		template <class InputIterator1, class InputIterator2, class OutputIterator>
		OutputIterator set_difference (InputIterator1 first1, InputIterator1 last1,
                                 InputIterator2 first2, InputIterator2 last2,
                                 OutputIterator result);



custom (2)	:用戶指定的排序方式
		template <class InputIterator1, class InputIterator2,
          class OutputIterator, class Compare>
		OutputIterator set_difference (InputIterator1 first1, InputIterator1 last1,
                                 InputIterator2 first2, InputIterator2 last2,
                                 OutputIterator result, Compare comp);
*/
//版本號一:默認是operator<操作的排序方式
template <class _InputIter1, class _InputIter2, class _OutputIter>
_OutputIter set_difference(_InputIter1 __first1, _InputIter1 __last1,
                           _InputIter2 __first2, _InputIter2 __last2,
                           _OutputIter __result) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
                 _LessThanComparable);
  //若兩個區間都尚未到達尾端,則運行下面操作
  while (__first1 != __last1 && __first2 != __last2)
	 /*
	 在兩個區間分別移動叠代器。當第一區間元素等於第二區間元素時。表示兩區間共同存在該元素
	 則同一時候移動叠代器;
	 當第一區間元素大於第二區間元素時。就讓第二區間叠代器前進;
	 第一區間元素小於第二區間元素時,把第一區間元素記錄到目標區
	繼續移動叠代器...直到兩區間之中有到達尾端
	*/
    if (*__first1 < *__first2) {//第一區間元素小於第二區間元素
      *__result = *__first1;//把第一區間元素記錄到目標區
      ++__first1;//移動第一區間叠代器
      ++__result;//跟新目標區。以便繼續記錄數據
    }
    else if (*__first2 < *__first1)//當第一區間的元素大於第二區間的元素
      ++__first2;//移動第二區間叠代器,註意:這裏不記錄不論什麽元素
    else {//若兩區間的元素相等時,同一時候移動兩區間的叠代器
      ++__first1;
      ++__first2;
    }
	//若第二區間先到達尾端。則把第一區間剩余的元素復制到目標區
  return copy(__first1, __last1, __result);
}
//版本號二:用戶依據仿函數comp指定排序規則
template <class _InputIter1, class _InputIter2, class _OutputIter, 
          class _Compare>
_OutputIter set_difference(_InputIter1 __first1, _InputIter1 __last1,
                           _InputIter2 __first2, _InputIter2 __last2, 
                           _OutputIter __result, _Compare __comp) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool,
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);

  while (__first1 != __last1 && __first2 != __last2)
    if (__comp(*__first1, *__first2)) {
      *__result = *__first1;
      ++__first1;
      ++__result;
    }
    else if (__comp(*__first2, *__first1))
      ++__first2;
    else {
      ++__first1;
      ++__first2;
    }
  return copy(__first1, __last1, __result);
}
/*樣例:
	#include <iostream>     // std::cout
	#include <algorithm>    // std::set_difference, std::sort
	#include <vector>       // std::vector

	int main () {
	  int first[] = {5,10,15,20,25};
	  int second[] = {50,40,30,20,10};
	  std::vector<int> v(10);                      // 0  0  0  0  0  0  0  0  0  0
	  std::vector<int>::iterator it;

	  std::sort (first,first+5);     //  5 10 15 20 25
	  std::sort (second,second+5);   // 10 20 30 40 50

	  it=std::set_difference (first, first+5, second, second+5, v.begin());
												   //  5 15 25  0  0  0  0  0  0  0
	  v.resize(it-v.begin());                      //  5 15 25

	  std::cout << "The difference has " << (v.size()) << " elements:\n";
	  for (it=v.begin(); it!=v.end(); ++it)
		std::cout << ‘ ‘ << *it;
	  std::cout << ‘\n‘;

	  return 0;
	}
	Output:
	The difference has 3 elements:
	5 15 25
*/

 //兩個集合區間的對稱差集,相同也有兩個版本號
//求存在於[first1, last1)但不存在於[first2, last2)內的全部元素以及出如今[first2, last2)但不出如今[first1, last1)
//註意:輸入區間必須是已排序
/*
default (1)	:默認是operator<操作的排序方式
		template <class InputIterator1, class InputIterator2, class OutputIterator>
		OutputIterator set_symmetric_difference (InputIterator1 first1, InputIterator1 last1,
                                           InputIterator2 first2, InputIterator2 last2,
                                           OutputIterator result);


custom (2)	:用戶指定的排序方式
		template <class InputIterator1, class InputIterator2,
          class OutputIterator, class Compare>
		OutputIterator set_symmetric_difference (InputIterator1 first1, InputIterator1 last1,
                                           InputIterator2 first2, InputIterator2 last2,
                                           OutputIterator result, Compare comp);
*/
//版本號一:默認是operator<操作的排序方式
template <class _InputIter1, class _InputIter2, class _OutputIter>
_OutputIter 
set_symmetric_difference(_InputIter1 __first1, _InputIter1 __last1,
                         _InputIter2 __first2, _InputIter2 __last2,
                         _OutputIter __result) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
                 _LessThanComparable);
  //若兩個區間都尚未到達尾端,則運行下面的操作
  while (__first1 != __last1 && __first2 != __last2)
	  /*
	  情況1:若兩區間元素相等,則同一時候移動兩區間的叠代器.
	  情況2:若第一區間的元素小於第二區間元素,則把第一區間元素記錄到目標區,且移動第一區間叠代器.
	  情況3:若第一區間的元素大於第二區間元素,則把第二區間元素記錄到目標區,且移動第二區間叠代器.
	  */
    if (*__first1 < *__first2) {//屬於情況2
      *__result = *__first1;//把第一區間元素記錄到目標區
      ++__first1;//移動第一區間叠代器.此時第二區間叠代器不變
      ++__result;
    }
    else if (*__first2 < *__first1) {//屬於情況3
      *__result = *__first2;//把第二區間元素記錄到目標區
      ++__first2;//移動第二區間叠代器.此時第一區間叠代器不變
      ++__result;
    }
    else {//屬於情況1
		//同一時候移動兩區間的叠代器
      ++__first1;
      ++__first2;
    }
	 /*
  僅僅要兩區間之中有一個區間到達尾端,就結束上面的while循環
  下面將尚未到達尾端的區間剩余的元素復制到目標區
  此刻,[first1, last1)和[first2, last2)至少有一個是空區間
  */
  return copy(__first2, __last2, copy(__first1, __last1, __result));
}

//版本號二:用戶依據仿函數comp指定排序規則
template <class _InputIter1, class _InputIter2, class _OutputIter,
          class _Compare>
_OutputIter 
set_symmetric_difference(_InputIter1 __first1, _InputIter1 __last1,
                         _InputIter2 __first2, _InputIter2 __last2,
                         _OutputIter __result,
                         _Compare __comp) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(_OutputIter, _OutputIterator);
  __STL_REQUIRES_SAME_TYPE(
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  __STL_BINARY_FUNCTION_CHECK(_Compare, bool,
       typename iterator_traits<_InputIter1>::value_type,
       typename iterator_traits<_InputIter2>::value_type);
  while (__first1 != __last1 && __first2 != __last2)
    if (__comp(*__first1, *__first2)) {
      *__result = *__first1;
      ++__first1;
      ++__result;
    }
    else if (__comp(*__first2, *__first1)) {
      *__result = *__first2;
      ++__first2;
      ++__result;
    }
    else {
      ++__first1;
      ++__first2;
    }
  return copy(__first2, __last2, copy(__first1, __last1, __result));
}
/*樣例:
	#include <iostream>     // std::cout
	#include <algorithm>    // std::set_symmetric_difference, std::sort
	#include <vector>       // std::vector

	int main () {
	  int first[] = {5,10,15,20,25};
	  int second[] = {50,40,30,20,10};
	  std::vector<int> v(10);                      // 0  0  0  0  0  0  0  0  0  0
	  std::vector<int>::iterator it;

	  std::sort (first,first+5);     //  5 10 15 20 25
	  std::sort (second,second+5);   // 10 20 30 40 50

	  it=std::set_symmetric_difference (first, first+5, second, second+5, v.begin());
												   //  5 15 25 30 40 50  0  0  0  0
	  v.resize(it-v.begin());                      //  5 15 25 30 40 50

	  std::cout << "The symmetric difference has " << (v.size()) << " elements:\n";
	  for (it=v.begin(); it!=v.end(); ++it)
		std::cout << ‘ ‘ << *it;
	  std::cout << ‘\n‘;

	  return 0;
	}
	Output:
	The symmetric difference has 6 elements:
	5 15 25 30 40 50
*/
參考資料:

《STL源代碼剖析》侯捷

STL源代碼剖析——STL算法之set集合算法