STL堆实现

逻辑

堆是一种用数组模拟完全二叉树的结构
完全二叉树:只有最后一层是不满的,其他层都是满的,而且最后一层左满又不满
如果一个结点的位置为k,则它的父节点的位置为k/2,左子节点位置2k,右子结点2k+1
堆规定父节点大于子节点,对子节点之间的大小不做要求

代码实现

#ifndef Heap
#define Heap
using namespace std;
template <class RandomAccessIterator, class T>
//下沉操作
void _adjust_heaps(RandomAccessIterator first, int holeIndex, int len, T value){
    //找到左节点和右节点中最大的
    //与父节点比较如果大则交换
    int maxchild = holeIndex * 2 + 2;//先假设右子结点大
    //有右子结点
    while(maxchild < len){
        //比较两个子节点的大小
        if(*(first + maxchild) < *(first + maxchild - 1)){
            maxchild--;
        }
        //如果子节点大于父节点,将子节点的值填入洞内
        if(*(first + maxchild) > value)
            *(first + holeIndex) = *(first + maxchild);
        //已经找到合适的位置
        else{
            *(first + holeIndex) = value;
            return;
        }
        //没找到合适的位置,继续循环
        holeIndex = maxchild;
        maxchild = holeIndex * 2 + 2;

    }
    //只有左子结点(此时洞结点为最后一个父节点)
    if(maxchild == len){
        //如果子节点大于父节点,将子节点的值填入洞内
        if(*(first + maxchild - 1) > value){
            *(first + holeIndex) = *(first + maxchild - 1);
            holeIndex = maxchild -1;
        }
    }
    //根据上面if的结果,将value放到最后一个子结点或最后一个父节点
    *(first + holeIndex) = value;
}
// 將 [first,last) 排列為一個 heap。
template <class RandomAccessIterator>
inline void make_heaps(RandomAccessIterator first, RandomAccessIterator last) {
	if (last - first < 2) return;	// 如果長度為 0 或 1,不必重新排列。
	int len = last - first;
	// 找出第一個需要重排的子樹頭部,以 parent 標示出。由於任何葉節點都不需執行
	// perlocate down,所以有以下計算。parent 命名不佳,名為 holeIndex 更好。
	int parent = (len - 2) / 2;

	while (true) {
		// 重排以 parent 為首的子樹。len 是為了讓 __adjust_heap() 判斷操作範圍
		_adjust_heaps(first, parent, len, *(first + parent));
		if (parent == 0) return;	// 走完根節點,就結束。
		parent--;// (即將重排之子樹的)頭部向前一個節點
    }
}

template <class RandomAccessIterator, class Distance, class T>
void push_heaps(RandomAccessIterator first, RandomAccessIterator last){
    //插入的元素在最后一个节点
    //索引为(last - first) - 1,值为*(last - 1)
    Distance holeIndex = (last - first) - 1;
    //找到父节点
    Distance parent = (holeIndex - 1) / 2;
    T value = *(first + holeIndex);
    //没到最上层且子节点大于父节点,上浮
    while(parent > 0 && value > *(first + parent)){
        *(first + parent) = value;
        //调整洞节点到父节点
        holeIndex = parent;
        //调整父节点
        parent = (holeIndex-1) / 2;
    }
    //调整完毕已经找到位置或到了顶端
    *(first + holeIndex) = value;

}
template <class RandomAccessIterator>
void pop_heaps(RandomAccessIterator first, RandomAccessIterator last){
    //将尾值和首值互换
    RandomAccessIterator result;
    *result = *first;
    *first = *(last - 1);
    *(last - 1) = *result;
    //调整堆
    _adjust_heaps(first, 0, last - first - 1, *first);
}

//堆排序
template <class RandomAccessIterator>
void sort_heaps(RandomAccessIterator first, RandomAccessIterator last){
    //只需不断的对堆中元素进行pop操作,
    //pop操作中将堆顶元素也就是最大元素放入最后
    while(last - first > 1)
        pop_heaps(first, last--);
}

#endif // Heap

©️2020 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值