四.c++中的算法--排序及相关操作---合并排序

来源:互联网 发布:关于网络的论文 编辑:程序博客网 时间:2024/06/03 20:06

5.合并排序

1.两个已序集合的总和

  • merge()
    函数模板:
                 版本一
template<class InputIt1, class InputIt2, class OutputIt>OutputIt merge(InputIt1 first1, InputIt1 last1,               InputIt2 first2, InputIt2 last2,               OutputIt d_first){    for (; first1 != last1; ++d_first) {        if (first2 == last2) {//序列为空            return std::copy(first1, last1, d_first);        }        if (*first2 < *first1) {//升序排列            *d_first = *first2;            ++first2;        } else {            *d_first = *first1;            ++first1;        }    }    return std::copy(first2, last2, d_first);//将序列剩余部分拷贝到目标区间}

           版本二

template<class InputIt1, class InputIt2,         class OutputIt, class Compare>OutputIt merge(InputIt1 first1, InputIt1 last1,               InputIt2 first2, InputIt2 last2,               OutputIt d_first, Compare comp){    for (; first1 != last1; ++d_first) {        if (first2 == last2) {            return std::copy(first1, last1, d_first);        }        if (comp(*first2, *first1)) {//自定义二元比较函数            *d_first = *first2;            ++first2;        } else {            *d_first = *first1;            ++first1;        }    }    return std::copy(first2, last2, d_first);}

说明:
1. 源容器的两个序列应该是有序的,但是无序也可以
2. 要保证目标空间够大,否则需要使用插入行迭代器。如back_inserter
3. 一般情况,目标区间和源区间不允许重复。

2.两个已序集合的并集(union)

  • set_union()
    用于将已序的两个集合合并,重复的元素被唯一化。
    函数模板为:
template<class InputIt1, class InputIt2, class OutputIt>OutputIt set_union(InputIt1 first1, InputIt1 last1,                   InputIt2 first2, InputIt2 last2,                   OutputIt d_first){    for (; first1 != last1; ++d_first) {        if (first2 == last2)//序列二为空            return std::copy(first1, last1, d_first);        if (*first2 < *first1) {//默认比较规则,升序合并            *d_first = *first2++;        } else {            *d_first = *first1;            if (!(*first1 < *first2))//除去相等元素                ++first2;            ++first1;        }    }    return std::copy(first2, last2, d_first);}//第二种形式template<class InputIt1, class InputIt2,         class OutputIt, class Compare>OutputIt set_union(InputIt1 first1, InputIt1 last1,                   InputIt2 first2, InputIt2 last2,                   OutputIt d_first, Compare comp){    for (; first1 != last1; ++d_first) {        if (first2 == last2)            return std::copy(first1, last1, d_first);        if (comp(*first2, *first1)) {            *d_first = *first2++;        } else {            *d_first = *first1;            if (!comp(*first1, *first2))                ++first2;            ++first1;        }    }    return std::copy(first2, last2, d_first);}

说明:
1. 其中,两个源序列需要是有序的,不然会报错
2. 同时,当源区间本来就有重复元素时,会保留这些重复元素,元素的重复个数是两个源区间中重复个数较大的那个数值。
例子:

-------------省略----------------vector<int> vec1 = { 1, 2, 4, 5, 6, 3 };vector<int> vec2 = { 1, 2, 2,2,3,3,4,4,5 };vector<int> vec4;//先排序sort(vec1.begin(),vec1.end());sort(vec2.begin(), vec2.end());//并集set_union(vec1.begin(),vec1.end(),vec2.begin(),vec2.end(),back_inserter(vec4));-------------省略----------------

结果为:

 vec4: 1   2   2   2   3   3   4   4   5   6

可以发现重复元素时序列2这个重复元素多的序列个数

3.两个已序集合的交集(intersection)

  • set_intersection()
    1. 算法用于将已序的两个区间的元素合并,新生区间内的元素应该是同时属于两个源区间的元素
    2. 如果源区间存在重复元素,那么新生区间也存在重复元素,并且使属于数目小的那个重复个数。

函数原型为:

template<class InputIt1, class InputIt2, class OutputIt>OutputIt set_intersection(InputIt1 first1, InputIt1 last1,                          InputIt2 first2, InputIt2 last2,                          OutputIt d_first){    while (first1 != last1 && first2 != last2) {        if (*first1 < *first2) {            ++first1;        } else  {            if (!(*first2 < *first1)) {//寻找公有元素                *d_first++ = *first1++;            }            ++first2;        }    }    return d_first;}//第二种形式template<class InputIt1, class InputIt2,         class OutputIt, class Compare>OutputIt set_intersection(InputIt1 first1, InputIt1 last1,                          InputIt2 first2, InputIt2 last2,                          OutputIt d_first, Compare comp){    while (first1 != last1 && first2 != last2) {        if (comp(*first1, *first2)) {            ++first1;        } else {            if (!comp(*first2, *first1)) {                *d_first++ = *first1++;            }            ++first2;        }    }    return d_first;}

说明:
1. 第一种形式: 使用默认比较规则:operator<
2. 第二种形式: 使用自定义二元比较函数: comp
3. 返回值: 目标区间最后一个公有元素的后一个位置。
4. 所有元素都有序排列

例子:

--------------------------省略-------------------    vector<int> vec1 = { 1, 2, 4, 5, 6, 3 };    vector<int> vec2 = { 1, 2, 2,2,3,3,4,4,5 };    vector<int> vec4;    set_intersection(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), back_inserter(vec4));--------------------------省略-------------------

结果为:

 vec4: 1   2   3   4   5

4.两个已序集合的差集 (difference)

  • set_difference()

    1. 算法实现两个源区间之间的求差。
    2. 新生区间的元素为只在序列1中存在的元素。

函数原型:

template<class InputIt1, class InputIt2, class OutputIt>OutputIt set_difference(InputIt1 first1, InputIt1 last1,                        InputIt2 first2, InputIt2 last2,                        OutputIt d_first){    while (first1 != last1) {        if (first2 == last2) return std::copy(first1, last1, d_first);        if (*first1 < *first2) {//选择序列1中独有的元素            *d_first++ = *first1++;        } else {            if (! (*first2 < *first1)) {                ++first1;            }            ++first2;//跳过相同的元素        }    }    return d_first;}//第二种形式:template<class InputIt1, class InputIt2,         class OutputIt, class Compare>OutputIt set_difference( InputIt1 first1, InputIt1 last1,                         InputIt2 first2, InputIt2 last2,                         OutputIt d_first, Compare comp){    while (first1 != last1) {        if (first2 == last2) return std::copy(first1, last1, d_first);        if (comp(*first1, *first2)) {            *d_first++ = *first1++;        } else {            if (!comp(*first2, *first1)) {                ++first1;            }            ++first2;        }    }    return d_first;}

说明:
1. 第一种形式: 使用默认比较规则:operator<
2. 第二种形式: 使用自定义二元比较函数: comp
3. 返回值: 目标区间最后一个公有元素的后一个位置。
4. 所有元素都有序排列
5. 如果源区间有重复元素,目标区间也会有,重复的个数是区间一减去源区间二的个数。如果区间二的个数大于区间一的个数,那么重复个数为0 ,即不会存在此元素。

例子:

--------------省略---------------------    vector<int> vec1 = { 1, 2,4, 5, 6, 3,3 };    vector<int> vec2 = { 1, 2,2,3,4,4,5 };    vector<int> vec4;    sort(vec1.begin(),vec1.end());    sort(vec2.begin(), vec2.end());    set_difference(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), back_inserter(vec4));--------------省略--------------------

结果为:

 vec4: 3   6

set_symmetric_difference
函数原型;

版本一template<class InputIt1, class InputIt2, class OutputIt>OutputIt set_difference(InputIt1 first1, InputIt1 last1,                        InputIt2 first2, InputIt2 last2,                        OutputIt d_first){    while (first1 != last1) {    //序列2为空,返回序列1        if (first2 == last2) return std::copy(first1, last1, d_first);        if (*first1 < *first2) {//返回序列1和序列2中小的元素            *d_first++ = *first1++;        } else {            if (*first2 < *first1) {                *d_first++ = *first2;            } else {                ++first1;            }            ++first2;//两个元素相等,跳过        }    }    return std::copy(first2, last2, d_first);//返回序列2剩下的部分}//第二种形式:template<class InputIt1, class InputIt2,         class OutputIt, class Compare>OutputIt set_difference(InputIt1 first1, InputIt1 last1,                        InputIt2 first2, InputIt2 last2,                        OutputIt d_first, Compare comp){    while (first1 != last1) {        if (first2 == last2) return std::copy(first1, last1, d_first);        if (comp(*first1, *first2)) {            *d_first++ = *first1++;        } else {            if (comp(*first2, *first1)) {                *d_first++ = *first2;            } else {                ++first1;            }            ++first2;        }    }    return std::copy(first2, last2, d_first);}

例子:

-----------------省略-------------    vector<int> vec1 = {1,3,5,7,9};    vector<int> vec2 = {0,2,3,3,4,6,8 };    vector<int> vec4;    set_symmetric_difference(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), back_inserter(vec4));-----------------省略-------------

结果为:

 vec4: 0   1   2   3   4   5   6   7   8   9

可以看错,这个函数是选择两个序列的有序序列,如果两个序列有重复元素,元素的个数为多个减去少个的个数,如3的个数为2-1 =1。
【相关文档】
1.C++集合操作之集合对称并集:std::set_symmetric_difference

5.连贯的已序区间合并算法

  • inplace_merge()
    inplace_merge函数的作用和merge函数差不多,只不过是在一个容器中进行归并。将[first,mid) 和 [mid,last)这两个区间进行归并成一个有序序列。

    数原型:
template< class BidirIt >void inplace_merge( BidirIt first, BidirIt middle, BidirIt last );template< class BidirIt, class Compare>void inplace_merge( BidirIt first, BidirIt middle, BidirIt last, Compare comp );

说明:
1. 第一个形式:operator<的第一个版本使用比较的元素,
2. 第二个版本使用给定的比较函数comp.
3. [first,middle)和[middle,last)这两个区间必须都是升序或者降序。

例子:

------------省略-------------    vector<int> vec2 = {1,3,5,7,2,4,5,8 };    inplace_merge(vec2.begin(), vec2.begin() + 4, vec2.end());------------省略-------------

结果为:

vec2: 1   2   3   4   5   5   7   8
原创粉丝点击