zoukankan      html  css  js  c++  java
  • 【STL源码剖析读书笔记】【第6章】算法之inplace_merge算法

    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:缓冲区足够安置序列一


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


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


     旋转操作后:


    左段递归调用:


    右端递归调用:


    排序完成。



  • 相关阅读:
    能成大事儿的人,都具备这5个特质
    元气森林唐彬森:苦了10年我发现,发大财首先要会选
    反者道之动,亿万富翁查理芒格受用一生的逆向思维
    解决不了bug先放着,这里有40条提升编程技能小妙招
    理解maven命令package、install、deploy的联系与区别
    每日一则
    《穷查理年鉴》贪嗔痴 & 懒贪装(关于败坏)
    C++构造函数
    C++类的定义和封装
    C++访问控制限定符
  • 原文地址:https://www.cnblogs.com/ruan875417/p/4558296.html
Copyright © 2011-2022 走看看