zoukankan      html  css  js  c++  java
  • 小根堆(Heap)的详细实现

    堆的介绍

    Heap是一种数据结构具有以下的特点:

    1)完全二叉树
    2)heap中存储的值是偏序

    Min-heap: 父节点的值小于或等于子节点的值

    Max-heap: 父节点的值大于或等于子节点的值

    图1

    堆的存储

    一般都用数组来表示堆,i结点的父结点下标就为(i–1)/2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。

    图2

    由于堆存储在下标从0开始计数的数组中,因此,在堆中给定下标为i的结点时:

    (1)如果i=0,结点i是根结点,无父结点;否则结点i的父结点为结点(i-1)/2;

    (2)如果2i+1>n-1,则结点i无左子女;否则结点i的左子女为结点2i+1;

    (3)如果2i+2>n-1,则结点i无右子女;否则结点i的右子女为结点2i+2。

    堆的操作:小根堆插入元素

    插入一个元素:新元素被加入到heap的末尾,然后更新树以恢复堆的次序。

    每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于直接插入排序中将一个数据并入到有序区间中。需要从下网上,与父节点的关键码进行比较,对调。

    图3

    堆的操作:删除小根堆堆的最小元素

    按定义,堆中每次都删除第0个数据。为了便于重建堆,实际的操作是将最后一个数据的值赋给根结点,堆的元素个数-1,然后再从根结点开始进行一次从上向下的调整。调整时先在左右儿子结点中找最小的,如果父结点比这个最小的子结点还小说明不需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点将一个数据的“下沉”过程。

    图4

    堆的操作:创建堆

    对于叶子节点,不用调整次序,根据满二叉树的性质,叶子节点比内部节点的个数多1.所以i=n/2 -1 ,不用从n开始。就是从最后一个有叶子结点的结点开始。

    堆排序

    如果从小到大排序,创建大堆建好之后堆中第0个数据是堆中最大的数据。取出这个数据,放在数组最后一个元素上,将当前元素数-1,再执行下堆的删除操作。这样堆中第0个数据又是堆中最大的数据,重复上述步骤直至堆中只有一个数据时,数组元素就已经有序。

    小根堆的实现

    #include <iostream>
    using namespace std;
    
    const int DefaultSize = 50;
    
    template<typename T>
    class MinHeap
    {
    public:
    	//构造函数:建立空堆
    	MinHeap(int sz=DefaultSize)
    	{
    		maxHeapSize = (DefaultSize < sz) ? sz : DefaultSize;
    		heap = new T[maxHeapSize];
    		currentSize = 0;
    	}
    
    	//构造函数通过一个数组建立堆
    	MinHeap(T arr[],int n)
    	{
    		maxHeapSize = (DefaultSize < n) ? n : DefaultSize;
    		heap = new T[maxHeapSize];
    		for(int i=0;i<n;i++)
    		{
    			heap[i] = arr[i];
    		}
    		currentSize = n;
    		int currentPos = (currentSize - 2) / 2;	//找最初调整位置:最后分支结点
    		while (currentPos>=0)	//自底向上逐步扩大形成堆
    		{
    			siftDowm(currentPos, currentSize - 1);	//局部自上向下下滑调整
    			currentPos--;	//再向前换一个分支结点
    		}
    	}
    
    	//将x插入到最小堆中
    	bool Insert(const T& x)
    	{
    		if(currentSize==maxHeapSize)
    		{
    			cout << "Heap Full!" << endl;
    			return false;
    		}
    		heap[currentSize] = x;	//插入
    		siftUp(currentSize);	//向上调整
    		currentSize++;	//堆计数+1
    		return true;
    	}
    
    	bool RemoveMin(T& x)
    	{
    		if(!currentSize)
    		{
    			cout << "Heap Empty!" << endl;
    			return false;
    		}
    		x = heap[0];	//返回最小元素
    		heap[0] = heap[currentSize - 1];	//最后元素填补到根结点
    		currentSize--;
    		siftDowm(0, currentSize - 1);	//自上向下调整为堆
    		return true;
    	}
    
    	void output()
    	{
    		for(int i=0;i<currentSize;i++)
    		{
    			cout << heap[i] << " ";
    		}
    		cout << endl;
    	}
    
    protected:
    
    	//最小堆的下滑调整算法
    	void siftDowm(int start, int end)	//从start到end下滑调整成为最小堆
    	{
    		int cur = start;
    		int min_child = 2 * cur + 1;	//先记max_child是cur的左子女位置
    		T temp = heap[cur];
    		while (min_child <=end)
    		{
    			if (min_child<end&&heap[min_child]>heap[min_child + 1])	//找到左右孩子中最小的一个
    				min_child++;
    
    			if(temp<=heap[min_child])
    				break;
    			else
    			{
    				heap[cur] = heap[min_child];
    				cur = min_child;
    				min_child = 2 * min_child + 1;
    			}
    		}
    		heap[cur] = temp;
    	}
    
    	//最小堆的上滑调整算法
    	void siftUp(int start)	//从start到0上滑调整成为最小堆
    	{
    		int cur = start;
    		int parent = (cur - 1) / 2;
    		T temp = heap[cur];
    		while (cur>0)
    		{
    			if(heap[parent]<=temp)
    				break;
    			else
    			{
    				heap[cur] = heap[parent];
    				cur = parent;
    				parent = (parent - 1) / 2;
    			}
    		}
    		heap[cur] = temp;	//回放temp中暂存的元素
    	}
    private:	//存放最小堆中元素的数组
    	T* heap;
    	int currentSize;	//最小堆中当前元素个数
    	int maxHeapSize;	//最小堆最多允许元素个数
    };
    
    //------------------------主函数-------------------------
    int main(int argc, char* argv[])
    {
    	MinHeap<int> h;
    	h.Insert(8);
    	h.Insert(5);
    	h.Insert(7);
    	h.Insert(9);
    	h.Insert(6);
    	h.Insert(12);
    	h.Insert(15);
    	h.output();
    
    	int out;
    	cout << static_cast<int> (h.RemoveMin(out)) << endl;
    	h.output();
    
    	int arr[10] = { 15,19,13,12,18,14,10,17,20,11 };
    	MinHeap<int> h1(arr,10);
    	h1.output();
    }
    
  • 相关阅读:
    Caffe_Example之训练mnist
    监督学习和无监督学习
    linux 命令cp拷贝
    Caffe solver.prototxt学习
    caffe下python环境的编译
    ubuntu 绘制lenet网络结构图遇到的问题汇总
    1-6 能否形成三角形
    Python的四个内置数据类型list, tuple, dict, set
    Python 函数(二)
    Python 函数(一)
  • 原文地址:https://www.cnblogs.com/WindSun/p/11444446.html
Copyright © 2011-2022 走看看