Scaffolding  0.1
This program can assemble genome scaffolds using the pairing information in paired-end reads.
low_priority_queue_old.hpp
1 
2 // we implement a priority queue taking O(n+k) space
3 // where k is the maximum priority & n is the number of elements in the queue
4 // and the following times:
5 // construct: O(k)
6 // insert: O(1) (amortized)
7 // erase by iterator: O(1)
8 // change_priority by iterator: O(k) - NOTE: I suspect this to be O(1) in practice
9 // top: O(1)
10 // pop: O(1)
11 
12 #ifndef LOW_PRIORITY_QUEUE
13 #define LOW_PRIORITY_QUEUE
14 
15 #include <list>
16 #include <vector>
17 
18 namespace std{
19 
20  template<class Element, class Priority = size_t>
21  class low_priority_queue{
22  public:
23  // public types
24  typedef typename std::pair<Element, Priority> value_type;
25  typedef typename list<value_type>::const_iterator const_iterator;
26 
27  private:
28  // private types
29  typedef typename list<value_type>::iterator iterator;
30 
31  // main data container
32  list<value_type> _data;
33  // a vector of pointers; _start_points[i] points to the first element with priority exactly i
34  // thus, we assume the position that _start_points[i] points to in _data grows monotonically with i (except for "past the end")
35  vector<iterator> _start_points;
36 
37  // the maximum priority in the queue
38  Priority max_priority;
39 
40  public:
41 
42  // construct an empty low priority queue
43  low_priority_queue():
44  max_priority(0)
45  {}
46 
47  // copy construct a low priority queue
48  low_priority_queue(const low_priority_queue<Element>& lpq):
49  max_priority(lpq.max_priority)
50  {
51  _start_points.resize((size_t)max_priority + 1);
52  Priority next_prio(0);
53  ++next_prio;
54  for(const value_type& value : lpq._data){
55  const Priority& prio = value.second;
56  const iterator it = _data.emplace_back(value);
57  // if we broke a new priority, set the _start_points vector
58  while(prio > next_prio)
59  _start_points[next_prio++] = _data.end();
60  if(prio == next_prio)
61  _start_points[next_prio++] = it;
62  }
63  }
64 
65 
66  private:
67  // prepare _start_points to receive an entry of priority new_priority
68  void prepare_start_points_to_receive(const Priority& new_priority){
69  if(new_priority > max_priority){
70  _start_points.resize((size_t)new_priority + 1);
71  while(new_priority > max_priority)
72  _start_points[++max_priority] = _data.end();
73  }
74  }
75  // update the start pointer for priority it->second if it points to it
76  void update_start_point_assuming_we_remove(const iterator& it){
77  const Priority& prio = it->second;
78  iterator& first_element = _start_points[prio];
79  if(first_element == it){
80  // get the element behind it
81  iterator next_element = it;
82  ++next_element;
83 
84  if((next_element == _data.end()) || (next_element->second == prio)){
85  // if there is no element behind it, then we have no more elements of priority prio
86  // if the priority of the element behind us is the same as ours, then just move the _start_point pointer
87  first_element = next_element;
88  } else {
89  // otherwise, the next element has a higher priority than the item to erase
90  first_element = _data.end();
91  }// if/else
92  }// if
93  }
94 
95  // get the correct position in _data to insert an item with the given priority
96  const_iterator get_insertion_position(const Priority& prio) {
97  typename vector<iterator>::const_iterator start_point_it(_start_points.cbegin() + prio);
98  // find the next biggest priority that has a start_point
99  // TODO: this seems hardly optimal, maybe we can improve?
100  while( (start_point_it != _start_points.end()) && (*start_point_it == _data.end()))
101  ++start_point_it;
102  // if there are no elements with higher priority, the end is the place to insert
103  if(start_point_it == _start_points.end()) {
104  max_priority = prio;
105  return _data.end();
106  } else return *start_point_it;
107  }
108  public:
109 
110  // insert an element into the low priority queue, returning a const_iterator to the newly inserted item
111  const_iterator insert(const value_type& value){
112  DEBUG5(cout << "inserting degree "<<value.second<< " (max is "<<max_priority<<")"<<endl);
113  const Priority& prio = value.second;
114  // prepare _start_points to receive the new item
115  prepare_start_points_to_receive(prio);
116  DEBUG5(cout << "prepared for insertion, max is now "<<max_priority<<endl);
117  // get the position at which to insert the new item
118  const iterator& it = _data.emplace(get_insertion_position(prio), value);
119  iterator& i = _start_points[prio];
120  if(i == _data.end()) i = it;
121  // fix the pointer to the first element of this priority
122  DEBUG5(cout << "done inserting "<< it->second<< "; the first degree is now "<<_data.front().second<<endl);
123  return it;
124  }
125 
126  // erase an element from the low priority queue, returning an iterator to the following item
127  iterator erase(const const_iterator& it){
128  assert(it != _data.end());
129  const value_type& value = *it;
130  const Priority& prio = value.second;
131  assert(prio <= max_priority);
132 
133  // update the start pointer
134  update_start_point_assuming_we_remove(it);
135 
136  // do the actual removal
137  return _data.erase(it);
138  }
139 
140  // decrease or increase the priority of it by one
141  void decrement_priority(const const_iterator& it){
142  assert(it != _data.end());
143  const Priority old_prio = it->second;
144  assert(old_prio <= max_priority);
145  assert(old_prio > 0);
146 
147  // cast const off it, thanks to Howard Hinnant and Jon Kalb
148  const iterator mutable_it = _data.erase(it, it);
149 
150  // decrease the priority of it
151  Priority& new_prio(mutable_it->second);
152  --new_prio;
153  iterator& new_start_point = _start_points[new_prio];
154 
155  // get the element before which we want to move it
156  iterator& start_element = _start_points[old_prio];
157  assert(start_element != _data.end());
158 
159  // if we're about to decrease the priority of the first element with this priority, we have to modify the start_point of this priority
160  iterator where_inserted;
161  if(start_element == it){
162  iterator next_element = std::next(start_element);
163  // set _start_element[old_prio] to the next element, or _data.end() if the next element has a different priority
164  if(next_element == _data.end()){
165  // if we're at the end of the list, then we're decrementing the key of the unique maximum item
166  start_element = _data.end();
167  --max_priority;
168  } else {
169  if(next_element->second == old_prio)
170  start_element = _data.end();
171  else
172  start_element = next_element;
173  }// if/else
174  where_inserted = next_element;
175  // note that no move is necessary
176  } else {
177  // move it in front of the beginning of the sequence of elements with priority prio
178  _data.splice(start_element, _data, it);
179  where_inserted = start_element;
180  // note that it is _invalid_ from here on
181  }
182 
183  // if there are were no elements of the target priority, we have to modify _start_points[new_prio]
184  if(new_start_point == _data.end())
185  new_start_point = std::prev(where_inserted);
186 
187  DEBUG5(cout << "done decreasing prio from "<<old_prio<<" to "<<new_prio<<endl);
188  DEBUG5(if(_start_points[old_prio] == _data.end()) cout << "start["<<old_prio<<"] is now void"<<endl);
189  DEBUG5(if(_start_points[new_prio] == _data.end()) cout << "start["<<new_prio<<"] is now void"<<endl);
190  }
191 
192 
193  // change the priority of an item in the low priority queue
194  void change_priority(const const_iterator& it, const Priority& new_priority){
195  assert(it != _data.end());
196  const value_type& value = *it;
197  const Priority& prio = value.second;
198  assert(prio <= max_priority);
199 
200  if(prio != new_priority){
201  // if this is the first item of this priority, we have to move the priority pointer to the next (or behind the end)
202  update_prio_pointer_assuming_we_remove(it);
203  // prepare the _start_points to receive the new priority
204  prepare_start_points_to_receive(prio);
205 
206  const const_iterator insert_here = get_insertion_position(prio);
207  // move the element to the designated spot
208  _data.splice(insert_here, _data, it);
209  // fix the pointer to the first element of this priority
210  _start_points[prio] = std::prev(insert_here);
211  }// if
212  }
213 
214  // return whether the low priority queue is empty
215  bool empty() const{
216  return _data.empty();
217  }
218 
219  // return the top of the low priority queue - this is an item of minimum priority
220  value_type& top(){
221  return _data.front();
222  }
223  // return the top of the low priority queue - this is an item of minimum priority
224  const value_type& top() const{
225  return _data.front();
226  }
227 
228  // remove the top of the low priority queue and return the next top
229  const_iterator pop(){
230  assert(!empty());
231  // update the start pointer
232  update_start_point_assuming_we_remove(_data.begin());
233 
234  // do the actual removal
235  return _data.erase(_data.begin());
236  }
237  };
238 
239 };
240 
241 #endif
242 
Definition: low_priority_queue.hpp:18