【日常实现STL : partial_sort】

defautl version调用有user-defined compare functor的版本,并指定为std::less<>{}

std::adddress(std::declval<Tp>()) 作为param用于传递元信息(meta info)

仿照的是老式的泛型algorithm的实现(C ++ 11 左右),封装性低(没有iterator_traits,concepts & requires, decltype(auto)的适用等等),所以便于底层的impl insight的查看

template <typename RandomAccessIterator, typename Compare>
constexpr void partial_sort(
	RandomAccessIterator first,
	RandomAccessIterator middle,
	RandomAccessIterator last,
	Compare comp){

	__partial_sort(first, middle, last,
	std::addressof(typename std::iterator_traits<RandomAccessIterator>::value_type {})
    std::addressof(typename             std::iterator_traits<RandomAccessIterator>::difference_type{}),
std::addressof(comp));
}

template <typename RandomAccessIterator>
constexpr void partial_sort(
	RandomAccessIterator first,
	RandomAccessIterator middle,
	RandomAccessIterator last){
	return (void)(partial_sort(first, middle, last, std::less<>()));
}

 auxiliary function【__partial_sort function】的impl insight:

首先将range:[first, middle)之间的容器slice整理成max-heap

然后遍历range:[middle, last),在后面搜索比* first更小的元素,置为更合适的heap-top,然后shift-down(调用adjust_heap, 实质上为shift-down + push_heap), 然后调整range:[first, middle]再次成为max-heap

最终将整个容器中top-k构成的元素集合在range:[first, middle)中构成的max-heap进行排序(调用pop_heap)

template <typename RandomAccessIterator, typename Tp, typename Distance, typename Compare>
void __partial_sort(
	RandomAccessIterator first,
	RandomAccessIterator middle,
	RandomAccessIterator last,
    Tp * const,
    Distance * const,
	Compare * const,
	Tp * const){
	make_heap(first, middle, std::addressof(Compare{}));
	auto it { middle };
	while(!(it == last)){
		if(std::declval<Compare>()(*it, *first))
			__pop_heap(first, middle, it,
				Tp {*it},
				std::addressof(typename std::iterator_traits<RandomAccessIterator>::differenc_type {}),
				std::addressof(std::declval<Compare>()));
		it ++;
	}
    sort_heap(first, last, 
        std::addressof(Tp{}), 
        std::addressof(Distance {}), 
        std::addressof(std::declval<Compare>()));
}

make_heap从leaf-nodes的编号最后一个开始检查并调整,迭代地调整整个tree-like array(原容器的range:[first, middle)区间 ),直到第一个元素,此时容器切片被调整为一个天然的max-heap

template <typename RandomAccessIterator, typename Tp, typename Distance, typename Compare>
void __make_heap(
	RandomAccessIterator first,
	RandomAccessIterator last,
	Tp * const,
	Distance * const,
	Compare * const){
	Distance length { std::distance(first, last) };
	if(length < Distance {2U}) return;
	Distance parent { (length - 2) / 2 };
	do{
		__adjuct_heap(first, parent, length, Tp {*(first + parent)}, std::addressof(std::declval<Compare>()));
		parent --;
	}while(!(parent == Distance {0U}));
}

template <typename RandomAccessIterator, typename Tp, typename Distance, typename Compare>
constexpr void make_heap(
	RandomAccessIterator first,
	RandomAccessIterator last,
	Tp * const,
	Distance * const,
	Compare * const){
	__make_heap(first, last, std::addressof(Tp {}), std::addressof(Distance {}));
}

pop_heap 将* result赋值成* first(该max-heap的top), 并将此时的first position视作hole position进行逻辑删除,通过adjust_heap上浮调整失衡的堆

template <typename RandomAccessIterator, typename Tp, typename Distance, typename Compare>
constexpr void __pop_heap(
	RandomAccessIterator first,
	RandomAccessIterator last,
	RandomAccessIterator result,
	Tp && value,
	Distance * const,
	Compare * const){
	(void) std::exchange(*result, *first);
	__adjuct_heap(first, Distance {0U}, std::distance(first, last),
		std::forward<Tp>(value),
		std::addressof(std::declval<Compare>()));
}

 adjust_heap通过double-pointer的方法,沿着minimal-oriented路径,将堆上浮,调整原先heap的hole position,最终将给定的value填补到最后一个位置上,注意special-judge: second_child == length, 需要判断最后一个节点没有右子树的情况

template <typename RandomAccessIterator, typename Tp, typename Distance, typename Compare>
void __adjuct_heap(
	RandomAccessIterator first,
	Distance hole,
	Distance length,
	Tp && value,
	Compare * const){
	Distance top { hole };
	Distance second_child { 2U * hole + 2U };
	while(second_child < length){
		if(std::declval<Compare>()(*(first + second_child), *std::prev(first + second_child)))
			second_child --;
		(void) std::exchange(*(first + hole), *(first + second_child));
		hole = second_child;
		second_child = 2U * second_child + 2U;
	}
	if(second_child == length){
		(void) std::exchange(*(first + hole), *std::prev(first + second_child));
		hole = length - 1;
	}
	__push_heap(first, hole, top, std::forward<Tp>(value));
}

 push_heap先自底向上检查和调整max-heap, 最后把value赋值到* first的位置上

template <typename RandomAccessIterator, typename Tp, typename Distance, typename Compare>
void __push_heap(RandomAccessIterator first, Distance hole, Distance top, Tp && value, Compare * const){
	Distance parent { (hole - 1)/2 };
	while(hole > top && std::declval<Compare>()(*(first + parent), value)){
		(void) std::exchange(*(first + hole), *(first + parent));
		hole = parent;
		parent = (hole - 1U)/2U;
	}
	(void) std::exchange(*(first + hole), std::forward<Tp>(value));
}

sort_heap的实现思路很想random_shuffle,将max-node 置为最后一个,同时更新last,调整堆的大小,最终实现原线性空间自然有序

template <typename RandomAccessIterator, typename Tp, typename Distance, typename Compare>
void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Tp * const, Distance * const, Compare * const){
	while(std::distance(first, last) > Distance { 1U }){
		__pop_heap(first, last, std::prev(last), *last, std::addressof(Tp {}), std::addressof(Distance {}));
		std::advance(last, -1);
	}
}

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值