/**************************************************************************** | HEADER FILE FOR THE priority MODULE (priority.h) | | EXPORTED ITEMS: | CompleteBinaryTree Class: | A complete binary tree. Each node in the tree contains data of type | DataAtOneNode. | | template | class PriorityQueue | A priority queue of entries. Each entry in the priority queue has type | Entry, and has a priority of type int. | | METHODS FOR THE CompleteBinaryTree CLASS | | CompleteBinaryTree(unsigned int RequestedCapacity); | This is the constructor. RequestedCapacity is the maximum capacity which | is requested for this priority queue. | | int Empty(); | Returns true if the tree is empty; otherwise, returns false. | | | int Full(); | Returns true if the tree is full; otherwise, returns false. | | | unsigned int Size(); | Returns the number of nodes in the tree. | | void AddNode(DataAtOneNode NewEntry); | Precondition: Full returns false. | Postcondition: A new node has been added to the complete binary tree, at | the next available location. The entry stored in this node is | NewEntry. | | | void RemoveNode(); | Precondition: Size > 0. | Postcondition: The most-recently added node has been removed | from the tree. | | void ChangeEntry(unsigned int NodeNumber, DataAtOneNode NewEntry); | Precondition: Index < Size. | Postcondition: The data stored at the node with number Index has been | changed to NewEntry, and the tree is otherwise unchanged. Note: | The Root is node number 0, the next level has nodes 1 and 2, and so on. | | | void FetchEntry(unsigned int NodeNumber, DataAtOneNode& Result); | Precondition: Index < Size. | Postcondition: The value of Result has been set to the data stored at | node number Index. The tree is unchanged. | | | void SwapWithParent(unsigned int Index); | Precondition: 0 < Index < Size. | Postcondition: The data stored at the node with number Index has been | swapped with the data stored at the parent of that node. The tree is | otherwise unchanged. | | METHODS FOR THE PriorityQueue CLASS | | PriorityQueue(unsigned int RequestedCapacity); | This is the constructor. RequestedCapacity is the maximum capacity which | is requested for this priority queue. | | void Insert(Entry NewEntry, int Priority); | Precondition: Full() returns false. | Postcondition: A new copy of NewEntry has been added to the priority queue | with the given Priority. | | void GetFront(Entry& Result); | Precondition: The priority queue is not empty. | Postcondition: The highest priority entry of the priority queue has been | assigned to Result, and has been removed from the queue. (If several | entries have the same priority, then they are removed in FIFO order.) | | int Empty(); | Returns true if the priority queue is empty; otherwise, returns false. | | int Full(); | Returns true if the priority queue can NOT accept another item; | otherwise, returns false. | | unsigned int Size(); | Returns the total number of entries in the priority queue. |**************************************************************************/ /* In general, we do not want to include all these definitions if they have | already been included from some other location. Therefore, we check whether | the definitions have previously been defined, and if so then we skip to | the end of this file. */ #ifndef PRIORITY_DEFINITIONS #define PRIORITY_DEFINITIONS #include // Permits writing of error messages to cerr #include // Permits use of exit #define FALSE 0 #define TRUE 1 template class CompleteBinaryTree { // Student may define whatever private data fields are needed unsigned int Used; unsigned int Capacity; DataAtOneNode* Data; public: CompleteBinaryTree(unsigned int RequestedCapacity); int Empty(); int Full(); unsigned int Size(); void AddNode(DataAtOneNode NewEntry); void RemoveNode(); void ChangeEntry(unsigned int NodeNumber, DataAtOneNode NewEntry); void FetchEntry(unsigned int NodeNumber, DataAtOneNode& Result); void SwapWithParent(unsigned int Index); ~CompleteBinaryTree() { delete [] Data; } }; template class PriorityQueueData { public: Entry Value; PriorityType Priority; int TimeStamp; }; template class PriorityQueue { private: typedef PriorityQueueData DataAtOneNode; CompleteBinaryTree Heap; unsigned int NumberOfCallsToInsert; int PeckingOrder(unsigned int Index1, unsigned int Index2); void ReheapifyUp(); void ReheapifyDown(); public: PriorityQueue(unsigned int RequestedCapacity); void Print(); void Insert(Entry NewEntry, PriorityType Priority); void GetFront(Entry& Result); int Empty() { return Heap.Empty(); } int Full() { return Heap.Full(); } unsigned int Size() { return Heap.Size(); } }; template void PriorityQueue::Print() { int I; for (I = 0; I < Size(); I++) { DataAtOneNode D; Heap.FetchEntry(I, D); cout << I << " " << D.Priority << " " << D.Value << endl; } } /********************************************************************** | Implementation of the complete binary tree. */ template CompleteBinaryTree:: CompleteBinaryTree(unsigned int RequestedCapacity) { Used = 0; Capacity = RequestedCapacity; Data = new DataAtOneNode[RequestedCapacity]; } template int CompleteBinaryTree::Empty() { return (Used == 0); } template int CompleteBinaryTree::Full() { return (Used == Capacity); } template unsigned int CompleteBinaryTree::Size() { return Used; } template void CompleteBinaryTree::AddNode(DataAtOneNode NewEntry) { if (Full()) { cerr << "ERROR in AddNode: Full tree." << endl; exit(0); } Data[Used++] = NewEntry; } template void CompleteBinaryTree::RemoveNode() { if (Empty()) { cerr << "ERROR in RemoveNode: Empty tree." << endl; exit(0); } Used--; } template void CompleteBinaryTree:: ChangeEntry(unsigned int Index, DataAtOneNode NewEntry) { if (Index >= Used) { cerr << "ERROR in ChangeEntry: Index too big." << endl; exit(0); } Data[Index] = NewEntry; } template void CompleteBinaryTree:: FetchEntry(unsigned int Index, DataAtOneNode& Result) { if (Index >= Used) { cerr << "ERROR in FetchEntry: Index too big." << endl; exit(0); } Result = Data[Index]; } template void CompleteBinaryTree::SwapWithParent(unsigned int Index) { if ((Index == 0) || (Index >= Used)) { cerr << "ERROR in ChangeEntry: Illegal Index." << endl; exit(0); } unsigned int ParentIndex = (Index-1)/2; DataAtOneNode Temp = Data[Index]; Data[Index] = Data[ParentIndex]; Data[ParentIndex] = Temp; } /********************************************************************** | PriorityQueue Implementation. | Note: All methods must make sure that the field NumberOfCallsToInsert | is always equal to the number of times that Insert has been called for | this object. When a new entry is inserted, the value of that item's | TimeStamp is set to the current value of NumberOfCallsToInsert. | Therefore, a smaller timestamp indicates an earlier entry time. */ template PriorityQueue:: PriorityQueue(unsigned int RequestedCapacity) : Heap(RequestedCapacity) { } template int PriorityQueue:: PeckingOrder(unsigned int Index1, unsigned int Index2) { /* This is a private method that will be useful within the implementation | of ReheapifyUp and ReheapifyDown. | Precondition: Index1 and Index2 are both less than or equal to Size. | Postcondition: In the Heap, the node with Index1 is compared to the | node with Index2. This function returns true under any of the following | conditions: | a. If (Priority of Index1) > (Priority of Index2). | b. Or, if the Priorities are equal and | (TimeStamp of Index 1) < (TimeStamp of Index 2). | Otherwise, the function returns false. */ DataAtOneNode Value1, Value2; Heap.FetchEntry(Index1, Value1); Heap.FetchEntry(Index2, Value2); if (Value1.Priority > Value2.Priority) return TRUE; if (Value1.Priority < Value2.Priority) return FALSE; return Value1.TimeStamp < Value2.TimeStamp; } template void PriorityQueue::ReheapifyDown() { /* This is a private method that will be useful within the implementation | of Insert. | Precondition: The heap contains at least one entry, and Heap is a valid | heap with one possible exception: The value stored in the root might | be less than its children. | Postcondition: The heap has been reheapified downward so that it is once | again a valid heap. */ unsigned int Index = 0; do { unsigned int BigIndex = Index; unsigned int Left = Index*2 + 1; unsigned int Right = Left+1; if ((Left < Size()) && PeckingOrder(Left, BigIndex)) BigIndex = Left; if ((Right < Size()) && PeckingOrder(Right, BigIndex)) BigIndex = Right; if (BigIndex == Index) return; Heap.SwapWithParent(BigIndex); Index = BigIndex; } while (TRUE); } template void PriorityQueue::ReheapifyUp() { /* This is a private method that will be useful within the implementation | of GetFront. | Precondition: Heap is a valid heap with one possible exception: The value | stored in the final node might be more than its parent. | Postcondition: The heap has been reheapified upward so that it is once | again a valid heap. */ unsigned int Index = Size()-1; unsigned int ParentIndex; while (Index && PeckingOrder(Index, ParentIndex = (Index-1)/2)) { Heap.SwapWithParent(Index); Index = ParentIndex; } } template void PriorityQueue::Insert(Entry NewEntry, PriorityType Priority) { DataAtOneNode Record; Record.Value = NewEntry; Record.Priority = Priority; Record.TimeStamp = NumberOfCallsToInsert++; Heap.AddNode(Record); ReheapifyUp(); } template void PriorityQueue::GetFront(Entry& Result) { DataAtOneNode Record; Heap.FetchEntry(0, Record); Result = Record.Value; Heap.FetchEntry(Size()-1, Record); Heap.ChangeEntry(0, Record); Heap.RemoveNode(); if (Size() > 0) ReheapifyDown(); } #endif