📄 priority_q.h
字号:
/* * Copyright 2003 Gilbert (Gang) Chen, Boleslaw K. Szymanski and * Rensselaer Polytechnic Institute. All worldwide rights reserved. * A license to use, copy, modify and distribute this software for * non-commercial research purposes only is hereby granted, provided * that this copyright notice and accompanying disclaimer is not * modified or removed from the software. * * DISCLAIMER: The software is distributed "AS IS" without any * express or implied warranty, including but not limited to, any * implied warranties of merchantability or fitness for a particular * purpose or any warranty of non-infringement of any current or * pending patent rights. The authors of the software make no * representations about the suitability of this software for any * particular purpose. The entire risk as to the quality and * performance of the software is with the user. Should the software * prove defective, the user assumes the cost of all necessary * servicing, repair or correction. In particular, neither Rensselaer * Polytechnic Institute, nor the authors of the software are liable * for any indirect, special, consequential, or incidental damages * related to the software, to the maximum extent the law permits. */#ifndef PRIORITY_QUEUE_H#define PRIORITY_QUEUE_H/* Five Priority Queues: SimpleQueue: Double Linked list GuardedQueue: Derived from SimpleQueue, checks before EnQueue() and Delete() ErrorQueue: Derived from SimpleQueue, only correct half of the time (for debugging) HeadQueue: Implicit Heap CalendarQueue: The fastest Last Modified: Nov 18, 2002 by Gilbert Chen */template < class ITEM >class SimpleQueue { public: SimpleQueue() :m_head(NULL) {}; void EnQueue(ITEM*); ITEM* DeQueue(); void Delete(ITEM*); ITEM* NextEvent() const { return m_head; }; const char* GetName(); protected: ITEM* m_head;};template <class ITEM>const char* SimpleQueue<ITEM>::GetName(){ static const char* name = "SimpleQueue"; return name;}template <class ITEM>void SimpleQueue<ITEM>::EnQueue(ITEM* item){ if( m_head==NULL || item->time < m_head->time ) { if(m_head!=NULL)m_head->prev=item; item->next=m_head; m_head=item; item->prev=NULL; return; } ITEM* i=m_head; while( i->next!=NULL && item->time > i->next->time) i=i->next; item->next=i->next; if(i->next!=NULL)i->next->prev=item; i->next=item; item->prev=i;}template <class ITEM>ITEM* SimpleQueue<ITEM> ::DeQueue(){ if(m_head==NULL)return NULL; ITEM* item = m_head; m_head=m_head->next; if(m_head!=NULL)m_head->prev=NULL; return item;}template <class ITEM>void SimpleQueue<ITEM>::Delete(ITEM* item){ if(item==NULL) return; if(item==m_head) { m_head=m_head->next; if(m_head!=NULL)m_head->prev=NULL; } else { item->prev->next=item->next; if(item->next!=NULL) item->next->prev=item->prev; }}template <class ITEM>class GuardedQueue : public SimpleQueue<ITEM>{ public: void Delete(ITEM*); void EnQueue(ITEM*); bool Validate(const char*);};template <class ITEM>void GuardedQueue<ITEM>::EnQueue(ITEM* item){// mwl gcc 4.0 requires the "SimpleQueue<ITEM>::" ITEM* i=SimpleQueue<ITEM>::m_head; while(i!=NULL) { if(i==item) { pthread_printf("queue error: item %f(%p) is already in the queue\n",item->time,item); } i=i->next; } SimpleQueue<ITEM>::EnQueue(item);}template <class ITEM>void GuardedQueue<ITEM>::Delete(ITEM* item){ ITEM* i=SimpleQueue<ITEM>::m_head; while(i!=item&&i!=NULL) i=i->next; if(i==NULL) pthread_printf("error: cannot find the to-be-deleted event %f(%p)\n",item->time,item); else SimpleQueue<ITEM>::Delete(item);}template <class ITEM>bool GuardedQueue<ITEM>::Validate(const char* s){ char out[1000],buff[100]; ITEM* i=SimpleQueue<ITEM>::m_head; bool qerror=false; sprintf(out,"queue error %s : ",s); while(i!=NULL) { sprintf(buff,"%f ",i->time); strcat(out,buff); if(i->next!=NULL) if(i->next->prev!=i) { qerror=true; sprintf(buff," {broken} "); strcat(out,buff); } if(i==i->next) { qerror=true; sprintf(buff,"{loop}"); strcat(out,buff); break; } i=i->next; } if(qerror) printf("%s\n",out); return qerror;}template <class ITEM>class ErrorQueue : public SimpleQueue<ITEM>{ public: ITEM* DeQueue(double); const char* GetName();};template <class ITEM>const char* ErrorQueue<ITEM>::GetName(){ static const char* name = "ErrorQueue"; return name;}template <class ITEM>ITEM* ErrorQueue<ITEM> ::DeQueue(double stoptime){ //Validate("Before DeQueue()"); if(drand48()>0.5) return SimpleQueue<ITEM>::DeQueue(); int s=0; ITEM* e; e=SimpleQueue<ITEM>::m_head; while(e!=NULL&&e->time<stoptime) { s++; e=e->next; } e=SimpleQueue<ITEM>::m_head; s=(int)(s*drand48()); while(s!=0) { e=e->next; s--; } Delete(e); return e;}template < class ITEM >class HeapQueue { public: HeapQueue(); ~HeapQueue(); void EnQueue(ITEM*); ITEM* DeQueue(); void Delete(ITEM*); const char* GetName(); ITEM* NextEvent() const { return num_of_elems?elems[0]:NULL; }; private: void SiftDown(int); void PercolateUp(int); void Validate(const char*); ITEM** elems; int num_of_elems; int curr_max;};template <class ITEM>const char* HeapQueue<ITEM>::GetName(){ static const char* name = "HeapQueue"; return name;}template <class ITEM>void HeapQueue<ITEM>::Validate(const char* s){ int i,j; char out[1000],buff[100]; for(i=0;i<num_of_elems;i++) if( ((2*i+1)<num_of_elems&&elems[i]->time>elems[2*i+1]->time) || ((2*i+2)<num_of_elems&&elems[i]->time>elems[2*i+2]->time) ) { sprintf(out,"queue error %s : ",s); for(j=0;j<num_of_elems;j++) { if(i!=j) sprintf(buff,"%f(%d) ",elems[j]->time,j); else sprintf(buff,"{%f(%d)} ",elems[j]->time,j); strcat(out,buff); } printf("%s\n",out); }}template <class ITEM>HeapQueue<ITEM>::HeapQueue(){ curr_max=16; elems=new ITEM*[curr_max]; num_of_elems=0;}template <class ITEM>HeapQueue<ITEM>::~HeapQueue(){ delete [] elems;}template <class ITEM>void HeapQueue<ITEM>::SiftDown(int node){ if(num_of_elems<=1) return; int i=node,k,c1,c2; ITEM* temp; do{ k=i; c1=c2=2*i+1; c2++; if(c1<num_of_elems && elems[c1]->time < elems[i]->time) i=c1; if(c2<num_of_elems && elems[c2]->time < elems[i]->time) i=c2; if(k!=i) { temp=elems[i]; elems[i]=elems[k]; elems[k]=temp; elems[k]->pos=k; elems[i]->pos=i; } }while(k!=i);}template <class ITEM>void HeapQueue<ITEM>::PercolateUp(int node){ int i=node,k,p; ITEM* temp; do{ k=i; if( (p=(i+1)/2) != 0) { --p; if(elems[i]->time < elems[p]->time) { i=p; temp=elems[i]; elems[i]=elems[k]; elems[k]=temp; elems[k]->pos=k; elems[i]->pos=i; } } }while(k!=i);}template <class ITEM>void HeapQueue<ITEM>::EnQueue(ITEM* item){ if(num_of_elems>=curr_max) { curr_max*=2; ITEM** buffer=new ITEM*[curr_max]; for(int i=0;i<num_of_elems;i++) buffer[i]=elems[i]; delete[] elems; elems=buffer; } elems[num_of_elems]=item; elems[num_of_elems]->pos=num_of_elems; num_of_elems++; PercolateUp(num_of_elems-1);}template <class ITEM>ITEM* HeapQueue<ITEM>::DeQueue(){ if(num_of_elems<=0)return NULL; ITEM* item=elems[0]; num_of_elems--; elems[0]=elems[num_of_elems]; elems[0]->pos=0; SiftDown(0); return item;}template <class ITEM>void HeapQueue<ITEM>::Delete(ITEM* item){ int i=item->pos; num_of_elems--; elems[i]=elems[num_of_elems]; elems[i]->pos=i; SiftDown(i); PercolateUp(i);}#define CQ_MAX_SAMPLES 25template <class ITEM>class CalendarQueue { public: CalendarQueue(); const char* GetName(); ~CalendarQueue(); void enqueue(ITEM*); ITEM* dequeue(); void EnQueue(ITEM*); ITEM* DeQueue(); ITEM* NextEvent() const { return m_head;} void Delete(ITEM*); private: long last_bucket,number_of_buckets; double bucket_width; void ReSize(long); double NewWidth(); ITEM ** buckets; long total_number; double bucket_top; long bottom_threshold; long top_threshold; double last_priority; bool resizable; ITEM* m_head; char m_name[100];};template <class ITEM>const char* CalendarQueue<ITEM> :: GetName(){ sprintf(m_name,"Calendar Queue (bucket width: %.2e, size: %ld) ", bucket_width,number_of_buckets); return m_name;}template <class ITEM>CalendarQueue<ITEM>::CalendarQueue(){ long i; number_of_buckets=16; bucket_width=1.0; bucket_top=bucket_width; total_number=0; last_bucket=0; last_priority=0.0; top_threshold=number_of_buckets*2; bottom_threshold=number_of_buckets/2-2; resizable=true; buckets= new ITEM*[number_of_buckets]; for(i=0;i<number_of_buckets;i++) buckets[i]=NULL; m_head=NULL;}template <class ITEM>CalendarQueue<ITEM>::~CalendarQueue(){ delete [] buckets;}template <class ITEM>void CalendarQueue<ITEM>::ReSize(long newsize){ long i; ITEM** old_buckets=buckets; long old_number=number_of_buckets; resizable=false; bucket_width=NewWidth(); buckets= new ITEM*[newsize]; number_of_buckets=newsize; for(i=0;i<newsize;i++) buckets[i]=NULL; last_bucket=0; total_number=0; //printf("Resize to width=%e and size=%ld\n",bucket_width,newsize); ITEM *item; for(i=0;i<old_number;i++) { while(old_buckets[i]!=NULL) { item=old_buckets[i]; old_buckets[i]=item->next; enqueue(item); } } resizable=true; delete[] old_buckets; number_of_buckets=newsize; top_threshold=number_of_buckets*2; bottom_threshold=number_of_buckets/2-2; bucket_top=bucket_width*((long)(last_priority/bucket_width)+1)+bucket_width*0.5; last_bucket = long(last_priority/bucket_width) % number_of_buckets;}template <class ITEM>ITEM* CalendarQueue<ITEM>::DeQueue(){ ITEM* head=m_head; m_head=dequeue(); return head;}template <class ITEM>ITEM* CalendarQueue<ITEM>::dequeue(){ long i; for(i=last_bucket;;) { if(buckets[i]!=NULL&&buckets[i]->time<bucket_top) { ITEM * item=buckets[i]; buckets[i]=buckets[i]->next; total_number--; last_bucket=i; last_priority=item->time; if(resizable&&total_number<bottom_threshold) ReSize(number_of_buckets/2); item->next=NULL; return item; } else { i++; if(i==number_of_buckets)i=0; bucket_top+=bucket_width; if(i==last_bucket) break; } } /* Start Direct Search */ long smallest; for(smallest=0;smallest<number_of_buckets;smallest++) if(buckets[smallest]!=NULL)break; if(smallest >= number_of_buckets) { last_priority=bucket_top; return NULL; } for(i=smallest+1;i<number_of_buckets;i++) { if(buckets[i]==NULL) continue; else if(buckets[i]->time<buckets[smallest]->time) smallest=i; } ITEM * item=buckets[smallest]; buckets[smallest]=buckets[smallest]->next; total_number--; last_bucket=smallest; last_priority=item->time; bucket_top=bucket_width*((long)(last_priority/bucket_width)+1)+bucket_width*0.5; item->next=NULL; return item;}template <class ITEM>void CalendarQueue<ITEM>::EnQueue(ITEM* item){ //printf("Enqueue %f\n",item->time); if(m_head==NULL) { m_head=item; return; } if(m_head->time>item->time) { enqueue(m_head); m_head=item; } else enqueue(item);}template <class ITEM>void CalendarQueue<ITEM>::enqueue(ITEM* item){ long i; if(item->time<last_priority) { i=(long)(item->time/bucket_width); last_priority=item->time; bucket_top=bucket_width*(i+1)+bucket_width*0.5; i=i%number_of_buckets; last_bucket=i; } else { i=(long)(item->time/bucket_width); i=i%number_of_buckets; } /*Insert into buckets[i] */ if(buckets[i]==NULL||item->time<buckets[i]->time) { item->next=buckets[i]; buckets[i]=item; } else { ITEM* pos=buckets[i]; while(pos->next!=NULL&&item->time>pos->next->time) { pos=pos->next; } item->next=pos->next; pos->next=item; } total_number++; if(resizable&&total_number>top_threshold) ReSize(number_of_buckets*2);}template <class ITEM>void CalendarQueue<ITEM>::Delete(ITEM* item){ if(item==m_head) { m_head=dequeue(); return; } long j; j=(long)(item->time/bucket_width); j=j%number_of_buckets; /*remove from buckets[j] */ // the address of the pointer that points // to the current item ITEM** p = &buckets[j]; // the current item ITEM* i=buckets[j]; while(i!=NULL) { if(i==item) { /* got it */ (*p)=item->next; total_number--; if(resizable&&total_number<bottom_threshold) ReSize(number_of_buckets/2); return; } p=&(i->next); i=i->next; } }template <class ITEM>double CalendarQueue<ITEM>::NewWidth(){ long i, nsamples; if(total_number<2) return 1.0; if(total_number<=5) nsamples=total_number; else nsamples=5+total_number/10; if(nsamples>CQ_MAX_SAMPLES) nsamples=CQ_MAX_SAMPLES; long _last_bucket=last_bucket; double _bucket_top=bucket_top; double _last_priority=last_priority; double AVG[CQ_MAX_SAMPLES],avg1=0,avg2=0; ITEM* list,*next,*item; list=dequeue(); long real_samples=0; while(real_samples<nsamples) { item=dequeue(); if(item==NULL) { item=list; while(item!=NULL) { next=item->next; enqueue(item); item=next; } last_bucket=_last_bucket; bucket_top=_bucket_top; last_priority=_last_priority; return 1.0; } AVG[real_samples]=item->time-list->time; avg1+=AVG[real_samples]; if(AVG[real_samples]!=0.0) real_samples++; item->next=list; list=item; } item=list; while(item!=NULL) { next=item->next; enqueue(item); item=next; } last_bucket=_last_bucket; bucket_top=_bucket_top; last_priority=_last_priority; avg1=avg1/(double)(real_samples-1); avg1=avg1*2.0; //printf("avg1: %le\n",avg1); long count=0; for(i=0;i<real_samples-1;i++) { if(AVG[i]<avg1&&AVG[i]!=0) { avg2+=AVG[i]; count++; } } if(count==0||avg2==0) return 1.0; avg2 /= (double) count; avg2 *= 3.0; return avg2;}#endif /*PRIORITY_QUEUE_H*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -