NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
sorter.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2019 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19#include "sorter.hpp"
20#include "../utils/tools.hpp"
21
22using namespace std;
23
24
40bool Sorter::qSort(int* nIndex, int nElements, int nColumn, long long int nLeft, long long int nRight, int nSign)
41{
42 // Ensure that all necessary paramters are available and valid
43 if (!nIndex || !nElements || nLeft < 0 || nRight > nElements || nRight < nLeft)
44 {
45 return false;
46 }
47
48 // Ignore all invalid data points, which are at the
49 // lower "right" end of the data set
50 while (nRight >= nLeft && !isValue(nIndex[nRight], nColumn))
51 {
52 nRight--;
53 }
54
55 // Ensure that the right border is larger or equal to zero
56 if (nRight < 0)
57 return false;
58
59 int nPos = nRight;
60
61 // swap all invalid values to the right end of the array
62 while (nPos >= nLeft)
63 {
64 if (!isValue(nIndex[nPos], nColumn))
65 {
66 int nTemp = nIndex[nPos];
67 nIndex[nPos] = nIndex[nRight];
68 nIndex[nRight] = nTemp;
69 nRight--;
70 }
71 nPos--;
72 }
73
74 // Redirect the control to the quicksort implementation
75 return qSortImplementation(nIndex, nElements, nColumn, nLeft, nRight, nSign);
76}
77
78
93bool Sorter::qSortImplementation(int* nIndex, int nElements, int nColumn, long long int nLeft, long long int nRight, int nSign)
94{
95 // Ensure that all parameters are available and valid
96 if (!nIndex || !nElements || nLeft < 0 || nRight > nElements || nRight < nLeft)
97 {
98 return false;
99 }
100
101 // If the left and right border are equal, return.
102 // This section is already sorted
103 if (nRight == nLeft)
104 return true;
105
106 // Catch the cases, where the distance between the left
107 // and the right border equals to one
108 if (nRight - nLeft <= 1 && (nSign * compare(nIndex[nLeft], nIndex[nRight], nColumn) <= 0))
109 return true;
110 else if (nRight - nLeft <= 1 && (nSign * compare(nIndex[nLeft], nIndex[nRight], nColumn) >= 0))
111 {
112 int nTemp = nIndex[nLeft];
113 nIndex[nLeft] = nIndex[nRight];
114 nIndex[nRight] = nTemp;
115 return true;
116 }
117
118 // Move the middle element to the right
119 int nTemp = nIndex[nRight];
120 nIndex[nRight] = nIndex[(nRight+nLeft)/2];
121 nIndex[(nRight+nLeft)/2] = nTemp;
122
123 // Define pivot and running indices
124 int nPivot = nRight;
125 int i = nLeft;
126 int j = nRight - 1;
127
128 // Main part of the quicksort algorithm. Move all values,
129 // which are smaller than the pivot value to the left and
130 // all values, which are larger to the right
131 do
132 {
133 // Jump over all values, which are smaller
134 while (i < nRight && (nSign * compare(nIndex[i], nIndex[nPivot], nColumn) <= 0))
135 i++;
136
137 // Jump over all values, which are larger
138 while (j > nLeft && (nSign * compare(nIndex[j], nIndex[nPivot], nColumn) >= 0))
139 j--;
140
141 // Did we find two candidates, which are on the wrong side?
142 // Exchange them.
143 if (i < j)
144 {
145 int nTemp = nIndex[i];
146 nIndex[i] = nIndex[j];
147 nIndex[j] = nTemp;
148 }
149 }
150 while (i < j);
151
152 // Move the pivot element to its correct position
153 if (nSign * compare(nIndex[i], nIndex[nPivot], nColumn) > 0)
154 {
155 int nTemp = nIndex[i];
156 nIndex[i] = nIndex[nRight];
157 nIndex[nRight] = nTemp;
158 }
159
160 // Call this algorithm recursively for the left and
161 // the right sections of the whole interval
162 if (i > nLeft)
163 {
164 if (!qSortImplementation(nIndex, nElements, nColumn, nLeft, i - 1, nSign))
165 return false;
166 }
167
168 if (i < nRight)
169 {
170 if (!qSortImplementation(nIndex, nElements, nColumn, i + 1, nRight, nSign))
171 return false;
172 }
173
174 return true;
175}
176
177
196bool Sorter::sortSubList(int* nIndex, int nElements, ColumnKeys* KeyList, long long int i1, long long int i2, long long int j1, int nSign, long long int nColumns)
197{
198 // Get the subkey list
199 ColumnKeys* subKeyList = KeyList->subkeys;
200 int nTopColumn = KeyList->nKey[0];
201 int nStart = i1;
202
203 // If the subkey list is valid and contains further subkeys and the current
204 // column number is not larger than the maximal column number, search through
205 // the current column and look for blocks of equal numbers, which may be
206 // sorted using further columns
207 if (subKeyList && subKeyList->subkeys && j1 + nTopColumn < nColumns)
208 {
209 for (int k = i1 + 1; k <= i2 && k < nElements; k++)
210 {
211 // Is this the first element, which is not equal to the current
212 // start element?
213 if (compare(nIndex[k], nIndex[nStart], j1 + nTopColumn) != 0)
214 {
215 // Do only something, if this is a block of at least two
216 // equal numbers
217 if (k > nStart + 1)
218 {
219 // Sort the current block of equal numbers
220 if (!qSort(nIndex, nElements, j1 + subKeyList->nKey[0], nStart, k - 1, nSign))
221 {
222 return false;
223 }
224
225 // Redo this for this block recursively using the next columns
226 // in the ColumnKeys list
227 if (!sortSubList(nIndex, nElements, subKeyList, nStart, k - 1, j1, nSign, nColumns))
228 return false;
229 }
230
231 // Set the current number as the next start number
232 nStart = k;
233 }
234 }
235 }
236
237 return true;
238}
239
240
252ColumnKeys* Sorter::evaluateKeyList(string& sKeyList, long long int nColumnCount)
253{
254 // Create a new ColumnKeys object. The calling function is responsible
255 // for cleanup
256 ColumnKeys* keys = new ColumnKeys();
257
258 // Determine, whether a hierarchical sorting is required
259 if (sKeyList.find(':') == string::npos && sKeyList.find('[') == string::npos)
260 {
261 // In this case not. Simply set the current number as first key
262 keys->nKey[0] = StrToInt(sKeyList) - 1;
263 sKeyList.clear();
264 }
265 else
266 {
267 // In this case we want a hierarchical sorting
268 unsigned int nLastIndex = 0;
269
270 // Go through the complete keylist string and decode it into
271 // a recursive ColumnKeys object
272 for (unsigned int n = 0; n < sKeyList.length(); n++)
273 {
274 if (sKeyList[n] == ':')
275 {
276 // Found a column separator
277 if (n != nLastIndex)
278 keys->nKey[0] = StrToInt(sKeyList.substr(nLastIndex, n - nLastIndex)) - 1;
279
280 // Last element? Use the maximal number of columns as last column
281 if (n + 1 == sKeyList.length())
282 keys->nKey[1] = nColumnCount;
283
284 // Find the end of the next column key
285 for (size_t i = n + 1; i < sKeyList.length(); i++)
286 {
287 if (sKeyList[i] == '[' || sKeyList[i] == ':' || sKeyList[i] == ',')
288 {
289 keys->nKey[1] = StrToInt(sKeyList.substr(n + 1, i - n - 1));
290 sKeyList.erase(0, i + 1);
291 break;
292 }
293 else if (i + 1 == sKeyList.length())
294 {
295 if (i == n + 1)
296 keys->nKey[1] = nColumnCount;
297 else
298 keys->nKey[1] = StrToInt(sKeyList.substr(n + 1));
299
300 sKeyList.clear();
301 break;
302 }
303 }
304
305 break;
306 }
307 else if (sKeyList[n] == '[' && sKeyList.find(']', n) != string::npos)
308 {
309 // Found a hierarchical subset. Extract the hierarchical
310 // definition first
311 keys->nKey[0] = StrToInt(sKeyList.substr(nLastIndex, n - nLastIndex)) - 1;
312 string sColArray;
313
314 size_t i = getMatchingParenthesis(sKeyList.substr(n));
315
316 if (i != string::npos)
317 {
318 sColArray = sKeyList.substr(n + 1, i - 1);
319 sKeyList.erase(0, i + n + 1);
320 }
321
322 // Decode the hierarchical subset recursively and assign
323 // the returned pointer to a subfield of the ColumnKeys object
324 keys->subkeys = evaluateKeyList(sColArray, nColumnCount);
325
326 break;
327 }
328 else if (sKeyList[n] == '[')
329 {
330 // Something is wrong here. Clean up memory and return a
331 // null pointer
332 delete keys;
333 return nullptr;
334 }
335 }
336 }
337
338 return keys;
339}
340
341
ColumnKeys * evaluateKeyList(std::string &sKeyList, long long int nColumnCount)
This public member function creates a ColumnKeys object from a string containing the hierarchical sor...
Definition: sorter.cpp:252
bool qSort(int *nIndex, int nElements, int nColumn, long long int nLeft, long long int nRight, int nSign)
This public member function is the interface to the quicksort algorithm, which itself is implemented ...
Definition: sorter.cpp:40
bool qSortImplementation(int *nIndex, int nElements, int nColumn, long long int nLeft, long long int nRight, int nSign)
This private member function is the actual implementation of the quicksort algorithm.
Definition: sorter.cpp:93
virtual bool isValue(int line, int col)=0
virtual int compare(int i, int j, int col)=0
bool sortSubList(int *nIndex, int nElements, ColumnKeys *KeyList, long long int i1, long long int i2, long long int j1, int nSign, long long int nColumns)
This public member function handles the hierarchical sorting process of many columns together....
Definition: sorter.cpp:196
unsigned int getMatchingParenthesis(const StringView &)
Returns the position of the closing parenthesis.
Definition: tools.cpp:414
int StrToInt(const std::string &)
Converts a string into an integer.
Structure for the sorting functionality: used for the recursive definition of the index columns for s...
ColumnKeys * subkeys