【STL源码剖析读书笔记】【第6章】算法之inplace_merge算法

时间:2022-02-09 04:18:33

1、  inplace_merge()函数将两个连接在一起的排序序列[first, middle)和[middle, last)结合成单一序列并保持有序。inplace_merge()函数是stable操作。

2、  inplace_merge()版本一的源代码,只讨论了有暂时缓冲区的情况

template <class BidirectionalIterator>
inline void inplace_merge(BidirectionalIterator first,
BidirectionalIterator middle,
BidirectionalIterator last) {
//其中一个序列为空,什么也不做
if (first == middle || middle == last) return;
__inplace_merge_aux(first, middle, last, value_type(first),
distance_type(first));
}
//辅助函数
template <class BidirectionalIterator, class T, class Distance>
inline void __inplace_merge_aux(BidirectionalIterator first,
BidirectionalIterator middle,
BidirectionalIterator last, T*, Distance*) {
Distance len1 = 0;
distance(first, middle, len1);
Distance len2 = 0;
distance(middle, last, len2);
//会使用额外的内存空间
temporary_buffer<BidirectionalIterator, T> buf(first, last);
if (buf.begin() == 0)//内存配置失败
__merge_without_buffer(first, middle, last, len1, len2);
else//在有暂时缓冲区的情况下进行
__merge_adaptive(first, middle, last, len1, len2,
buf.begin(), Distance(buf.size()));
}
//辅助函数,在有暂时缓冲区的情况下
template <class BidirectionalIterator, class Distance, class Pointer>
void __merge_adaptive(BidirectionalIterator first,
BidirectionalIterator middle,
BidirectionalIterator last, Distance len1, Distance len2,
Pointer buffer, Distance buffer_size) {
if (len1 <= len2 && len1 <= buffer_size) {
//case1:缓冲区足够安置序列一
Pointer end_buffer = copy(first, middle, buffer);
merge(buffer, end_buffer, middle, last, first);
}
else if (len2 <= buffer_size) {
//case2:缓冲区足够安置序列二
Pointer end_buffer = copy(middle, last, buffer);
__merge_backward(first, middle, buffer, end_buffer, last);
}
else {//case3:缓冲区不能安置任何一个序列
BidirectionalIterator first_cut = first;
BidirectionalIterator second_cut = middle;
Distance len11 = 0;
Distance len22 = 0;
if (len1 > len2) {//序列一比序列二长
len11 = len1 / 2;
advance(first_cut, len11);
second_cut = lower_bound(middle, last, *first_cut);
distance(middle, second_cut, len22);
}
else {//序列二比序列一长
len22 = len2 / 2;
advance(second_cut, len22);
first_cut = upper_bound(first, middle, *second_cut);
distance(first, first_cut, len11);
}
//旋转操作
BidirectionalIterator new_middle =
__rotate_adaptive(first_cut, middle, second_cut, len1 - len11,
len22, buffer, buffer_size);
//对左段递归调用
__merge_adaptive(first, first_cut, new_middle, len11, len22, buffer,
buffer_size);
//对右端递归调用
__merge_adaptive(new_middle, second_cut, last, len1 - len11,
len2 - len22, buffer, buffer_size);
}
}
template <class BidirectionalIterator1, class BidirectionalIterator2,
class Distance>
BidirectionalIterator1 __rotate_adaptive(BidirectionalIterator1 first,
BidirectionalIterator1 middle,
BidirectionalIterator1 last,
Distance len1, Distance len2,
BidirectionalIterator2 buffer,
Distance buffer_size) {
<span style="white-space:pre"> </span>BidirectionalIterator2 buffer_end;
<span style="white-space:pre"> </span>if (len1 > len2 && len2 <= buffer_size) {
<span style="white-space:pre"> </span>//缓冲区能安置序列二
<span style="white-space:pre"> </span>buffer_end = copy(middle, last, buffer);
<span style="white-space:pre"> </span>copy_backward(first, middle, last);
<span style="white-space:pre"> </span>return copy(buffer, buffer_end, first);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if (len1 <= buffer_size) {
<span style="white-space:pre"> </span>//缓冲区能安置序列一
<span style="white-space:pre"> </span>buffer_end = copy(first, middle, buffer);
<span style="white-space:pre"> </span>copy(middle, last, first);
<span style="white-space:pre"> </span>return copy_backward(buffer, buffer_end, last);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else  {
<span style="white-space:pre"> </span>//缓冲区不足,调用rotate()函数
<span style="white-space:pre"> </span>rotate(first, middle, last);
<span style="white-space:pre"> </span>advance(first, len2);
<span style="white-space:pre"> </span>return first;
<span style="white-space:pre"> </span>}
}

3、  图解说明

case 1:缓冲区足够安置序列一

【STL源码剖析读书笔记】【第6章】算法之inplace_merge算法

case 2:缓冲区足够安置序列二

【STL源码剖析读书笔记】【第6章】算法之inplace_merge算法

case 3:假设缓冲区大小为3,小于序列一的长度4和序列二的长度5,缓冲区不能安置任何一个序列

【STL源码剖析读书笔记】【第6章】算法之inplace_merge算法

 旋转操作后:

【STL源码剖析读书笔记】【第6章】算法之inplace_merge算法

左段递归调用:

【STL源码剖析读书笔记】【第6章】算法之inplace_merge算法

右端递归调用:

【STL源码剖析读书笔记】【第6章】算法之inplace_merge算法

排序完成。