gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
Doc improvements and source unification in radix_sort (#72)
0 2 0
default
2 files changed with 176 insertions and 174 deletions:
↑ Collapse diff ↑
Ignore white space 6 line context
1
/* -*- C++ -*-
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library
3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-2008
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
... ...
@@ -34,99 +34,99 @@
34 34

	
35 35
  namespace _radix_sort_bits {
36 36

	
37 37
    template <typename Value>
38 38
    struct Identity {
39 39
      const Value& operator()(const Value& val) {
40
	return val;
40
        return val;
41 41
      }
42 42
    };
43 43

	
44 44

	
45 45
    template <typename Value, typename Iterator, typename Functor>
46
    Iterator radixSortPartition(Iterator first, Iterator last, 
47
				Functor functor, Value mask) {
46
    Iterator radixSortPartition(Iterator first, Iterator last,
47
                                Functor functor, Value mask) {
48 48
      while (first != last && !(functor(*first) & mask)) {
49
	++first;
49
        ++first;
50 50
      }
51 51
      if (first == last) {
52
	return first;
52
        return first;
53 53
      }
54 54
      --last;
55 55
      while (first != last && (functor(*last) & mask)) {
56
	--last;
56
        --last;
57 57
      }
58 58
      if (first == last) {
59
	return first;
59
        return first;
60 60
      }
61 61
      std::iter_swap(first, last);
62 62
      ++first;
63 63
      if (!(first < last)) {
64
	return first;
64
        return first;
65 65
      }
66 66
      while (true) {
67
	while (!(functor(*first) & mask)) {
68
	  ++first;
69
	}
70
	--last;
71
	while (functor(*last) & mask) {
72
	  --last;
73
	}
74
	if (!(first < last)) {
75
	  return first;
76
	}
77
	std::iter_swap(first, last);
78
	++first;
67
        while (!(functor(*first) & mask)) {
68
          ++first;
69
        }
70
        --last;
71
        while (functor(*last) & mask) {
72
          --last;
73
        }
74
        if (!(first < last)) {
75
          return first;
76
        }
77
        std::iter_swap(first, last);
78
        ++first;
79 79
      }
80 80
    }
81 81

	
82 82
    template <typename Iterator, typename Functor>
83
    Iterator radixSortSignPartition(Iterator first, Iterator last, 
84
				    Functor functor) {
83
    Iterator radixSortSignPartition(Iterator first, Iterator last,
84
                                    Functor functor) {
85 85
      while (first != last && functor(*first) < 0) {
86
	++first;
86
        ++first;
87 87
      }
88 88
      if (first == last) {
89
	return first;
89
        return first;
90 90
      }
91 91
      --last;
92 92
      while (first != last && functor(*last) >= 0) {
93
	--last;
93
        --last;
94 94
      }
95 95
      if (first == last) {
96
	return first;
96
        return first;
97 97
      }
98 98
      std::iter_swap(first, last);
99 99
      ++first;
100 100
      if (!(first < last)) {
101
	return first;
101
        return first;
102 102
      }
103 103
      while (true) {
104
	while (functor(*first) < 0) {
105
	  ++first;
106
	}
107
	--last;
108
	while (functor(*last) >= 0) {
109
	  --last;
110
	}
111
	if (!(first < last)) {
112
	  return first;
113
	}
114
	std::iter_swap(first, last);
115
	++first;
104
        while (functor(*first) < 0) {
105
          ++first;
106
        }
107
        --last;
108
        while (functor(*last) >= 0) {
109
          --last;
110
        }
111
        if (!(first < last)) {
112
          return first;
113
        }
114
        std::iter_swap(first, last);
115
        ++first;
116 116
      }
117 117
    }
118 118

	
119 119
    template <typename Value, typename Iterator, typename Functor>
120
    void radixIntroSort(Iterator first, Iterator last, 
121
			Functor functor, Value mask) {
120
    void radixIntroSort(Iterator first, Iterator last,
121
                        Functor functor, Value mask) {
122 122
      while (mask != 0 && last - first > 1) {
123
	Iterator cut = radixSortPartition(first, last, functor, mask);
124
	mask >>= 1;
125
	radixIntroSort(first, cut, functor, mask);
126
	first = cut;
123
        Iterator cut = radixSortPartition(first, last, functor, mask);
124
        mask >>= 1;
125
        radixIntroSort(first, cut, functor, mask);
126
        first = cut;
127 127
      }
128 128
    }
129 129

	
130 130
    template <typename Value, typename Iterator, typename Functor>
131 131
    void radixSignedSort(Iterator first, Iterator last, Functor functor) {
132 132

	
... ...
@@ -135,89 +135,92 @@
135 135
      Value mask;
136 136
      int max_digit;
137 137
      Iterator it;
138 138

	
139 139
      mask = ~0; max_digit = 0;
140 140
      for (it = first; it != cut; ++it) {
141
	while ((mask & functor(*it)) != mask) {
142
	  ++max_digit;
143
	  mask <<= 1;
144
	}
141
        while ((mask & functor(*it)) != mask) {
142
          ++max_digit;
143
          mask <<= 1;
144
        }
145 145
      }
146 146
      radixIntroSort(first, cut, functor, 1 << max_digit);
147 147

	
148 148
      mask = 0; max_digit = 0;
149 149
      for (it = cut; it != last; ++it) {
150
	while ((mask | functor(*it)) != mask) {
151
	  ++max_digit;
152
	  mask <<= 1; mask |= 1;
153
	}
150
        while ((mask | functor(*it)) != mask) {
151
          ++max_digit;
152
          mask <<= 1; mask |= 1;
153
        }
154 154
      }
155 155
      radixIntroSort(cut, last, functor, 1 << max_digit);
156 156
    }
157 157

	
158 158
    template <typename Value, typename Iterator, typename Functor>
159 159
    void radixUnsignedSort(Iterator first, Iterator last, Functor functor) {
160 160

	
161 161
      Value mask = 0;
162 162
      int max_digit = 0;
163 163

	
164 164
      Iterator it;
165 165
      for (it = first; it != last; ++it) {
166
	while ((mask | functor(*it)) != mask) {
167
	  ++max_digit;
168
	  mask <<= 1; mask |= 1;
169
	}
166
        while ((mask | functor(*it)) != mask) {
167
          ++max_digit;
168
          mask <<= 1; mask |= 1;
169
        }
170 170
      }
171 171
      radixIntroSort(first, last, functor, 1 << max_digit);
172 172
    }
173 173

	
174 174

	
175
    template <typename Value, 
176
	      bool sign = std::numeric_limits<Value>::is_signed >
175
    template <typename Value,
176
              bool sign = std::numeric_limits<Value>::is_signed >
177 177
    struct RadixSortSelector {
178 178
      template <typename Iterator, typename Functor>
179 179
      static void sort(Iterator first, Iterator last, Functor functor) {
180
	radixSignedSort<Value>(first, last, functor);
180
        radixSignedSort<Value>(first, last, functor);
181 181
      }
182 182
    };
183 183

	
184 184
    template <typename Value>
185 185
    struct RadixSortSelector<Value, false> {
186 186
      template <typename Iterator, typename Functor>
187 187
      static void sort(Iterator first, Iterator last, Functor functor) {
188
	radixUnsignedSort<Value>(first, last, functor);
188
        radixUnsignedSort<Value>(first, last, functor);
189 189
      }
190 190
    };
191 191

	
192 192
  }
193 193

	
194 194
  /// \ingroup auxalg
195 195
  ///
196 196
  /// \brief Sorts the STL compatible range into ascending order.
197 197
  ///
198
  /// The \c radixSort sorts the STL compatible range into ascending
199
  /// order.  The radix sort algorithm can sort the items which mapped
200
  /// to an integer with an adaptable unary function \c functor and the
201
  /// order will be ascending by these mapped values. As function
202
  /// specialization it is possible to use a normal function instead
203
  /// of the functor object or if the functor is not given it will use
204
  /// an identity function instead.
198
  /// The \c radixSort sorts an STL compatible range into ascending
199
  /// order.  The radix sort algorithm can sort items which are mapped
200
  /// to integers with an adaptable unary function \c functor and the
201
  /// order will be ascending according to these mapped values.
205 202
  ///
206
  /// This implemented radix sort is a special quick sort which pivot
207
  /// value is choosen to partite the items on the next
208
  /// bit. Therefore, let be \c c the maximal capacity and \c n the
209
  /// number of the items in the container, the time complexity of the
210
  /// algorithm is \f$ O(\log(c)n) \f$ and the additional space
211
  /// complexity is \f$ O(\log(c)) \f$.
203
  /// It is also possible to use a normal function instead
204
  /// of the functor object. If the functor is not given it will use
205
  /// the identity function instead.
206
  ///
207
  /// This is a special quick sort algorithm where the pivot
208
  /// values to split the items are choosen to be \f$ 2^k \f$ for each \c k.
209
  /// Therefore, the time complexity of the
210
  /// algorithm is \f$ O(\log(c)n) \f$ and it uses \f$ O(\log(c)) \f$,
211
  /// additional space, where \c c is the maximal value and \c n is the
212
  /// number of the items in the container.
212 213
  ///
213 214
  /// \param first The begin of the given range.
214 215
  /// \param last The end of the given range.
215 216
  /// \param functor An adaptible unary function or a normal function
216 217
  /// which maps the items to any integer type which can be either
217 218
  /// signed or unsigned.
219
  ///
220
  /// \sa counterSort()
218 221
  template <typename Iterator, typename Functor>
219 222
  void radixSort(Iterator first, Iterator last, Functor functor) {
220 223
    using namespace _radix_sort_bits;
221 224
    typedef typename Functor::result_type Value;
222 225
    RadixSortSelector<Value>::sort(first, last, functor);
223 226
  }
... ...
@@ -258,103 +261,103 @@
258 261
    template <typename Value>
259 262
    unsigned char valueByte(Value value, int byte) {
260 263
      return value >> (std::numeric_limits<unsigned char>::digits * byte);
261 264
    }
262 265

	
263 266
    template <typename Functor, typename Key>
264
    void counterIntroSort(Key *first, Key *last, Key *target, 
265
			  int byte, Functor functor) {
266
      const int size = 
267
	unsigned(std::numeric_limits<unsigned char>::max()) + 1;
267
    void counterIntroSort(Key *first, Key *last, Key *target,
268
                          int byte, Functor functor) {
269
      const int size =
270
        unsigned(std::numeric_limits<unsigned char>::max()) + 1;
268 271
      std::vector<int> counter(size);
269 272
      for (int i = 0; i < size; ++i) {
270
	counter[i] = 0;
273
        counter[i] = 0;
271 274
      }
272 275
      Key *it = first;
273 276
      while (first != last) {
274
	++counter[valueByte(functor(*first), byte)]; 
275
	++first;
277
        ++counter[valueByte(functor(*first), byte)];
278
        ++first;
276 279
      }
277 280
      int prev, num = 0;
278 281
      for (int i = 0; i < size; ++i) {
279
	prev = num;
280
	num += counter[i];
281
	counter[i] = prev;
282
        prev = num;
283
        num += counter[i];
284
        counter[i] = prev;
282 285
      }
283 286
      while (it != last) {
284
	target[counter[valueByte(functor(*it), byte)]++] = *it;
285
	++it;
287
        target[counter[valueByte(functor(*it), byte)]++] = *it;
288
        ++it;
286 289
      }
287 290
    }
288 291

	
289 292
    template <typename Functor, typename Key>
290
    void signedCounterIntroSort(Key *first, Key *last, Key *target, 
291
				int byte, Functor functor) {
292
      const int size = 
293
	unsigned(std::numeric_limits<unsigned char>::max()) + 1;
293
    void signedCounterIntroSort(Key *first, Key *last, Key *target,
294
                                int byte, Functor functor) {
295
      const int size =
296
        unsigned(std::numeric_limits<unsigned char>::max()) + 1;
294 297
      std::vector<int> counter(size);
295 298
      for (int i = 0; i < size; ++i) {
296
	counter[i] = 0;
299
        counter[i] = 0;
297 300
      }
298 301
      Key *it = first;
299 302
      while (first != last) {
300
	counter[valueByte(functor(*first), byte)]++;
301
	++first;
303
        counter[valueByte(functor(*first), byte)]++;
304
        ++first;
302 305
      }
303 306
      int prev, num = 0;
304 307
      for (int i = size / 2; i < size; ++i) {
305
	prev = num;
306
	num += counter[i];
307
	counter[i] = prev;
308
        prev = num;
309
        num += counter[i];
310
        counter[i] = prev;
308 311
      }
309 312
      for (int i = 0; i < size / 2; ++i) {
310
	prev = num;
311
	num += counter[i];
312
	counter[i] = prev;
313
        prev = num;
314
        num += counter[i];
315
        counter[i] = prev;
313 316
      }
314 317
      while (it != last) {
315
	target[counter[valueByte(functor(*it), byte)]++] = *it;
316
	++it;
318
        target[counter[valueByte(functor(*it), byte)]++] = *it;
319
        ++it;
317 320
      }
318 321
    }
319 322

	
320
  
323

	
321 324
    template <typename Value, typename Iterator, typename Functor>
322 325
    void counterSignedSort(Iterator first, Iterator last, Functor functor) {
323 326
      if (first == last) return;
324 327
      typedef typename std::iterator_traits<Iterator>::value_type Key;
325 328
      typedef std::allocator<Key> Allocator;
326 329
      Allocator allocator;
327 330

	
328 331
      int length = std::distance(first, last);
329 332
      Key* buffer = allocator.allocate(2 * length);
330 333
      try {
331
	bool dir = true;
332
	std::copy(first, last, buffer);
333
	for (int i = 0; i < int(sizeof(Value)) - 1; ++i) {
334
	  if (dir) {
335
	    counterIntroSort(buffer, buffer + length, buffer + length, 
336
			     i, functor);
337
	  } else {
338
	    counterIntroSort(buffer + length, buffer + 2 * length, buffer, 
339
			     i, functor);
340
	  }
341
	  dir = !dir;
342
	}
343
	if (dir) {
344
	  signedCounterIntroSort(buffer, buffer + length, buffer + length, 
345
				 sizeof(Value) - 1, functor);
346
	  std::copy(buffer + length, buffer + 2 * length, first);
347
	}	else {
348
	  signedCounterIntroSort(buffer + length, buffer + 2 * length, buffer, 
349
				 sizeof(Value) - 1, functor);
350
	  std::copy(buffer, buffer + length, first);
351
	}
334
        bool dir = true;
335
        std::copy(first, last, buffer);
336
        for (int i = 0; i < int(sizeof(Value)) - 1; ++i) {
337
          if (dir) {
338
            counterIntroSort(buffer, buffer + length, buffer + length,
339
                             i, functor);
340
          } else {
341
            counterIntroSort(buffer + length, buffer + 2 * length, buffer,
342
                             i, functor);
343
          }
344
          dir = !dir;
345
        }
346
        if (dir) {
347
          signedCounterIntroSort(buffer, buffer + length, buffer + length,
348
                                 sizeof(Value) - 1, functor);
349
          std::copy(buffer + length, buffer + 2 * length, first);
350
        }        else {
351
          signedCounterIntroSort(buffer + length, buffer + 2 * length, buffer,
352
                                 sizeof(Value) - 1, functor);
353
          std::copy(buffer, buffer + length, first);
354
        }
352 355
      } catch (...) {
353
	allocator.deallocate(buffer, 2 * length);
354
	throw;
356
        allocator.deallocate(buffer, 2 * length);
357
        throw;
355 358
      }
356 359
      allocator.deallocate(buffer, 2 * length);
357 360
    }
358 361

	
359 362
    template <typename Value, typename Iterator, typename Functor>
360 363
    void counterUnsignedSort(Iterator first, Iterator last, Functor functor) {
... ...
@@ -363,87 +366,86 @@
363 366
      typedef std::allocator<Key> Allocator;
364 367
      Allocator allocator;
365 368

	
366 369
      int length = std::distance(first, last);
367 370
      Key *buffer = allocator.allocate(2 * length);
368 371
      try {
369
	bool dir = true;
370
	std::copy(first, last, buffer);
371
	for (int i = 0; i < int(sizeof(Value)); ++i) {
372
	  if (dir) {
373
	    counterIntroSort(buffer, buffer + length, 
374
			     buffer + length, i, functor);
375
	  } else {
376
	    counterIntroSort(buffer + length, buffer + 2 * length, 
377
			     buffer, i, functor);
378
	  }
379
	  dir = !dir;
380
	}
381
	if (dir) {
382
	  std::copy(buffer, buffer + length, first);
383
	}	else {
384
	  std::copy(buffer + length, buffer + 2 * length, first);
385
	}
372
        bool dir = true;
373
        std::copy(first, last, buffer);
374
        for (int i = 0; i < int(sizeof(Value)); ++i) {
375
          if (dir) {
376
            counterIntroSort(buffer, buffer + length,
377
                             buffer + length, i, functor);
378
          } else {
379
            counterIntroSort(buffer + length, buffer + 2 * length,
380
                             buffer, i, functor);
381
          }
382
          dir = !dir;
383
        }
384
        if (dir) {
385
          std::copy(buffer, buffer + length, first);
386
        }        else {
387
          std::copy(buffer + length, buffer + 2 * length, first);
388
        }
386 389
      } catch (...) {
387
	allocator.deallocate(buffer, 2 * length);
388
	throw;
390
        allocator.deallocate(buffer, 2 * length);
391
        throw;
389 392
      }
390 393
      allocator.deallocate(buffer, 2 * length);
391 394
    }
392 395

	
393 396

	
394 397

	
395
    template <typename Value, 
396
	      bool sign = std::numeric_limits<Value>::is_signed >
398
    template <typename Value,
399
              bool sign = std::numeric_limits<Value>::is_signed >
397 400
    struct CounterSortSelector {
398 401
      template <typename Iterator, typename Functor>
399 402
      static void sort(Iterator first, Iterator last, Functor functor) {
400
	counterSignedSort<Value>(first, last, functor);
403
        counterSignedSort<Value>(first, last, functor);
401 404
      }
402 405
    };
403 406

	
404 407
    template <typename Value>
405 408
    struct CounterSortSelector<Value, false> {
406 409
      template <typename Iterator, typename Functor>
407 410
      static void sort(Iterator first, Iterator last, Functor functor) {
408
	counterUnsignedSort<Value>(first, last, functor);
411
        counterUnsignedSort<Value>(first, last, functor);
409 412
      }
410 413
    };
411 414

	
412 415
  }
413 416

	
414 417
  /// \ingroup auxalg
415 418
  ///
416
  /// \brief Sorts stable the STL compatible range into ascending order.
419
  /// \brief Sorts the STL compatible range into ascending order in a stable
420
  /// way.
417 421
  ///
418
  /// The \c counterSort sorts the STL compatible range into ascending
419
  /// order.  The counter sort algorithm can sort the items which
420
  /// mapped to an integer with an adaptable unary function \c functor
421
  /// and the order will be ascending by these mapped values. As
422
  /// function specialization it is possible to use a normal function
423
  /// instead of the functor object or if the functor is not given it
424
  /// will use an identity function instead.
422
  /// This function sorts an STL compatible range into ascending
423
  /// order according to an integer mapping in the same as radixSort() does.
425 424
  ///
426
  /// The implemented counter sort use a radix forward sort on the
425
  /// This sorting algorithm is stable, i.e. the order of two equal
426
  /// element remains the same after the sorting.
427
  ///
428
  /// This sort algorithm  use a radix forward sort on the
427 429
  /// bytes of the integer number. The algorithm sorts the items
428
  /// byte-by-byte, first it counts how many times occurs a byte value
429
  /// in the containerm, and with the occurence number the container
430
  /// can be copied to an other in asceding order in \c O(n) time.
431
  /// Let be \c c the maximal capacity of the integer type and \c n
432
  /// the number of the items in the container, the time complexity of
433
  /// the algorithm is \f$ O(\log(c)n) \f$ and the additional space
434
  /// complexity is \f$ O(n) \f$.
430
  /// byte-by-byte. First, it counts how many times a byte value occurs
431
  /// in the container, then it copies the corresponding items to
432
  /// another container in asceding order in \c O(n) time.
435 433
  ///
436
  /// The sorting algorithm is stable, i.e. the order of two equal
437
  /// element remains the same.
434
  /// The time complexity of the algorithm is \f$ O(\log(c)n) \f$ and
435
  /// it uses \f$ O(n) \f$, additional space, where \c c is the
436
  /// maximal value and \c n is the number of the items in the
437
  /// container.
438 438
  ///
439

	
439 440
  /// \param first The begin of the given range.
440 441
  /// \param last The end of the given range.
441 442
  /// \param functor An adaptible unary function or a normal function
442 443
  /// which maps the items to any integer type which can be either
443 444
  /// signed or unsigned.
445
  /// \sa radixSort()
444 446
  template <typename Iterator, typename Functor>
445 447
  void counterSort(Iterator first, Iterator last, Functor functor) {
446 448
    using namespace _radix_sort_bits;
447 449
    typedef typename Functor::result_type Value;
448 450
    CounterSortSelector<Value>::sort(first, last, functor);
449 451
  }
Ignore white space 12 line context
1
/* -*- C++ -*-
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library
3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-2008
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
... ...
@@ -78,14 +78,14 @@
78 78

	
79 79
    radixSort(data2.begin(), data2.end(), negate);
80 80
    for (int i = 0; i < n; ++i) {
81 81
      check(data1[i] == data2[n - 1 - i], "Test failed");
82 82
    }
83 83

	
84
  } 
85
  
84
  }
85

	
86 86
  {
87 87
    std::vector<unsigned char> data1(n);
88 88
    generateCharSequence(n, data1);
89 89

	
90 90
    std::vector<unsigned char> data2(data1);
91 91
    std::sort(data1.begin(), data1.end());
... ...
@@ -118,13 +118,13 @@
118 118
    }
119 119

	
120 120
    counterSort(data2.begin(), data2.end(), negate);
121 121
    for (int i = 0; i < n; ++i) {
122 122
      check(data1[i] == data2[n - 1 - i], "Test failed");
123 123
    }
124
  } 
124
  }
125 125

	
126 126
  {
127 127
    std::vector<unsigned char> data1(n);
128 128
    generateCharSequence(n, data1);
129 129

	
130 130
    std::vector<unsigned char> data2(data1);
... ...
@@ -137,11 +137,11 @@
137 137

	
138 138
  }
139 139
}
140 140

	
141 141
int main() {
142 142

	
143
  checkRadixSort();  
143
  checkRadixSort();
144 144
  checkCounterSort();
145 145

	
146 146
  return 0;
147 147
}
0 comments (0 inline)