Experimental Code
Code Written To Experiment With Various Techniques And Otherwise Not Very Useful...
ListMergeSort.h
Go to the documentation of this file.
1 /*
2 Copyright (c) 2013, Komodo Does Inc
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6 
7 - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 - Neither the name of the Komodo Does Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10 
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 */
13 
14 #ifndef LIST_MERGE_SORT_H
15 #define LIST_MERGE_SORT_H
16 
17 /** \file
18  * DoubleLinkedList-based Merge Sort
19  */
20 
21 #ifndef DOUBLE_LINKED_LIST_H
22 #include "DoubleLinkedList.h"
23 #endif // DOUBLE_LINKED_LIST_H
24 
25 namespace Experiment {
26 
27  /** Do-nothing Metric-collector for major actions done by ListMergeSort.
28  *
29  * This serves as a placeholder should you wish to perform metrics on a sort.
30  *
31  * \tparam type of data being sorted
32  */
33  template<class T>
34  class NoSortMetrics {
35  public:
36  /** a and b are compared */
37  void compare(const T& a, const T&b) { }
38 
39  /** Two items were swapped */
40  void swap() { }
41 
42  /** The sort completed */
43  void done() { }
44 
45  /** Metrics should be reset due to starting a new sort */
46  void reset() { }
47  };
48 
49  /** Merge Sort algorithm using lists to hold the data.
50  *
51  * The real advantage of this class is that sort() taking a DoubleLinkedList
52  * will sort without copying the values in the List -- the list will be
53  * disassembled and reassembled in the correct order.
54  *
55  * \tparam T the data type being sorted
56  * \tparam Lessor to compare items
57  * \tparam Metrics to collect metrics on the sort -- \see NoSortMetrics as an example
58  */
59  template<class T, class Iterator = T*, class Lessor = std::less<T>, class Metrics = NoSortMetrics<T> >
60  class ListMergeSort {
61  public:
62  /** Convenience typedef of the type of data in the list */
63  typedef T value_type;
64 
65  /** Convenience typedef of the type of list used in this sort */
67 
68  /** Convenience typedef of the iterator of DataList */
69  typedef typename DataList::iterator DataIter;
70 
71  private:
72  /** Convenience typedef of the type of a list of DataList used in this sort */
74 
75  /** Convenience typedef of the iterator of ListList */
76  typedef typename ListList::iterator ListIter;
77 
78  public:
79 
80  /** Sort from begin to end by copying.
81  *
82  * First, this copies all values to temporary storage. Then it stores.
83  * Finally, it copies the results back.
84  *
85  * This avoids copying values at each stage of the sort as an array-based
86  * merge sort would; however, it still copies the values twice.
87  *
88  * \param begin first value to sort
89  * \param end the position after the last value to sort
90  */
91  void sort(const Iterator begin, const Iterator end) {
92  if(end == begin) {
93  return;
94  }
95 
96  // Load initial list
97  ListList listA;
98  for(Iterator iter = begin; iter != end; ++iter) {
99  listA.push_back(DataList());
100  ListIter added = listA.end() - 1;
101  added->push_back(*iter);
102  }
103 
104  // Create second ListList, location flag, and merge
105  ListList listB;
106  bool dataInListA = true;
107  DataList& sorted = mergeSort(listA, listB, dataInListA);
108  // NOTE: listA, listB and dataInListA must stay in scope with sorted
109 
110  // Overwrite original list
111  {
112  Iterator originalIter = begin;
113  DataIter sortedIter = sorted.begin();
114  for( ; originalIter != end && sorted.end() != sortedIter; ++originalIter, ++sortedIter) {
115  *originalIter = *sortedIter;
116  }
117 
118  // We should do something to ensure we ddidn't lose values...
119  }
120  metrics.done();
121  }
122 
123  /** Sort the values in data in constant memory by removing the disassembling
124  * data, sorting the values and reassembling it.
125  */
126  void sort(DataList& data) {
127  if(data.isEmpty() || data.end() == data.begin() + 1) {
128  return;
129  }
130 
131  // Remove from argument
132  ListList listA;
133  for(Iterator iter = data.begin(); data.end() != data.begin(); iter = data.begin()) {
134  listA.push_back(DataList());
135  ListIter added = listA.end() - 1;
136  DataIter dest = added->end();
137  moveBefore(iter, dest);
138  }
139 
140  // Create second ListList, location flag, and merge
141  ListList listB;
142  bool dataInListA = true;
143  DataList& sorted = mergeSort(listA, listB, dataInListA);
144  // NOTE: listA, listB and dataInListA must stay in scope with sorted
145 
146  // Populate argument
147  moveAll(sorted, data);
148  }
149 
150  private:
151 
152  /** merge listA and listB such that which list data is in at the start and
153  * end is determined by dataInListA.
154  *
155  * listA and listB each contain DataLists.
156  *
157  * At the start of each round of merging, the one used for input has N > 1
158  * DataLists with the first N-1 of length M and the last of length <M.
159  * Merging will move the data back and for between each of listA
160  * and listB. After each pass of merging, the one merged into will have N/2
161  * (rounded up) DataLists.
162  *
163  * Upon completion, the list with data will have one DataList -- the results.
164  *
165  * \param listA to be used in merge sorting and, if dataInListA contains the data to be merged
166  * \param listB to be used in merge sorting and, if dataInListB contains the data to be merged
167  *
168  * \return convenience reference to the final DataList which is the only
169  * element contained in (dataIsInListA ? listA or listB).
170  *
171  * \note The return value is \code *(dataInListA ? listA : listB).begin(); \endcode
172  * This means that all three arguments must remain in scope for the return value to
173  * remain valid.
174  */
175  DataList& mergeSort(ListList& listA, ListList& listB, bool& dataInListA) {
176  metrics.reset();
177  while(true) {
178  ListList& input = dataInListA ? listA : listB;
179  ListList& output = dataInListA ? listB : listA;
180 
181  if(input.end() == input.begin() + 1) {
182  break;
183  }
184 
185  dataInListA = ! dataInListA;
186  mergeLists(input, output);
187  }
188 
189  return *(dataInListA ? listA : listB).begin();
190  }
191 
192  /** Perform one iteration of merging of sequential pairs of lists in input
193  * to ouput.
194  *
195  * Each pair of lists in input is merged to a single list in output. If
196  * input has an odd number of lists, the last list is moved in without
197  * any merge necessary.
198  *
199  * \param input List of sequential pairs of sorted DataList to merge together
200  * \param output the list to write the output DataLists to.
201  */
202  void mergeLists(ListList& input, ListList& output) {
203  output.clear();
204  // Pass across input list
205  ListIter listIter = input.begin();
206  while(input.end() != listIter) {
207  // Create new DataList for merge(DataList, DataList) -> DataList
208  output.push_back(DataList());
209  ListIter current = output.end() - 1;
210 
211  // Grab next one or two (if available) from input
212  ListIter first = listIter;
213  ++listIter;
214 
215  ListIter second = listIter;
216  ++listIter;
217 
218  // Merge the one and possible second list together
219  if(input.end() == second) {
220  // No second list, copy first as new entry in output
221  moveAll(*first, *current);
222  } else {
223  // Two lists, just merge them
224  mergeTwo(*first, *second, *current);
225  }
226  }
227  }
228 
229  /** Merge two sorted DataList elements, first and second, into out
230  *
231  * \param first DataList to merge with second into out
232  * \param second DataList to merge with first into out
233  * \param out DataList containing the merge sort of first and second
234  */
235  void mergeTwo(DataList& first, DataList& second, DataList& out) {
236  // Merge first and second into new entry in output
237  DataIter dest = out.end();
238  while(!first.isEmpty() && !second.isEmpty()) {
239  DataIter firstIter = first.begin();
240  DataIter secondIter = second.begin();
241  metrics.compare(*firstIter, *secondIter);
242  if(lessor(*firstIter, *secondIter)) {
243  metrics.swap();
244  moveBefore(firstIter, dest);
245  } else {
246  moveBefore(secondIter, dest);
247  }
248  }
249 
250  // When first or second is empty, we 'merge' by moving the remaining values
251  // of the other to the end of out.
252  moveAll(first, out);
253  moveAll(second, out);
254  }
255 
256  /** Move all values from from to the end of to
257  *
258  * \param from to move all values, if any, to the end of to
259  * \param to to move all values, if any, from from to the end of
260  */
261  void moveAll(DataList& from, DataList& to) {
262  while(!from.isEmpty()) {
263  DataIter iter = from.begin();
264  DataIter dest = to.end();
265  moveBefore(iter, dest);
266  }
267  }
268 
269  private:
270  /** Comparator to decide if one value is less than another */
271  Lessor lessor;
272 
273  public:
274  /** Collection of metrics for the caller to inspect details of the sort */
275  Metrics metrics;
276  };
277 
278 } // namespace Experiment
279 
280 #endif // LIST_MERGE_SORT_H
Double Linked List defintion.
DoubleLinkedList which can be iterated via DoubleLinkedList::iterator.
void push_back(const value_type &value)
Insert value as the last item in this list.
Iterator class that works genericly on a List containing Node elements with data of type T.
Definition: Iterator.h:33
Merge Sort algorithm using lists to hold the data.
Definition: ListMergeSort.h:60
DoubleLinkedList< T > DataList
Convenience typedef of the type of list used in this sort.
Definition: ListMergeSort.h:66
void sort(DataList &data)
Sort the values in data in constant memory by removing the disassembling data, sorting the values and...
T value_type
Convenience typedef of the type of data in the list.
Definition: ListMergeSort.h:63
Metrics metrics
Collection of metrics for the caller to inspect details of the sort.
DataList::iterator DataIter
Convenience typedef of the iterator of DataList.
Definition: ListMergeSort.h:69
void sort(const Iterator begin, const Iterator end)
Sort from begin to end by copying.
Definition: ListMergeSort.h:91
Do-nothing Metric-collector for major actions done by ListMergeSort.
Definition: ListMergeSort.h:34
void done()
The sort completed.
Definition: ListMergeSort.h:43
void compare(const T &a, const T &b)
a and b are compared
Definition: ListMergeSort.h:37
void reset()
Metrics should be reset due to starting a new sort.
Definition: ListMergeSort.h:46
void swap()
Two items were swapped.
Definition: ListMergeSort.h:40
This file is to be included at the end of Iterator.h.
void moveBefore(Iterator< T, List, Node > &a, Iterator< T, List, Node > &b)
Move the value at a before b.
Definition: Iterator.h:100