LAL: Linear Arrangement Library 21.07.01
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
counting_sort.hpp
1/*********************************************************************
2 *
3 * Linear Arrangement Library - A library that implements a collection
4 * algorithms for linear arrangments of graphs.
5 *
6 * Copyright (C) 2019 - 2021
7 *
8 * This file is part of Linear Arrangement Library. To see the full code
9 * visit the webpage:
10 * https://github.com/lluisalemanypuig/linear-arrangement-library.git
11 *
12 * Linear Arrangement Library is free software: you can redistribute it
13 * and/or modify it under the terms of the GNU Affero General Public License
14 * as published by the Free Software Foundation, either version 3 of the
15 * License, or (at your option) any later version.
16 *
17 * Linear Arrangement Library is distributed in the hope that it will be
18 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Affero General Public License for more details.
21 *
22 * You should have received a copy of the GNU Affero General Public License
23 * along with Linear Arrangement Library. If not, see <http://www.gnu.org/licenses/>.
24 *
25 * Contact:
26 *
27 * LluĂ­s Alemany Puig (lalemany@cs.upc.edu)
28 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
29 * CQL (Complexity and Quantitative Linguistics Lab)
30 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
31 * Webpage: https://cqllab.upc.edu/people/lalemany/
32 *
33 * Ramon Ferrer i Cancho (rferrericancho@cs.upc.edu)
34 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
35 * CQL (Complexity and Quantitative Linguistics Lab)
36 * Office S124, Omega building
37 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
38 * Webpage: https://cqllab.upc.edu/people/rferrericancho/
39 *
40 ********************************************************************/
41
42#pragma once
43
44// C++ includes
45#include <functional>
46#include <tuple>
47
48// lal includes
49#include <lal/internal/data_array.hpp>
50#include <lal/internal/macros.hpp>
51
52namespace lal {
53namespace internal {
54
55namespace countingsort {
56
57// Non-decreasing type of sort.
58struct increasing_t { };
59// Non-increasing type of sort.
60struct decreasing_t { };
61
62template<typename T>
63struct memory_counting_sort {
64 data_array<std::size_t> count;
65 data_array<T> output;
66
67 memory_counting_sort(
68 const std::size_t largest_key_plus_1,
69 const std::size_t max_size_container
70 ) :
71 count(largest_key_plus_1, 0), output(max_size_container)
72 { }
73
74 ~memory_counting_sort() { }
75
76 void reset_count() { count.fill(0); }
77};
78
79} // -- namespace countingsort
80
81/*
82 * @brief Counting sort algorithm with reusable memory.
83 *
84 * This algorithm is interesting for sorting containers with non-unique values.
85 * For details on the algorithm, see https://en.wikipedia.org/wiki/Counting_sort
86 *
87 * Template parameters:
88 * @tparam T Iterated type
89 * @tparam It Iterator type
90 * @tparam sort_type One of 'increasing_t' or 'decreasing_t'.
91 * @tparam memory_has_frequencies The memory passed as parameter already conatins
92 * the frequencies for the counting sort algorithm. See code for more details.
93 *
94 * Function paremeters:
95 * @param begin Iterator at the beginning of the range.
96 * @param end Iterator at the end of the range.
97 * @param largest_key_plus_1 Integer value equal to 1 + the largest key that can
98 * be obtained with function @e key.
99 * @param key Function that returns a single integer value used to compare the
100 * elements.
101 * @param mem Reusable memory for the counting sort algorithm.
102 * @post The elements in the range [begin,end) are sorted increasingly.
103 */
104template<
105 typename T, typename It,
106 typename sort_type,
107 bool memory_has_frequencies,
108 std::enable_if_t<
109 is_pointer_iterator_v<T, It> &&
110 (
111 std::is_same_v<sort_type, countingsort::increasing_t> ||
112 std::is_same_v<sort_type, countingsort::decreasing_t>
113 ),
114 bool
115 > = true
116>
117void counting_sort(
118 It begin, It end,
119 const std::size_t largest_key_plus_1,
120 const std::function<std::size_t (const T&)>& key,
121 countingsort::memory_counting_sort<T>& mem
122)
123{
124 constexpr bool is_increasing =
125 std::is_same_v<sort_type, countingsort::increasing_t>;
126
127 // nothing to do if there are no elements to sort
128 if (begin == end) { return; }
129
130 if constexpr (not memory_has_frequencies) {
131 // calculate frequency of each element
132 for (auto it = begin; it != end; ) {
133 const std::size_t elem_key = key(*(it++));
134 ++mem.count[elem_key];
135 }
136 }
137
138 std::size_t total = 0;
139 for (std::size_t k = 0; k < largest_key_plus_1; ++k) {
140 std::tie(mem.count[k], total)
141 = std::make_pair(total, mem.count[k] + total);
142 }
143
144 std::size_t size_container = 0;
145 for (auto it = begin; it != end; ) {
146 ++size_container;
147
148 const std::size_t elem_key = key(*it);
149 mem.output[mem.count[elem_key]] = std::move(*(it++));
150 mem.count[elem_key] += 1;
151 }
152
153 // calculate output
154 if constexpr (is_increasing) {
155 auto it = begin;
156 for (std::size_t k = 0; k < size_container;) {
157 *(it++) = std::move(mem.output[k++]);
158 }
159 }
160 else {
161 auto it = begin;
162 for (std::size_t k = size_container - 1; k > 0;) {
163 *(it++) = std::move(mem.output[k--]);
164 }
165 *it = std::move(mem.output[0]);
166 }
167}
168
169/*
170 * @brief Counting sort algorithm.
171 *
172 * This algorithm is interesting for sorting containers with non-unique values.
173 * For details on the algorithm, see https://en.wikipedia.org/wiki/Counting_sort
174 *
175 * Template parameters:
176 * @tparam T Iterated type
177 * @tparam It Iterator type
178 * @tparam sort_type One of 'increasing_t' or 'decreasing_t'.
179 *
180 * Function paremeters:
181 * @param begin Iterator at the beginning of the range.
182 * @param end Iterator at the end of the range.
183 * @param M Integer value equal to the largest key that can be obtained with
184 * function @e key.
185 * @param upper_bound_size An upper bound of he size of the container to be
186 * sorted. The lowest value is std::distance(begin,end), the actual size of the
187 * container.
188 * @param key Function that returns a single integer value used to compare the
189 * elements.
190 * @post The elements in the range [begin,end) are sorted increasingly.
191 */
192template<
193 typename T, typename It,
194 typename sort_type,
195 std::enable_if_t<
196 is_pointer_iterator_v<T, It>&&
197 (
198 std::is_same_v<sort_type, countingsort::increasing_t> ||
199 std::is_same_v<sort_type, countingsort::decreasing_t>
200 ),
201 bool
202 > = true
203>
204void counting_sort(
205 It begin, It end,
206 const std::size_t largest_key,
207 const std::size_t upper_bound_size,
208 const std::function<std::size_t (const T&)>& key
209)
210{
211 // nothing to do if there are no elements to sort
212 if (begin == end) { return; }
213
214 countingsort::memory_counting_sort<T> mem(largest_key+1, upper_bound_size);
215
216 counting_sort<T, It, sort_type, false>
217 (begin, end, largest_key+1, key, mem);
218
219 // memory is freed automatically (see destructor)
220}
221
222} // -- namespace internal
223} // -- namespace lal
Main namespace of the library.
Definition definitions.hpp:48