/*========================================================================= Program: Visualization Toolkit Module: vtkPriorityQueue.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkPriorityQueue.h" #include "vtkObjectFactory.h" vtkStandardNewMacro(vtkPriorityQueue); // Instantiate priority queue with default size and extension size of 1000. vtkPriorityQueue::vtkPriorityQueue() { this->Size = 0; this->Extend = 1000; this->Array = nullptr; this->MaxId = -1; this->ItemLocation = vtkIdTypeArray::New(); } // Allocate priority queue with specified size and amount to extend // queue (if reallocation required). void vtkPriorityQueue::Allocate(vtkIdType sz, vtkIdType ext) { this->ItemLocation->Allocate(sz, ext); for (vtkIdType i = 0; i < sz; i++) { this->ItemLocation->SetValue(i, -1); } this->Size = (sz > 0 ? sz : 1); delete[] this->Array; this->Array = new vtkPriorityQueue::Item[sz]; this->Extend = (ext > 0 ? ext : 1); this->MaxId = -1; } // Destructor for the vtkPriorityQueue class vtkPriorityQueue::~vtkPriorityQueue() { this->ItemLocation->Delete(); delete[] this->Array; } // Insert id with priority specified. void vtkPriorityQueue::Insert(double priority, vtkIdType id) { vtkIdType i, idx; vtkPriorityQueue::Item temp; // check and make sure item hasn't been inserted before if (id <= this->ItemLocation->GetMaxId() && this->ItemLocation->GetValue(id) != -1) { return; } // start by placing new entry at bottom of tree if (++this->MaxId >= this->Size) { this->Resize(this->MaxId + 1); } this->Array[this->MaxId].priority = priority; this->Array[this->MaxId].id = id; if (id >= this->ItemLocation->GetSize()) // might have to resize and initialize { vtkIdType oldSize = this->ItemLocation->GetSize(); this->ItemLocation->InsertValue(id, this->MaxId); for (i = oldSize; i < this->ItemLocation->GetSize(); i++) { this->ItemLocation->SetValue(i, -1); } this->ItemLocation->SetValue(id, this->MaxId); } this->ItemLocation->InsertValue(id, this->MaxId); // now begin percolating towards top of tree for (i = this->MaxId; i > 0 && this->Array[i].priority < this->Array[(idx = (i - 1) / 2)].priority; i = idx) { temp = this->Array[i]; this->ItemLocation->SetValue(temp.id, idx); this->Array[i] = this->Array[idx]; this->ItemLocation->SetValue(this->Array[idx].id, i); this->Array[idx] = temp; } } // Simplified call for easier wrapping for Tcl. vtkIdType vtkPriorityQueue::Pop(vtkIdType location) { double priority; return this->Pop(location, priority); } // Removes item at specified location from tree; then reorders and // balances tree. The location == 0 is the root of the tree. vtkIdType vtkPriorityQueue::Pop(vtkIdType location, double& priority) { vtkIdType idx; vtkPriorityQueue::Item temp; if (this->MaxId < 0) { return -1; } vtkIdType id = this->Array[location].id; priority = this->Array[location].priority; // move the last item to the location specified and push into the tree this->Array[location].id = this->Array[this->MaxId].id; this->Array[location].priority = this->Array[this->MaxId].priority; this->ItemLocation->SetValue(this->Array[location].id, location); this->ItemLocation->SetValue(id, -1); if (--this->MaxId <= 0) { return id; } // percolate down the tree from the specified location vtkIdType lastNodeToCheck = (this->MaxId - 1) / 2; for (vtkIdType j = 0, i = location; i <= lastNodeToCheck; i = j) { idx = 2 * i + 1; if (this->Array[idx].priority < this->Array[idx + 1].priority || idx == this->MaxId) { j = idx; } else { j = idx + 1; } if (this->Array[i].priority > this->Array[j].priority) { temp = this->Array[i]; this->ItemLocation->SetValue(temp.id, j); this->Array[i] = this->Array[j]; this->ItemLocation->SetValue(this->Array[j].id, i); this->Array[j] = temp; } else { break; } } // percolate up the tree from the specified location for (vtkIdType i = location; i > 0; i = idx) { idx = (i - 1) / 2; if (this->Array[i].priority < this->Array[idx].priority) { temp = this->Array[i]; this->ItemLocation->SetValue(temp.id, idx); this->Array[i] = this->Array[idx]; this->ItemLocation->SetValue(this->Array[idx].id, i); this->Array[idx] = temp; } else { break; } } return id; } // Protected method reallocates queue. vtkPriorityQueue::Item* vtkPriorityQueue::Resize(const vtkIdType sz) { vtkPriorityQueue::Item* newArray; vtkIdType newSize; if (sz >= this->Size) { newSize = this->Size + sz; } else { newSize = sz; } if (newSize <= 0) { newSize = 1; } newArray = new vtkPriorityQueue::Item[newSize]; if (this->Array) { memcpy( newArray, this->Array, (sz < this->Size ? sz : this->Size) * sizeof(vtkPriorityQueue::Item)); delete[] this->Array; } this->Size = newSize; this->Array = newArray; return this->Array; } // Reset all of the entries in the queue so they don not have a priority void vtkPriorityQueue::Reset() { this->MaxId = -1; for (int i = 0; i <= this->ItemLocation->GetMaxId(); i++) { this->ItemLocation->SetValue(i, -1); } this->ItemLocation->Reset(); } void vtkPriorityQueue::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Number Of Entries: " << this->MaxId + 1 << "\n"; os << indent << "Size: " << this->Size << "\n"; os << indent << "Extend size: " << this->Extend << "\n"; }