Implementation of Radix Sort algorithm for sorting integers in c++Improving performance when sorting array of...
Is it legal for company to use my work email to pretend I still work there?
What are the differences between the usage of 'it' and 'they'?
Do I have a twin with permutated remainders?
How to add double frame in tcolorbox?
Why, historically, did Gödel think CH was false?
Is it possible to do 50 km distance without any previous training?
What is the word for reserving something for yourself before others do?
The use of multiple foreign keys on same column in SQL Server
Schoenfled Residua test shows proportionality hazard assumptions holds but Kaplan-Meier plots intersect
Unknown notation: What do three bars mean?
Why Is Death Allowed In the Matrix?
Why doesn't H₄O²⁺ exist?
Accidentally leaked the solution to an assignment, what to do now? (I'm the prof)
Why was the small council so happy for Tyrion to become the Master of Coin?
Watching something be written to a file live with tail
Why not use SQL instead of GraphQL?
Smoothness of finite-dimensional functional calculus
Why is Minecraft giving an OpenGL error?
Why does Kotter return in Welcome Back Kotter?
What do the dots in this tr command do: tr .............A-Z A-ZA-Z <<< "JVPQBOV" (with 13 dots)
What does "Puller Prush Person" mean?
Is it tax fraud for an individual to declare non-taxable revenue as taxable income? (US tax laws)
Can a Warlock become Neutral Good?
Have astronauts in space suits ever taken selfies? If so, how?
Implementation of Radix Sort algorithm for sorting integers in c++
Improving performance when sorting array of structs by multiple fieldsSorting millions of integersAdaptive counting sort for integer arrays in JavaExact sort - sorting with few move operationsImplement LSD radix sort in pythonSpaceSort - A new sorting algorithmRadix sort implementationCompare 2 unordered, rooted trees for shape-isomorphismFollow-up 1: Compare 2 unordered, rooted trees for shape-isomorphismC++ - Radix sort implementation
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
$begingroup$
I wrote the following code for Radix Sort algorithm for number sorting. Any review is highly appreciated.
You can also view and run/test the code here Radix Sort
#include<iostream>
using namespace std;
int getNumberAtPosition(int num,int position){
return (num/position)%10;
}
void radixSort(int array[],int length){
int sizeOfEachBucket = length;
int numberOfBuckets = 10;
int buckets[10][sizeOfEachBucket];
int large = 0;
int maxPasses = 0;
//finding largest number from array
for(int i=0; i<length; i++){
if(array[i]>large){
large = array[i];
}
}
//finding the number of passes
while(large != 0){
maxPasses++;
large = large/10;
}
cout<<"Max passes ="<<maxPasses<<endl;
int position = 1;
int bucketIndex = 0;
int newListIndex = 0;
int arrayLengths[10];
for(int i=0; i<maxPasses; i++){
//cout<<"i ="<<i<<endl;
for(int k=0; k<=9; k++){
//cout<<"k ="<<k<<endl;
bucketIndex = 0;
for(int j=0; j<length; j++){
if(k==getNumberAtPosition(array[j],position)){
buckets[k][bucketIndex] = array[j];
bucketIndex++;
}
}
arrayLengths[k] = bucketIndex;
}
position = position*10;
int newArrayIndex = 0;
for(int k=0; k<=9; k++){
//cout<<"k ="<<k<<endl;
bucketIndex = 0;
for(int x=0; x<arrayLengths[k];x++){
array[newArrayIndex] = buckets[k][x];
newArrayIndex++;
}
}
}
for(int i=0; i<length; i++){
cout<<array[i]<<"t";
}
}
c++ algorithm sorting
$endgroup$
add a comment |
$begingroup$
I wrote the following code for Radix Sort algorithm for number sorting. Any review is highly appreciated.
You can also view and run/test the code here Radix Sort
#include<iostream>
using namespace std;
int getNumberAtPosition(int num,int position){
return (num/position)%10;
}
void radixSort(int array[],int length){
int sizeOfEachBucket = length;
int numberOfBuckets = 10;
int buckets[10][sizeOfEachBucket];
int large = 0;
int maxPasses = 0;
//finding largest number from array
for(int i=0; i<length; i++){
if(array[i]>large){
large = array[i];
}
}
//finding the number of passes
while(large != 0){
maxPasses++;
large = large/10;
}
cout<<"Max passes ="<<maxPasses<<endl;
int position = 1;
int bucketIndex = 0;
int newListIndex = 0;
int arrayLengths[10];
for(int i=0; i<maxPasses; i++){
//cout<<"i ="<<i<<endl;
for(int k=0; k<=9; k++){
//cout<<"k ="<<k<<endl;
bucketIndex = 0;
for(int j=0; j<length; j++){
if(k==getNumberAtPosition(array[j],position)){
buckets[k][bucketIndex] = array[j];
bucketIndex++;
}
}
arrayLengths[k] = bucketIndex;
}
position = position*10;
int newArrayIndex = 0;
for(int k=0; k<=9; k++){
//cout<<"k ="<<k<<endl;
bucketIndex = 0;
for(int x=0; x<arrayLengths[k];x++){
array[newArrayIndex] = buckets[k][x];
newArrayIndex++;
}
}
}
for(int i=0; i<length; i++){
cout<<array[i]<<"t";
}
}
c++ algorithm sorting
$endgroup$
add a comment |
$begingroup$
I wrote the following code for Radix Sort algorithm for number sorting. Any review is highly appreciated.
You can also view and run/test the code here Radix Sort
#include<iostream>
using namespace std;
int getNumberAtPosition(int num,int position){
return (num/position)%10;
}
void radixSort(int array[],int length){
int sizeOfEachBucket = length;
int numberOfBuckets = 10;
int buckets[10][sizeOfEachBucket];
int large = 0;
int maxPasses = 0;
//finding largest number from array
for(int i=0; i<length; i++){
if(array[i]>large){
large = array[i];
}
}
//finding the number of passes
while(large != 0){
maxPasses++;
large = large/10;
}
cout<<"Max passes ="<<maxPasses<<endl;
int position = 1;
int bucketIndex = 0;
int newListIndex = 0;
int arrayLengths[10];
for(int i=0; i<maxPasses; i++){
//cout<<"i ="<<i<<endl;
for(int k=0; k<=9; k++){
//cout<<"k ="<<k<<endl;
bucketIndex = 0;
for(int j=0; j<length; j++){
if(k==getNumberAtPosition(array[j],position)){
buckets[k][bucketIndex] = array[j];
bucketIndex++;
}
}
arrayLengths[k] = bucketIndex;
}
position = position*10;
int newArrayIndex = 0;
for(int k=0; k<=9; k++){
//cout<<"k ="<<k<<endl;
bucketIndex = 0;
for(int x=0; x<arrayLengths[k];x++){
array[newArrayIndex] = buckets[k][x];
newArrayIndex++;
}
}
}
for(int i=0; i<length; i++){
cout<<array[i]<<"t";
}
}
c++ algorithm sorting
$endgroup$
I wrote the following code for Radix Sort algorithm for number sorting. Any review is highly appreciated.
You can also view and run/test the code here Radix Sort
#include<iostream>
using namespace std;
int getNumberAtPosition(int num,int position){
return (num/position)%10;
}
void radixSort(int array[],int length){
int sizeOfEachBucket = length;
int numberOfBuckets = 10;
int buckets[10][sizeOfEachBucket];
int large = 0;
int maxPasses = 0;
//finding largest number from array
for(int i=0; i<length; i++){
if(array[i]>large){
large = array[i];
}
}
//finding the number of passes
while(large != 0){
maxPasses++;
large = large/10;
}
cout<<"Max passes ="<<maxPasses<<endl;
int position = 1;
int bucketIndex = 0;
int newListIndex = 0;
int arrayLengths[10];
for(int i=0; i<maxPasses; i++){
//cout<<"i ="<<i<<endl;
for(int k=0; k<=9; k++){
//cout<<"k ="<<k<<endl;
bucketIndex = 0;
for(int j=0; j<length; j++){
if(k==getNumberAtPosition(array[j],position)){
buckets[k][bucketIndex] = array[j];
bucketIndex++;
}
}
arrayLengths[k] = bucketIndex;
}
position = position*10;
int newArrayIndex = 0;
for(int k=0; k<=9; k++){
//cout<<"k ="<<k<<endl;
bucketIndex = 0;
for(int x=0; x<arrayLengths[k];x++){
array[newArrayIndex] = buckets[k][x];
newArrayIndex++;
}
}
}
for(int i=0; i<length; i++){
cout<<array[i]<<"t";
}
}
c++ algorithm sorting
c++ algorithm sorting
edited Mar 29 at 7:27
Emma
1631214
1631214
asked Mar 29 at 6:11
DeepeshkumarDeepeshkumar
232
232
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
First things first, don't use
using namespace std
in header files, where your radix sort implementation should be. Besides, convenience isn't a valid excuse when the only thing you import fromstd
iscout
: just typestd::cout
and you're done.One liner functions are often useless and noisy: you need to refer to the implementation to know exactly what they do, so they don't make the code more readable, and you have to come up with a name, which is not always easy. In the case of
getNumberAtPosition
, for instance, it's impossible to tell from the name if the position is meant for the most or least significant digit, and both are equally likely in a radix sort algorithm.everything that isn't meant to change should be
const
. The only place where it isn't idiomatic is in function signature, where you often don't tag built-in type arguments passed by value as const.Also, don't alias variables:
length
is only used to definesizeOfEachBucket
, that's two names to track down instead of one.Use the standard library: there may not be many things inside compared to other languages, but what's inside is very well implemented. It will also make your code more concise and expressive. For instance, the largest element in a
[first, last)
sequence is the result ofstd::max_element(first, last)
(std::max_element
resides in<algorithm>
). Using standard containers is also a statement: a constant size array will be astd::array
, whereas a variable-size one will be astd::vector
.Avoid naked loops: by that I mean loops like
for (int i = 0; i < z; ++i)
. The nested ones are particularly difficult to read, with all those meaningless one-letter variable names. Use either range based for loops when you iterate over the whole container (e.g:for (auto item : vector)
) or named algorithm when your loop has a standardly implemented purpose (std::for_each
,std::copy
, etc.).When implementing your own algorithms, try to use an stl-like interface: iterators are preferable because they abstract the concrete container-type. Your algorithm won't work on an
std::list
although it very well could be (radix sort doesn't rely on random access like quick sort does).
Here's an example of better-looking (though not thoroughly tested) code:
#include <algorithm>
#include <vector>
#include <array>
#include <cmath>
template <typename Iterator>
void radix_sort(Iterator first, Iterator last) {
const int max_divisor = std::pow(10, std::log10(*std::max_element(first, last)));
for (int divisor = 1; divisor < max_divisor; divisor *= 10) {
std::array<std::vector<int>, 10> buckets;
std::for_each(first, last, [&buckets, divisor](auto i) {
buckets[(i / divisor) % 10].push_back(i);
});
auto out = first;
for (const auto& bucket : buckets) {
out = std::copy(bucket.begin(), bucket.end(), out);
}
}
}
EDIT: since the algorithm exposed in the question relies on decimal digits, I also formulated a base-10 based algorithm. But thinking back about this, I feel like my answer isn't complete if I don't precise that a base-two approach is more optimal (and more generally used as far as I know). Why is that?
because binary arithmetic is easier for a computer (not a very strong reason since decimal arithmetic is often optimized into binary arithmetic by the compiler);
because -and that's a much stronger reason- you can the rely on a very well-known algorithm to distribute your number between buckets, an algorithm that moreover does it in place, thus without any memory allocation;
by the way, that algorithm is
std::stable_partition
And here is a sample:
template <typename Iterator>
void binary_radix_sort(Iterator first, Iterator last) {
using integer_type = std::decay_t<decltype(*first)>;
bool finished = false;
for (integer_type mask = 1; !finished; mask <<= 1) {
finished = true;
std::stable_partition(first, last, [mask, &finished](auto i) {
if (mask < i) finished = false;
return !(mask & i);
});
}
}
$endgroup$
$begingroup$
Thanks for such a valuable advice!
$endgroup$
– Deepeshkumar
Mar 29 at 17:34
4
$begingroup$
I have to strongly disagree with #2. One line functions often provide important abstractions that are invaluable and significantly reduce cognitive load
$endgroup$
– miscco
Mar 29 at 18:12
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216460%2fimplementation-of-radix-sort-algorithm-for-sorting-integers-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
First things first, don't use
using namespace std
in header files, where your radix sort implementation should be. Besides, convenience isn't a valid excuse when the only thing you import fromstd
iscout
: just typestd::cout
and you're done.One liner functions are often useless and noisy: you need to refer to the implementation to know exactly what they do, so they don't make the code more readable, and you have to come up with a name, which is not always easy. In the case of
getNumberAtPosition
, for instance, it's impossible to tell from the name if the position is meant for the most or least significant digit, and both are equally likely in a radix sort algorithm.everything that isn't meant to change should be
const
. The only place where it isn't idiomatic is in function signature, where you often don't tag built-in type arguments passed by value as const.Also, don't alias variables:
length
is only used to definesizeOfEachBucket
, that's two names to track down instead of one.Use the standard library: there may not be many things inside compared to other languages, but what's inside is very well implemented. It will also make your code more concise and expressive. For instance, the largest element in a
[first, last)
sequence is the result ofstd::max_element(first, last)
(std::max_element
resides in<algorithm>
). Using standard containers is also a statement: a constant size array will be astd::array
, whereas a variable-size one will be astd::vector
.Avoid naked loops: by that I mean loops like
for (int i = 0; i < z; ++i)
. The nested ones are particularly difficult to read, with all those meaningless one-letter variable names. Use either range based for loops when you iterate over the whole container (e.g:for (auto item : vector)
) or named algorithm when your loop has a standardly implemented purpose (std::for_each
,std::copy
, etc.).When implementing your own algorithms, try to use an stl-like interface: iterators are preferable because they abstract the concrete container-type. Your algorithm won't work on an
std::list
although it very well could be (radix sort doesn't rely on random access like quick sort does).
Here's an example of better-looking (though not thoroughly tested) code:
#include <algorithm>
#include <vector>
#include <array>
#include <cmath>
template <typename Iterator>
void radix_sort(Iterator first, Iterator last) {
const int max_divisor = std::pow(10, std::log10(*std::max_element(first, last)));
for (int divisor = 1; divisor < max_divisor; divisor *= 10) {
std::array<std::vector<int>, 10> buckets;
std::for_each(first, last, [&buckets, divisor](auto i) {
buckets[(i / divisor) % 10].push_back(i);
});
auto out = first;
for (const auto& bucket : buckets) {
out = std::copy(bucket.begin(), bucket.end(), out);
}
}
}
EDIT: since the algorithm exposed in the question relies on decimal digits, I also formulated a base-10 based algorithm. But thinking back about this, I feel like my answer isn't complete if I don't precise that a base-two approach is more optimal (and more generally used as far as I know). Why is that?
because binary arithmetic is easier for a computer (not a very strong reason since decimal arithmetic is often optimized into binary arithmetic by the compiler);
because -and that's a much stronger reason- you can the rely on a very well-known algorithm to distribute your number between buckets, an algorithm that moreover does it in place, thus without any memory allocation;
by the way, that algorithm is
std::stable_partition
And here is a sample:
template <typename Iterator>
void binary_radix_sort(Iterator first, Iterator last) {
using integer_type = std::decay_t<decltype(*first)>;
bool finished = false;
for (integer_type mask = 1; !finished; mask <<= 1) {
finished = true;
std::stable_partition(first, last, [mask, &finished](auto i) {
if (mask < i) finished = false;
return !(mask & i);
});
}
}
$endgroup$
$begingroup$
Thanks for such a valuable advice!
$endgroup$
– Deepeshkumar
Mar 29 at 17:34
4
$begingroup$
I have to strongly disagree with #2. One line functions often provide important abstractions that are invaluable and significantly reduce cognitive load
$endgroup$
– miscco
Mar 29 at 18:12
add a comment |
$begingroup$
First things first, don't use
using namespace std
in header files, where your radix sort implementation should be. Besides, convenience isn't a valid excuse when the only thing you import fromstd
iscout
: just typestd::cout
and you're done.One liner functions are often useless and noisy: you need to refer to the implementation to know exactly what they do, so they don't make the code more readable, and you have to come up with a name, which is not always easy. In the case of
getNumberAtPosition
, for instance, it's impossible to tell from the name if the position is meant for the most or least significant digit, and both are equally likely in a radix sort algorithm.everything that isn't meant to change should be
const
. The only place where it isn't idiomatic is in function signature, where you often don't tag built-in type arguments passed by value as const.Also, don't alias variables:
length
is only used to definesizeOfEachBucket
, that's two names to track down instead of one.Use the standard library: there may not be many things inside compared to other languages, but what's inside is very well implemented. It will also make your code more concise and expressive. For instance, the largest element in a
[first, last)
sequence is the result ofstd::max_element(first, last)
(std::max_element
resides in<algorithm>
). Using standard containers is also a statement: a constant size array will be astd::array
, whereas a variable-size one will be astd::vector
.Avoid naked loops: by that I mean loops like
for (int i = 0; i < z; ++i)
. The nested ones are particularly difficult to read, with all those meaningless one-letter variable names. Use either range based for loops when you iterate over the whole container (e.g:for (auto item : vector)
) or named algorithm when your loop has a standardly implemented purpose (std::for_each
,std::copy
, etc.).When implementing your own algorithms, try to use an stl-like interface: iterators are preferable because they abstract the concrete container-type. Your algorithm won't work on an
std::list
although it very well could be (radix sort doesn't rely on random access like quick sort does).
Here's an example of better-looking (though not thoroughly tested) code:
#include <algorithm>
#include <vector>
#include <array>
#include <cmath>
template <typename Iterator>
void radix_sort(Iterator first, Iterator last) {
const int max_divisor = std::pow(10, std::log10(*std::max_element(first, last)));
for (int divisor = 1; divisor < max_divisor; divisor *= 10) {
std::array<std::vector<int>, 10> buckets;
std::for_each(first, last, [&buckets, divisor](auto i) {
buckets[(i / divisor) % 10].push_back(i);
});
auto out = first;
for (const auto& bucket : buckets) {
out = std::copy(bucket.begin(), bucket.end(), out);
}
}
}
EDIT: since the algorithm exposed in the question relies on decimal digits, I also formulated a base-10 based algorithm. But thinking back about this, I feel like my answer isn't complete if I don't precise that a base-two approach is more optimal (and more generally used as far as I know). Why is that?
because binary arithmetic is easier for a computer (not a very strong reason since decimal arithmetic is often optimized into binary arithmetic by the compiler);
because -and that's a much stronger reason- you can the rely on a very well-known algorithm to distribute your number between buckets, an algorithm that moreover does it in place, thus without any memory allocation;
by the way, that algorithm is
std::stable_partition
And here is a sample:
template <typename Iterator>
void binary_radix_sort(Iterator first, Iterator last) {
using integer_type = std::decay_t<decltype(*first)>;
bool finished = false;
for (integer_type mask = 1; !finished; mask <<= 1) {
finished = true;
std::stable_partition(first, last, [mask, &finished](auto i) {
if (mask < i) finished = false;
return !(mask & i);
});
}
}
$endgroup$
$begingroup$
Thanks for such a valuable advice!
$endgroup$
– Deepeshkumar
Mar 29 at 17:34
4
$begingroup$
I have to strongly disagree with #2. One line functions often provide important abstractions that are invaluable and significantly reduce cognitive load
$endgroup$
– miscco
Mar 29 at 18:12
add a comment |
$begingroup$
First things first, don't use
using namespace std
in header files, where your radix sort implementation should be. Besides, convenience isn't a valid excuse when the only thing you import fromstd
iscout
: just typestd::cout
and you're done.One liner functions are often useless and noisy: you need to refer to the implementation to know exactly what they do, so they don't make the code more readable, and you have to come up with a name, which is not always easy. In the case of
getNumberAtPosition
, for instance, it's impossible to tell from the name if the position is meant for the most or least significant digit, and both are equally likely in a radix sort algorithm.everything that isn't meant to change should be
const
. The only place where it isn't idiomatic is in function signature, where you often don't tag built-in type arguments passed by value as const.Also, don't alias variables:
length
is only used to definesizeOfEachBucket
, that's two names to track down instead of one.Use the standard library: there may not be many things inside compared to other languages, but what's inside is very well implemented. It will also make your code more concise and expressive. For instance, the largest element in a
[first, last)
sequence is the result ofstd::max_element(first, last)
(std::max_element
resides in<algorithm>
). Using standard containers is also a statement: a constant size array will be astd::array
, whereas a variable-size one will be astd::vector
.Avoid naked loops: by that I mean loops like
for (int i = 0; i < z; ++i)
. The nested ones are particularly difficult to read, with all those meaningless one-letter variable names. Use either range based for loops when you iterate over the whole container (e.g:for (auto item : vector)
) or named algorithm when your loop has a standardly implemented purpose (std::for_each
,std::copy
, etc.).When implementing your own algorithms, try to use an stl-like interface: iterators are preferable because they abstract the concrete container-type. Your algorithm won't work on an
std::list
although it very well could be (radix sort doesn't rely on random access like quick sort does).
Here's an example of better-looking (though not thoroughly tested) code:
#include <algorithm>
#include <vector>
#include <array>
#include <cmath>
template <typename Iterator>
void radix_sort(Iterator first, Iterator last) {
const int max_divisor = std::pow(10, std::log10(*std::max_element(first, last)));
for (int divisor = 1; divisor < max_divisor; divisor *= 10) {
std::array<std::vector<int>, 10> buckets;
std::for_each(first, last, [&buckets, divisor](auto i) {
buckets[(i / divisor) % 10].push_back(i);
});
auto out = first;
for (const auto& bucket : buckets) {
out = std::copy(bucket.begin(), bucket.end(), out);
}
}
}
EDIT: since the algorithm exposed in the question relies on decimal digits, I also formulated a base-10 based algorithm. But thinking back about this, I feel like my answer isn't complete if I don't precise that a base-two approach is more optimal (and more generally used as far as I know). Why is that?
because binary arithmetic is easier for a computer (not a very strong reason since decimal arithmetic is often optimized into binary arithmetic by the compiler);
because -and that's a much stronger reason- you can the rely on a very well-known algorithm to distribute your number between buckets, an algorithm that moreover does it in place, thus without any memory allocation;
by the way, that algorithm is
std::stable_partition
And here is a sample:
template <typename Iterator>
void binary_radix_sort(Iterator first, Iterator last) {
using integer_type = std::decay_t<decltype(*first)>;
bool finished = false;
for (integer_type mask = 1; !finished; mask <<= 1) {
finished = true;
std::stable_partition(first, last, [mask, &finished](auto i) {
if (mask < i) finished = false;
return !(mask & i);
});
}
}
$endgroup$
First things first, don't use
using namespace std
in header files, where your radix sort implementation should be. Besides, convenience isn't a valid excuse when the only thing you import fromstd
iscout
: just typestd::cout
and you're done.One liner functions are often useless and noisy: you need to refer to the implementation to know exactly what they do, so they don't make the code more readable, and you have to come up with a name, which is not always easy. In the case of
getNumberAtPosition
, for instance, it's impossible to tell from the name if the position is meant for the most or least significant digit, and both are equally likely in a radix sort algorithm.everything that isn't meant to change should be
const
. The only place where it isn't idiomatic is in function signature, where you often don't tag built-in type arguments passed by value as const.Also, don't alias variables:
length
is only used to definesizeOfEachBucket
, that's two names to track down instead of one.Use the standard library: there may not be many things inside compared to other languages, but what's inside is very well implemented. It will also make your code more concise and expressive. For instance, the largest element in a
[first, last)
sequence is the result ofstd::max_element(first, last)
(std::max_element
resides in<algorithm>
). Using standard containers is also a statement: a constant size array will be astd::array
, whereas a variable-size one will be astd::vector
.Avoid naked loops: by that I mean loops like
for (int i = 0; i < z; ++i)
. The nested ones are particularly difficult to read, with all those meaningless one-letter variable names. Use either range based for loops when you iterate over the whole container (e.g:for (auto item : vector)
) or named algorithm when your loop has a standardly implemented purpose (std::for_each
,std::copy
, etc.).When implementing your own algorithms, try to use an stl-like interface: iterators are preferable because they abstract the concrete container-type. Your algorithm won't work on an
std::list
although it very well could be (radix sort doesn't rely on random access like quick sort does).
Here's an example of better-looking (though not thoroughly tested) code:
#include <algorithm>
#include <vector>
#include <array>
#include <cmath>
template <typename Iterator>
void radix_sort(Iterator first, Iterator last) {
const int max_divisor = std::pow(10, std::log10(*std::max_element(first, last)));
for (int divisor = 1; divisor < max_divisor; divisor *= 10) {
std::array<std::vector<int>, 10> buckets;
std::for_each(first, last, [&buckets, divisor](auto i) {
buckets[(i / divisor) % 10].push_back(i);
});
auto out = first;
for (const auto& bucket : buckets) {
out = std::copy(bucket.begin(), bucket.end(), out);
}
}
}
EDIT: since the algorithm exposed in the question relies on decimal digits, I also formulated a base-10 based algorithm. But thinking back about this, I feel like my answer isn't complete if I don't precise that a base-two approach is more optimal (and more generally used as far as I know). Why is that?
because binary arithmetic is easier for a computer (not a very strong reason since decimal arithmetic is often optimized into binary arithmetic by the compiler);
because -and that's a much stronger reason- you can the rely on a very well-known algorithm to distribute your number between buckets, an algorithm that moreover does it in place, thus without any memory allocation;
by the way, that algorithm is
std::stable_partition
And here is a sample:
template <typename Iterator>
void binary_radix_sort(Iterator first, Iterator last) {
using integer_type = std::decay_t<decltype(*first)>;
bool finished = false;
for (integer_type mask = 1; !finished; mask <<= 1) {
finished = true;
std::stable_partition(first, last, [mask, &finished](auto i) {
if (mask < i) finished = false;
return !(mask & i);
});
}
}
edited yesterday
answered Mar 29 at 9:27
papagagapapagaga
4,787421
4,787421
$begingroup$
Thanks for such a valuable advice!
$endgroup$
– Deepeshkumar
Mar 29 at 17:34
4
$begingroup$
I have to strongly disagree with #2. One line functions often provide important abstractions that are invaluable and significantly reduce cognitive load
$endgroup$
– miscco
Mar 29 at 18:12
add a comment |
$begingroup$
Thanks for such a valuable advice!
$endgroup$
– Deepeshkumar
Mar 29 at 17:34
4
$begingroup$
I have to strongly disagree with #2. One line functions often provide important abstractions that are invaluable and significantly reduce cognitive load
$endgroup$
– miscco
Mar 29 at 18:12
$begingroup$
Thanks for such a valuable advice!
$endgroup$
– Deepeshkumar
Mar 29 at 17:34
$begingroup$
Thanks for such a valuable advice!
$endgroup$
– Deepeshkumar
Mar 29 at 17:34
4
4
$begingroup$
I have to strongly disagree with #2. One line functions often provide important abstractions that are invaluable and significantly reduce cognitive load
$endgroup$
– miscco
Mar 29 at 18:12
$begingroup$
I have to strongly disagree with #2. One line functions often provide important abstractions that are invaluable and significantly reduce cognitive load
$endgroup$
– miscco
Mar 29 at 18:12
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216460%2fimplementation-of-radix-sort-algorithm-for-sorting-integers-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown