// file: $isip/class/dstr/PriorityQueue/PriorityQueue.h // version: $Id: PriorityQueue.h 10636 2007-01-26 22:18:09Z tm334 $ // // make sure definitions are made only once // #ifndef ISIP_PRIORITY_QUEUE #define ISIP_PRIORITY_QUEUE // isip include files // #ifndef ISIP_DSTR_BASE #include #endif #ifndef ISIP_LONG #include #endif #ifndef ISIP_STRING #include #endif #ifndef ISIP_CHAR #include #endif #ifndef ISIP_CONSOLE #include #endif // forward class definitions // template class PriorityQueueDiagnose; // PriorityQueue: this class implements a standard priority queue // using a vector to implement the underlying heap data structure. // template class PriorityQueue : public DstrBase { //--------------------------------------------------------------------------- // // public constants // //--------------------------------------------------------------------------- public: // define the class name // static const String CLASS_NAME; //---------------------------------------- // // i/o related constants // //---------------------------------------- static const String DEF_PARAM; //---------------------------------------- // // default values and arguments // //---------------------------------------- // default values // static const int32 DEF_END_POS = -1; // default arguments to methods // //---------------------------------------- // // error codes // //---------------------------------------- //--------------------------------------------------------------------------- // // protected data // //--------------------------------------------------------------------------- protected: // comparison function for the items in the priority queue // typedef Integral::COMPARE (*COMPARE_FUNC)(TObject* item1, TObject* item2); // the internal structure of the priority queue // TObject** v_d; // the allocation mode // ALLOCATION alloc_d; // number of elements of this vector // Long length_d; // the maximum number of elements // Long capacity_d; // debugging parameters // static Integral::DEBUG debug_level_d; // define the memory manager // static MemoryManager mgr_d; //--------------------------------------------------------------------------- // // required public methods // //--------------------------------------------------------------------------- public: // static methods: // the diagnose method is moved outside the class header file and // defined in the PriorityQueueDiagnose.h in order to avoid issues // with preprocessing of the diagnose code. // static const String& name(); // method: setDebug // static bool8 setDebug(Integral::DEBUG debug_level) { debug_level_d = debug_level; return true; } // other debug methods // bool8 debug(const unichar* message) const; // destructor/constructor(s) // ~PriorityQueue(); PriorityQueue(ALLOCATION alloc = DEF_ALLOCATION); PriorityQueue(const PriorityQueue& copy_queue); // assign method // bool8 assign(const PriorityQueue& copy_stack); // method: operator= // PriorityQueue& operator=(const PriorityQueue& arg) { assign(arg); return *this; } // method: eq // bool8 eq(const PriorityQueue& arg) const; // method: read // bool8 read(Sof& sof, int32 tag) { return read(sof, tag, name()); } // method: write // bool8 write(Sof& sof, int32 tag) const { return write(sof, tag, name()); } // method: sofSize // int32 sofSize() const { return 0; } // method: read // bool8 read(Sof& sof, int32 tag, const String& name) { return Error::handle(this->name(), L"read", Error::ARG, __FILE__, __LINE__); } // method: write // bool8 write(Sof& sof, int32 tag, const String& name) const { return Error::handle(this->name(), L"write", Error::ARG, __FILE__, __LINE__); } // method: readData // bool8 readData(Sof& sof, const String& pname = DEF_PARAM, int32 size = SofParser::FULL_OBJECT, bool8 param = true, bool8 nested = true) { return Error::handle(name(), L"readData", Error::ARG, __FILE__, __LINE__); } // method: writeData // bool8 writeData(Sof& sof, const String& pname = DEF_PARAM) const { return Error::handle(name(), L"writeData", Error::ARG, __FILE__, __LINE__); } // method: new // static void* operator new(size_t size) { return mgr_d.get(); } // method: new[] // static void* operator new[](size_t size) { return mgr_d.getBlock(size); } // method: delete // static void operator delete(void* ptr) { mgr_d.release(ptr); } // method: delete[] // static void operator delete[](void* ptr) { mgr_d.releaseBlock(ptr); } // method: setGrowSize // static bool8 setGrowSize(int32 grow_size) { return mgr_d.setGrow(grow_size); } // method: clear // bool8 clear(Integral::CMODE cmode = Integral::DEF_CMODE); //--------------------------------------------------------------------------- // // class-specific public methods: // priority queue push, pop and top methods // //--------------------------------------------------------------------------- // method inserts an intem into the priority queue // bool8 push(TObject* item, COMPARE_FUNC comp_func = compare); // method removes the largest item from the priority queue // TObject* pop(TObject* item = (TObject*)NULL); // method: top // const TObject* top() const; TObject* top(); //--------------------------------------------------------------------------- // // class-specific public methods: // size-related methods // //-------------------------------------------------------------------------- // method: isEmpty // bool8 isEmpty() const { return ((int32)length_d == 0); } // method: length // int32 length() const { return (int32)length_d; } // method: getCapacity // int32 getCapacity() const { return (int32)capacity_d; } // resize methods // bool8 setLength(int32 length, bool8 preserve_values = true); bool8 setCapacity(int32 capacity, bool8 preserve_values = true); //--------------------------------------------------------------------------- // // private methods // //--------------------------------------------------------------------------- private: //--------------------------------------------------------------------------- // // class-specific public methods: // priority queue property methods // //--------------------------------------------------------------------------- // method: parent // int32 parent(int32 val) { return (val - 1) / 2; } // method: left // int32 left(int32 val) { return (2 * val) + 1; } // method: right // int32 right(int32 val) { return (2 * val) + 2; } //--------------------------------------------------------------------------- // // class-specific public methods: // heap manipulation methods // //-------------------------------------------------------------------------- // this method evaluates the kernel for the input vectors // static Integral::COMPARE compare(TObject* item1, TObject* item2); // method to reorder the heap and maintain the heap property // bool8 heapify(int32 index, COMPARE_FUNC comp_func = compare); // method to construct a heap out of an existing array // bool8 buildHeap(); // method to sort an existing heap // bool8 heapSort(); // method to access the heap based on the mode // TObject* accessByMode(TObject* item); }; //----------------------------------------------------------------------------- // // we define non-integral constants at the end of class definition for // templates (for non-templates these are defined in the default constructor) // //----------------------------------------------------------------------------- // constants: required constants such as the class name // template const String PriorityQueue::CLASS_NAME(L"PriorityQueue"); template const String PriorityQueue::DEF_PARAM(L"values"); // static instantiations: debug level // template Integral::DEBUG PriorityQueue::debug_level_d = Integral::NONE; // static instantiations: the memory manager // template MemoryManager PriorityQueue::mgr_d(sizeof(PriorityQueue), CLASS_NAME); // below are all the methods for the Queue template class // // --------------------------------------------------------------------- // // required static methods // //---------------------------------------------------------------------- // method: name // // arguments: none // // return: a static String& containing the class name // // this method returns the class name // template const String& PriorityQueue::name() { // create the static name string for this class and return it // static String cname(CLASS_NAME); cname.clear(); cname.concat(CLASS_NAME); cname.concat(L"<"); cname.concat(TObject::name()); cname.concat(L">"); // return the name // return cname; } // --------------------------------------------------------------------- // // required debug methods // //---------------------------------------------------------------------- // method: debug // // arguments: // unichar* message: (input) information message // // return: a bool8 value indicating status // // this method dumps the contents of an object to the console // template bool8 PriorityQueue::debug(const unichar* message_a) const { // declare temporary strings to hold class data // String output; String value; String param; String numeric; // dump the length // value.assign((int32)length_d); output.debugStr(name(), message_a, L"length_d", value); Console::put(output); // dump the capacity // value.assign((int32)capacity_d); output.debugStr(name(), message_a, L"capacity_d", value); Console::put(output); // dump the values // for (int32 i = 0; i < (int32)length_d; i++) { param.assign(L"v_d["); value.assign(i); param.concat(value); param.concat(L"]"); output.debugStr(name(), message_a, param); Console::put(output); // increase indention // Console::increaseIndention(); // call the debug method of the element // if (v_d[i] != (TObject*)NULL) { v_d[i]->debug(L""); } Console::decreaseIndention(); } // exit gracefully // return true; } //------------------------------------------------------------------------ // // required destructor/constructor(s) // //----------------------------------------------------------------------- // method: destructor // // arguments: none // // return: none // template PriorityQueue::~PriorityQueue() { // free memory // clear(Integral::RELEASE); } // method: default constructor // // arguments: // ALLOCATION alloc: (input) the flag to specify whether or not the item // memory is allocated by the node itself // // return: none // template PriorityQueue::PriorityQueue(ALLOCATION alloc_a) { // initialize data // length_d = (int32)0; capacity_d = (int32)0; v_d = (TObject**)NULL; // set the allocation flag // alloc_d = alloc_a; } // method: copy constructor // // arguments: // const PriorityQueue& copy_queue: (input) the queue to copy // // return: none // template PriorityQueue::PriorityQueue(const PriorityQueue& copy_queue_a) { // initialize data // length_d = (int32)0; capacity_d = (int32)0; v_d = (TObject**)NULL; // call the assign method to copy the queue // assign(copy_queue_a); } //------------------------------------------------------------------------ // // required assign methods // //------------------------------------------------------------------------- // method: assign // // arguments: // const PriorityQueue& copy_queue: (input) the queue to copy // // return: a bool8 value indicating status // // this method copies the contents of the input to this queue // template bool8 PriorityQueue::assign(const PriorityQueue& copy_queue_a) { // resize the vector // if (!setLength(copy_queue_a.length(), false)) { return Error::handle(name(), L"assign", Error::NOMEM, __FILE__, __LINE__); } // copy the data // for (int32 index = 0; index < (int32)length_d; index++) { v_d[index] = accessByMode(copy_queue_a.v_d[index]); } // exit gracefully // return true; } //------------------------------------------------------------------------ // // required equality methods // //------------------------------------------------------------------------ // method: eq // // arguments: // const PriorityQueue& compare_queue: (input) the queue to compare // // return: a bool8 value indicating status // // this method compares two queues for equivalence. two queues are equivalent // if all corresponding items are equivalent // template bool8 PriorityQueue::eq(const PriorityQueue& compare_queue_a) const { // declare the output variable // bool8 are_equal = true; // two PriorityQueues can not be equivalent if they are of differing lengths // if ((int32)length_d != (int32)compare_queue_a.length_d) { // set the break flag // are_equal = false; } // loop over each element and see if each is equivalent // for (int32 i = 0; are_equal && (i < (int32)length_d); i++) { // see if the current items are equal // if (alloc_d == SYSTEM) { if (!v_d[i]->eq(*compare_queue_a.v_d[i])) { are_equal = false; } } else { if (v_d[i] != compare_queue_a.v_d[i]) { are_equal = false; } } } // return a value representing if they are equivalent // return are_equal; } //------------------------------------------------------------------------- // // required memory management methods // //------------------------------------------------------------------------- // method: clear // // arguments: // Integral::CMODE cmode_a: (input) clear mode // // return: a bool8 value indicating status // // this method clears the contents of the list by the setting of cmode_a // // enum CMODE { RETAIN = 0, RESET, RELEASE, FREE, DEF_CMODE = RESET }; // // RETAIN: call clear with RETAIN on each element in the queue // // RESET: clear the structure but don't necessarily delete memory // // RELEASE: clear the structure and release memory // // FREE: clear the structure and release memory // // Programming hint: // // use the clear() method to manage the memory of the objects going // into the queue. // particular useful when queue is in USER mode. Caution the object // you place into queue must have a clear method that meets the // requirements of the IFC clear method. // // template bool8 PriorityQueue::clear(Integral::CMODE cmode_a) { // if the cmode_a is RETAIN or FREE, call clear(cmode_a) method for // each element // if ((cmode_a == Integral::RETAIN) || (cmode_a == Integral::FREE)) { // loop over all elements // for (int32 i = 0; i < (int32)length_d; i++) { v_d[i]->clear(cmode_a); } } // if the cmode_a is RESET, clear the structure but don't // necessarily delete memory // if (cmode_a == Integral::RESET) { setLength(0); } // if the cmode_a is RELEASE or FREE, clear the structure and // release memory. // else if ((cmode_a == Integral::RELEASE) || (cmode_a == Integral::FREE)) { // free memory -- the setCapacity call will actually release it. // setCapacity(0); length_d = 0; } // exit gracefully // return true; } //------------------------------------------------------------------------ // // class-specific public methods: // get and set methods // //------------------------------------------------------------------------ // method: setLength // // arguments: // int32 length: (input) new length // bool8 preserve_values: (input) should we save the memory // // return: a bool8 value indicating status // // this method sets the length, or number of valid elements // template bool8 PriorityQueue::setLength(int32 length_a, bool8 preserve_values_a) { // check arguments // if (length_a < 0) { return Error::handle(name(), L"setLength", Error::ARG, __FILE__, __LINE__); } // if new length is greater than capacity, call setCapacity // if (length_a > capacity_d) { if (!setCapacity(length_a, preserve_values_a)) { return Error::handle(name(), L"setLength", Error::NOMEM, __FILE__, __LINE__); } } // set new length // length_d = length_a; // exit gracefully // return true; } // method: setCapacity // // arguments: // int32 capacity: (input) new capacity // bool8 preserve_values: (input) should we save the memory // // return: a bool8 value indicating status // // this method sets the capacity, which is the maximum number of elements // this queue can hold. // template bool8 PriorityQueue::setCapacity(int32 capacity_a, bool8 preserve_values_a) { // capacity_a < 0: error // if (capacity_a < 0) { return Error::handle(name(), L"setCapacity", Error::ARG, __FILE__, __LINE__); } // capacity_a = capacity_d: done // else if (capacity_a == capacity_d) { return true; } // capacity_a == 0 (and length_d == 0): just delete memory // else if (capacity_a == 0) { // delete the old memory // if (v_d != (TObject**)NULL) { if (alloc_d == SYSTEM) { for (int32 i=0; i < (int32)length_d; i++) { if (v_d[i] != (TObject*)NULL) { delete v_d[i]; v_d[i] = (TObject*)NULL; } } } delete [] v_d; v_d = (TObject**)NULL; } } // capacity_a >= length_d: we will need to allocate memory and/or // transfer data. // else { // allocate a new chunk of memory // TObject** new_mem = new TObject*[capacity_a]; if (new_mem == (TObject**)NULL) { return Error::handle(name(), L"setCapacity", Error::NOMEM, __FILE__, __LINE__); } // initialize the memory // for (int32 i=0; i < (int32)capacity_a; i++) { new_mem[i] = (TObject*)NULL; } // if there are valid elements and we need to preserve them // if (((int32)length_d > 0) && preserve_values_a) { for (int32 i = 0; i < (int32)length_d; i++) { new_mem[i] = accessByMode(v_d[i]); } } // delete the old memory // if (v_d != (TObject**)NULL) { if (alloc_d == SYSTEM) { for (int32 i=0; i < (int32)length_d; i++) { if (v_d[i] != (TObject*)NULL) { delete v_d[i]; v_d[i] = (TObject*)NULL; } } } delete [] v_d; v_d = (TObject**)NULL; } // assign the pointer to the new memory // v_d = new_mem; } // set the new capacity // capacity_d = capacity_a; // exit gracefully // return true; } //--------------------------------------------------------------------------- // // class-specific public methods: // queue property methods // //--------------------------------------------------------------------------- // method: push // // arguments: // TObject* item: (input) item to be inserted // COMPARE_FUNC comp_func: (input) priority queue comparison function // // return: a bool8 value indicating status // // this method inserts an item into the queue // template bool8 PriorityQueue::push(TObject* item_a, COMPARE_FUNC comp_func_a) { // declare local variables // TObject* new_obj = (TObject*)NULL; // mode: SYSTEM // make a copy of the element // if (alloc_d == SYSTEM) { new_obj = new TObject(*item_a); } // mode: USER // make a copy of the pointer to the item // else { new_obj = item_a; } // increase the size of the heap by one // setLength((int32)length_d + 1); // propagate the item up the heap until the heap properties are met // int32 i = (int32)length_d - 1; while ((i > 0) && (comp_func_a(v_d[parent(i)], new_obj) == Integral::LESSER)) { v_d[i] = v_d[parent(i)]; i = parent(i); } v_d[i] = new_obj; // exit gracefully // return true; } // method: pop // // arguments: // TObject* item: (output) item to be removed // // return: a bool8 value indicating status // // this method removes the maximum item from the queue // template TObject* PriorityQueue::pop(TObject* item_a) { // declare local variables // TObject* ptr = (TObject*)NULL; // when in SYSTEM mode the item passed in should not be // null, if we are in USER mode the item should be null // if (((alloc_d == SYSTEM) && (item_a == (TObject*)NULL)) || ((alloc_d == USER) && (item_a != (TObject*)NULL))) { Error::handle(name(), L"remove", ERR, __FILE__, __LINE__); return (TObject*)NULL; } // check for heap size violations // if (!isEmpty()) { // retrieve the maximum item form the heap // ptr = v_d[0]; // mode: SYSTEM // if (alloc_d == SYSTEM) { // make a copy of the object // item_a->assign(*ptr); // delete the reference to the object // delete ptr; } // mode: USER // else { // assign the pointer to the item // item_a = ptr; } // remove the maximum item and reorganize the heap // v_d[0] = v_d[(int32)length_d - 1]; setLength((int32)length_d - 1); heapify(0); // return a pointer to the object (so that the return value can // be compared) // return item_a; } // nothing in queue, return null // return (TObject*)NULL; } // method: top // // arguments: // TObject* item: (output) item to be removed // // return: a bool8 value indicating status // // this method removes the maximum item from the queue // template const TObject* PriorityQueue::top() const { // check for heap size violations // if (isEmpty()) { Error::handle(name(), L"top", Error::ARG, __FILE__, __LINE__); return (TObject*)NULL; } // return the maximum item in the heap // return v_d[0]; } // method: top // // arguments: // TObject* item: (output) item to be removed // // return: a bool8 value indicating status // // this method removes the maximum item from the queue // template TObject* PriorityQueue::top() { // check for heap size violations // if (isEmpty()) { Error::handle(name(), L"top", Error::ARG, __FILE__, __LINE__); return (TObject*)NULL; } // return the maximum item in the heap // return v_d[0]; } //--------------------------------------------------------------------------- // // heap manipulation methods // //--------------------------------------------------------------------------- // method: compare // // arguments: // TObject* item1: (input) first item to compare // TObject* item2: (input) second item to compare // // return: an enum indicating comparison status // // method compares the input items // template Integral::COMPARE PriorityQueue::compare(TObject* item1_a, TObject* item2_a) { // check if item1 is greater than item2 // if (*item1_a > *item2_a) { return Integral::GREATER; } // check if item1 is less than item2 // if (*item1_a < *item2_a) { return Integral::LESSER; } // if we made it this far then the item must be equal // return Integral::EQUAL; } // method: heapify // // arguments: // int32 index: (input) index at which o start the heapify process // COMPARE_FUNC comp_func: (input) priority queue comparison function // // return: a bool8 value indicating status // // this method verifies that the underlying array obeys the heap property // template bool8 PriorityQueue::heapify(int32 index_a, COMPARE_FUNC comp_func_a) { // declare local variables // TObject* tmp = (TObject*)NULL; // get the children of the index // int32 l = left(index_a); int32 r = right(index_a); // assume the current index is the largest // int32 largest = index_a; // check if the left child is larger // if ((l < (int32)length_d) && (comp_func_a(v_d[l], v_d[index_a]) == Integral::GREATER)) { largest = l; } // check if the right child is larger // if ((r < (int32)length_d) && (comp_func_a(v_d[r], v_d[largest]) == Integral::GREATER)) { largest = r; } // check if the heap property is violated // if (largest != index_a) { // exchange // tmp = v_d[largest]; v_d[largest] = v_d[index_a]; v_d[index_a] = tmp; // recursively reorder the heap // heapify(largest); } // exit gracefully // return true; } // method: buildHeap // // arguments: none // // return: a bool8 value indicating status // // this method builds a heap out of the underlying array // template bool8 PriorityQueue::buildHeap() { // build the heap using the heapify routine // int32 size = (int32)length_d - 1; for (int32 i=size/2; i >= 0; i--) { heapify(i); } // exit gracefully // return true; } // method: heapSort // // arguments: none // // return: a bool8 value indicating status // // this method sorts the elements in the heap // template bool8 PriorityQueue::heapSort() { // declare local variables // int32 size = (int32)length_d; TObject* tmp = (TObject*)NULL; // construct the heap out of the existing elements // buildHeap(); // loop over the elements and sort them as we move along // for (int32 i=(int32)length_d - 1; i >= 1; i--) { // exchange // tmp = v_d[0]; v_d[0] = v_d[i]; v_d[i] = tmp; // reduce the size of the heap and reorder // setLength((int32)length_d - 1); heapify(0); } // reset the length after we are done // setLength(size); // exit gracefully // return true; } // method: accessByMode // // arguments: // TObject* item: (input) input item to access by mode // // return: input item accessed by mode // // this method accesses the input element via the access mode // template TObject* PriorityQueue::accessByMode(TObject* item_a) { // declare local variables // TObject* new_obj = (TObject*)NULL; // access by mode // if (alloc_d == USER) { new_obj = item_a; } else { new_obj = new TObject(*item_a); } // return the item by mode // return new_obj; } // end of include file // #endif