zoukankan      html  css  js  c++  java
  • 堆-优先队列[数组]

    堆和优先队列

    分大顶堆和小顶堆,这里实现的是小顶堆,也就是说父亲节点一定小于孩子节点,不像二叉排序树这样,堆对子节点之间的大小没有限制,限制的仅仅只有一个条件,父亲一定比孩子节点小,这就是小顶堆,大顶堆则相反

    优先队列:堆中的每个元素都带有一个优先级,入队是无序的,出队是有序的,排序过程只需要在每步插入和删除都平衡一下堆就够了,所以有种排序算法叫堆排序

    代码实现

    结构

    这里用数组实现,length代表堆数组的长度,注意这里的树形结构是完全二叉树结构

    int Heap[MAX]={0};
    int length = 0;	
    

    寻找父亲和孩子节点

    这里反回的是节点的索引

    int parent(int j){
    	if(j>0){
    		return (j-1)/2;  //返回当前节点父亲的位置 		
    	} 
    	return -1;  //返回当前节点父亲的位置 
    }
    
    int left(int j){
    	return j*2+1;
    }
    int right(int j){
    	return j*2+2;
    }
    

    元素上浮

    上浮操作发生在插入的时候,因为插入永远都是从尾部插入,为了平衡堆,所以需要将插入的元素 上浮到符合小顶堆的位置

    //上浮 
    void up(int j){
    	if(j>0 && Heap[j]<Heap[parent(j)]){ //如果比父母小 
    		swap(Heap[j],Heap[parent(j)]);// 交换 
    		up(parent(j)); //递归 
    	} 
    }
    

    元素下沉

    下沉操作发生在删除元素的时候,因为删除元素的逻辑是将堆顶元素和尾部元素替换,注意,堆顶元素永远都是整个堆的最小的元素

    那为什么要和尾部元素替换呢?为了方便堆顶元素的移除,尾部元素移除很方便快速

    将尾部元素替换到堆顶后,可能会打破平衡,所以需要将刚替换的堆顶元素下沉

    //下沉 
    void down(int j){
    	//堆是一颗完全二叉树 先有左边 再有右边 
    	if(has_left(j)){
    		int small = left(j);
    		if(has_right(j))
    			if(Heap[small]>Heap[right(j)])
    				small = right(j);
    		
    			
    		if(Heap[small]<Heap[j]){
    			swap(Heap[small],Heap[j]);
    			down(small); //递归 
    		}
    	}
    } 
    

    添加和删除

    //添加 
    void add(int val){
    	Heap[length++] = val;
    	up(length-1); //将新元素上浮	
    }
    
    //删除 取堆顶元素 
    int remove(){
    	
    	swap(Heap[0],Heap[length-1]);//先和最后一个换 再删除
    	int r = Heap[--length]; //返回结果 
    	
    	down(0);  //堆顶下沉
    	return r; 
    } 
    

    取最小值

    int get_min(){
    	if(length>0){
    		return Heap[0];
    	}else{
    		return -1;
    	}
    }
    

    所有可执行代码

    #include <iostream>
    using namespace std;
    #define MAX 100
    
    int Heap[MAX]={0};
    int length = 0;	
    
    int parent(int j){
    	if(j>0){
    		return (j-1)/2;  //返回当前节点父亲的位置 		
    	} 
    	return -1;  //返回当前节点父亲的位置 
    }
    
    int left(int j){
    	return j*2+1;
    }
    int right(int j){
    	return j*2+2;
    }
    
    
    bool has_left(int j){
    	return left(j)<length; 
    }
    bool has_right(int j){
    	return right(j)<length;
    }
    
    //上浮 
    void up(int j){
    	if(j>0 && Heap[j]<Heap[parent(j)]){ //如果比父母小 
    		swap(Heap[j],Heap[parent(j)]);// 交换 
    		up(parent(j)); //递归 
    	} 
    }
    
    //下沉 
    void down(int j){
    	//堆是一颗完全二叉树 先有左边 再有右边 
    	if(has_left(j)){
    		int small = left(j);
    		if(has_right(j))
    			if(Heap[small]>Heap[right(j)])
    				small = right(j);
    		
    			
    		if(Heap[small]<Heap[j]){
    			swap(Heap[small],Heap[j]);
    			down(small); //递归 
    		}
    	}
    } 
    
    int get_min(){
    	if(length>0){
    		return Heap[0];
    	}else{
    		return -1;
    	}
    } 
    
    //添加 
    void add(int val){
    	Heap[length++] = val;
    	up(length-1); //将新元素上浮	
    }
    
    //删除 取堆顶元素 
    int remove(){
    	
    	swap(Heap[0],Heap[length-1]);//先和最后一个换 再删除
    	int r = Heap[--length]; //返回结果 
    	
    	down(0);  //堆顶下沉
    	return r; 
    } 
    
    
    
    
    
    
    
    int main(int argc, char *argv[])
    {
    	add(43); 
    	add(53);
    	add(4);
    	add(3);
    	add(9);
    	add(100);
    
    	cout<<remove()<<endl;
    	cout<<remove()<<endl;
    	cout<<remove()<<endl;
    	cout<<remove()<<endl;
    	cout<<remove()<<endl;
    	cout<<remove()<<endl;
    	
    	cout<<"----------"<<endl; 
    
    	return 0;
    }
    
  • 相关阅读:
    如何稳定地使用 Google 搜索https://encrypted.google.com/
    widows 2008 同步时间命令
    MySql 初始化权限脚本
    [转] windows下Svn服务器之必须提交修改注释篇
    给编译好的DLL增加签名
    Anychart 破解备注
    Javascript 日期时间格式正则
    微服务项目规范(二)
    微服务项目规范(一)
    mac系统安装、启动与关闭redis
  • 原文地址:https://www.cnblogs.com/biningooginind/p/12536701.html
Copyright © 2011-2022 走看看