手写priority queue

要求:

1、完成priority queue的基本功能
2、在至多logn的时间复杂度合并两个priority queue

基本功能(顺序存储)

#ifndef SJTU_PRIORITY_QUEUE_HPP
#define SJTU_PRIORITY_QUEUE_HPP

#include <cstddef>
#include <functional>
#include "exceptions.hpp"
#include<iostream>
namespace sjtu {
	
//  a container like std::priority_queue which is a heap internal.
//用cmp!!!Compare函数! 
template<typename T, class Compare = std::less<T>>
class priority_queue {
	private:
		T *data;
		int siz,capacity;
		void DoubleSpace(){
			if(capacity==0) {
				capacity = 5 ;
				data = (T *) malloc(sizeof(T)*capacity);
				return ;
			}
			capacity *= 2;
			T *data2 = (T *)malloc(sizeof(T)*capacity);
			for(int i=1;i<=siz;i++){//注意这里siz < capacity/2! 
				new(data2+i)T(data[i]);
			}
			for(int i=1;i<=siz;i++){
				data[i].~T();
			}
			free(data);
			data = data2;
		}
	public:
		// TODO constructors
		priority_queue(int maxsize = 5) {
			siz = 0;
//			capacity = 0;//不能不初始化!!!!capacity=0要写!! 
//			DoubleSpace();//或者采用未注释的写法 
			data = (T *)malloc (sizeof(T)*maxsize); 
			capacity = maxsize;
		}
		priority_queue(const priority_queue &other) {//copy constructor
			data = (T *) malloc(sizeof(T)*other.capacity);
			for(int i=1;i<=other.siz ;i++){
				new(data+i)T(other.data[i]);
			}
			capacity = other.capacity ;
			siz = other.siz ;
		}
		
		//TODO deconstructor
		~priority_queue() {
			for(int i=1;i<=siz;i++){
				data[i].~T();
			}
			free(data);
			siz = 0;
			capacity = 0;
			data = NULL;
		}
		
		//TODO Assignment operator
		priority_queue &operator=(const priority_queue &other) {
			if(this == &other) return *this;
			for(int i=1;i<=siz;i++){
				data[i].~T();
			}
			if(other.siz > capacity){
				free(data);
				data = (T *)malloc(sizeof(T)*other.capacity);
				capacity = other.capacity;
			}
			for(int i=1;i<=other.siz;i++){
				new(data+i)T(other.data[i]);
			}
			siz = other.siz;
			return *this;
		}
		
		/* get the top of the queue.
		 * @return a reference of the top element.
		 * throw container_is_empty if empty() returns true;
		 */
		const T & top() const {
			if(empty()) throw container_is_empty();
			return data[1];
		}
		
		// push new element to the priority queue.
		void push(const T &e) {//大顶堆
			if(siz>=capacity-1) 
				DoubleSpace();
			siz ++;
			int hole = siz;
			new(data+hole)T(e);//是这里,要写一个构造的而不是重载等于,因为本身没有T类型的变量 
			while(hole>1 && Compare()(data[hole>>1],e)){
				data[hole] = data[hole>>1];//不需要重复析构,因为在T类型重载等号已经写了 
				hole = hole>>1;
			} 
			data[hole] = e;
		}
		/* delete the top element.
		 * throw container_is_empty if empty() returns true;
		 */
		void pop() {
			if(siz==0) throw container_is_empty(); 
			int hole = 1;
			while(hole*2 < siz){//至少有一个儿子在下面呀! 
				int child = hole<<1;
				if(child+1<siz && Compare()(data[child],data[child+1])){
					child++;
				}
				if(Compare()(data[child],data[siz])) break;
				data[hole] = data[child];
				hole = child;
			}
			data[hole] = data[siz];
			data[siz].~T();
			siz--;
		}
		// return the number of the elements.
		size_t size() const {
			return siz;
		}
		/* check if the container has at least an element.
		 * @return true if it is empty, false if it has at least an element.
		 */
		bool empty() const {
			if(siz) return false;
			return true;
		}
	};
}

#endif
  • Compare函数来确定是大顶堆还是小顶堆!这里是大顶堆
  • 没法实现logn的合并
  • doublespace的时候特别注意sizcapacity的关系,因为进入doublespace的时候siz = capacity-1(申请5个空间,0不能用,只能放四个值),不管是析构还是复制都要小心,判别是否进入doublespace时也要小心
  • 顺序存储特别注意构造和析构,什么时候写构造什么时候写赋值(赋值是可能析构掉原来的,看具体的实现),析构是你做还是赋值的时候做,析构时要不要一起析构掉空间……都很重要

连接存储(左堆)

 #ifndef SJTU_PRIORITY_QUEUE_HPP
#define SJTU_PRIORITY_QUEUE_HPP

#include <cstddef>
#include <functional>
#include "exceptions.hpp"

namespace sjtu {
/**
 * a container like std::priority_queue which is a heap internal.
 */
template<typename T, class Compare = std::less<T>>
class priority_queue {
	private:
		struct Node{
			Node *left,*right;
			T *data;
			int npl;
			Node(const T &x,Node *l = NULL,Node *r = NULL){
				data = new T(x);
				left = l;
				right = r;
				npl = -1;
			}
			~Node(){
				if(data) delete data;//易忘if 
				left = NULL;
				right = NULL;
			}
		}; 
		Node *head;
		int siz; 
		Node *copy(Node *q){
			Node *p = new Node(*(q->data));
			if(q->left){
				p->left = copy(q->left);
			}
			if(q->right){
				p->right = copy(q->right);
			}
			return p;
		}
		void clear(Node *p){//有可能clear的时候本身就是p==NULL!! 
			if(p==NULL) return ;
			if(p->left) 
				clear(p->left);
			if(p->right)
				clear(p->right);
			delete p;
			return ;
		}
		void getnpl(Node *u){
			if(u==NULL) {//npl=-1
				return ;
			}
			if(u->left==NULL || u->right==NULL) {
				u->npl = 0;
				return ;
			}
			int x,y;
			if(u->left!=NULL && u->left->npl == -1) 
				getnpl(u->left);
			if(u->right!=NULL && u->right->npl == -1) 
				getnpl(u->right);
			if(u->left->npl < u->right->npl)
				u->npl = u->left->npl+1;
			else u->npl = u->right->npl+1;
			return;
		}
		void check(Node *u){
			getnpl(u);
			if(u->left==NULL || u->left->npl < u->right->npl){
				Node *tmp = u->left;
				u->left = u->right;
				u->right = tmp;
			}
			return ;
		}
		Node *merge(Node *u,Node *v,Node *fau,Node *fav){//考虑一下合并后u原先的father还指着它! 
			if(u==NULL) return v;
			if(v==NULL) return u;
			Node *fa = fau;
			//85-86行先声明Compare类型变量再用重载的括号,和直接写if(Compare()(*(v->data),*(u->data)))效果一样 
			Compare cmp;
			if(cmp(*(v->data),*(u->data))){
				Node *tmp = u;
				u = v;
				v = tmp;
				fa = fav;
			}//u是小的 ,用u和v的右子树合并
			if(v->right == NULL){
				v->right = u;
				check(v);
				return v;
			} 
			v->right = merge(u,v->right,fau,v);
			check(v);
			if(fa==NULL) return v;
			if(fa->left == u) fa->left = NULL;
			if(fa->right ==v) fa->right = NULL;
			return v;
		}
	public:
		priority_queue() {
			siz = 0;
			head = NULL;
		}
		priority_queue(const priority_queue &other) {
			siz = other.siz ;
			head = copy(other.head);
		}
		~priority_queue() {
			clear(head);
			head = NULL;
			siz = 0; 
		}
		priority_queue &operator=(const priority_queue &other) {
			if(this == &other) return *this;//易忘 
			clear(head);
			siz = other.siz ;
			head = copy(other.head);
			return *this; //易忘 
		}
		const T & top() const {
			if(empty()) throw container_is_empty();
			return *(head->data);
		}
		void push(const T &e) {
			Node *tmp = new Node(e);
			head = merge(head,tmp,NULL,NULL);//特判放在merge里面做了 
			siz ++;
		}
		void pop() {
			if(empty()) throw container_is_empty();
			Node *tmp = head;
			head = merge(head->left,head->right,NULL,NULL);
			delete tmp;
			siz--;
		}
		size_t size() const {
			return siz;
		}
		bool empty() const {
			return siz==0;
		}
		/**
		 * merge two priority_queues with at least O(logn) complexity.
		 * clear the other priority_queue.
		 */
		void merge(priority_queue &other) {//传的参数是堆,里面的函数传进去结点 
			 head = merge(head,other.head,NULL,NULL); 
			 siz += other.siz;
			 other.head = NULL;
			 other.siz = 0;
			 return ;
		}
	};
}

#endif
  • 写好了merge和其他private函数以后public写起来很舒服哎!
  • 关于Compare的用法:Comparecode实现里面是一个结构体cmp,使用的时候可以先声明一个Compare实例,然后再用重载的调用运算符即括号,来使用cmp操作;也可以写一个语句即if(Compare()(*(v->data),*(u->data))),第一个空括号表示构造一个Compare类型的实例,第二个括号才表示使用这个重载的调用运算符。
  • 注意merge里面的特判……如果传进去俩NULL咋整?
  • check也记得特判,很有可能u->left就是NULL,你用->left->data就会377
  • npl要用一定程度的记忆化,否则每次都搜会超时,虽然我用的记忆化方法也不是很快,但是好歹没有TLE
  • 其他特别特别容易写忘记的点:
    delete之前先判是不是NULL,不是再delete
    重载等号的时候,开头的判if(this==&other),尾巴的return *this;
  • 以后做题前能不能先看看题,要用顺序还是链接,就不至于像这次一样两个都写……
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值