Home c++ Implement Counting Sort in the style of C++

Implement Counting Sort in the style of C++

Author

Date

Category

it became interesting how to arrange the sorting algorithm by counting from C++ standards for sorting arbitrary objects, and not just numbers. The advantage of this sorting, in addition to speed, is that it is stable, that is, if the set of some objects is crighted with integers, but the algorithm will not mix objects with the same norm. You can either set the normalization function, or create a “object – number” pair, which are transmitted to the sort function. Here is the code:

# include & lt; iostream & gt;
#Include & lt; vector & gt;
#Include & lt; Iterator & GT;
// Sort counting
Void CSORT (Const std :: vector & lt; int & gt; in, std :: vector & lt; int & gt; & amp; out, int max) {
  INT * C = NEW INT [MAX + 1];
  STD :: MEMSET (C, 0, (MAX + 1) * SIZEOF (INT));
  Out.Resize (in.size ());
  for (int i = 0; i & lt; in.size (); i ++)
    C [in.at (i)] ++;
  for (int i = 1; i & lt; max + 1; i ++)
    C [i] = C [i] + C [I - 1];
  For (int i = in.size () - 1; I & gt; = 0; i -) {
    C [in [i]] -;
    Out [C [in [i]] = in [i];
  }
  Delete [] C;
}
INT MAIN () {
  std :: vector & lt; int & gt; U, V;
  INT A [17] = {0, 4, 7, 1, 2, 3, 3, 3, 9, 11, 13, 15, 15, 2, 17, 16, 16};
  Size_t max = 17;
  U.ASSIGN (A, A + 17);
  STD :: COPY (U.BEGIN (), U.End (), std :: ostream_terator & lt; int & gt; (std :: cout, ""));
  CSORT (U, V, MAX);
  STD :: COUT & LT; & LT; STD :: ENDL;
  STD :: COPY (V.BEGIN (), V.End (), std :: ostream_iterator & lt; int & gt; (std :: cout, ""));
  STD :: CIN & GT; & GT; Max;
}

C++ advise instead of arrays everywhere use vectors. It can be somehow in the line int * c = new int [max + 1]; Use the vector? And is it necessary at all? In the first part C [in.at (i)] ++; I use the AT () function instead of direct reference to the index in [i], and at the end I appeal to the items directly. What is the better way? For example, that in the last cycle, the set of functions AT () will make it very difficult to read the code.

How else can you rewrite this code? How to write a data type abstraction that are not numbers and which you need to sort?


Answer 1, Authority 100%

C++ advise vectors everywhere instead of arrays. It can be somehow in the line int * c = new int [max + 1]; Use the vector?

Yes, something like this:

std :: vector & lt; int & gt; C (MAX + 1, 0);

it will be the initialization of zeros.

And is it necessary at all?

This is your guarantee that in the case of Exception below, the allocated memory will be released. Those. In general, yes, it is necessary.

in the first part C [in.at (i)] ++; I use the AT () function instead of direct reference to the index in [i], and at the end I appeal to the items directly. What is the better way? For example, that in the last cycle, the set of functions at () will make it very difficult to read the code.

AT – generates Out_of_range Exception, in case you are trying to refer to the element outside the size of the array. Contact “Directly” in this case will lead to undefined behavior. Otherwise, they are identical. In my opinion, because You know exactly the sizes of your array and do not risk contacting out, and no one, besides you and this thread, this array does not change, you can safely contact “directly”.

How else can you rewrite this code?

A beautiful example is proposed in a nearby answer 🙂

I will offer to pay attention to possible code problems.

1) int i = in.size () - 1 – the size of the array has a type of size_t, which is more like an int. And the most sadness, if it has the same bit, but, for example, unsigned. This may, with a certain size of the array, give you a negative starting value. And in the case of appeal by AT (), you will receive Exception, and just flush the memory where you do New int , and in the case of contacting directly, there will be undefined behavior, and your process, for example, will tend to hack the Pentagon 🙂

2) C [i] = C [i] + C [i - 1]; – theoretically, this can lead to overflow, and receiving fun. But the calculation method is not used with a large scattering of values, and the minimum is not installed in you and on default 0, so it can be (for consideration of common sense) not to pay attention.

3) I would replace this part on a simpler.

out.resize (in.size ());
// ...
for (int i = 1; i & lt; max + 1; i ++)
  C [i] = C [i] + C [I - 1];
For (int i = in.size () - 1; I & gt; = 0; i -) {
  C [in [i]] -;
  Out [C [in [i]] = in [i];

That’s it:

out.reserve (in.size ());
For (Size_t i = 0; i & lt; max + 1; i ++)
  FOR (SIZE_T J = C [I]; j & gt; 0; --j)
    Out.Push_back (I);

IMHO so clearer what is happening.

How to write a data type abstraction that are not numbers and which need to be sorted?

depends on what basis they need to be sorted. Based on this, it will be necessary to form an integer presentation of this feature. If there are no signs for sorting, and it is necessary to sort the “somehow”, it is best to declare an array immediately on site sorted. Well, according to some existing, known only to you by the secret rule 🙂


Answer 2, Authority 200%

Simple copying sorting counting may look like this:

# include & lt; algorithm & gt;
#Include & lt; Numeric & GT;
#Include & lt; vector & gt;
// Sort counting requires a function that returns the sort key.
// Identity-function Returns the argument transferred to it unchanged.
// We will use it as a function for the default key.
Const Auto Identity = [] (Auto X) {Return X; };
using Identity = DeclType (Identity);
// Sort by counting uses serial access for input elements,
// And random access for elements at the output of the algorithm.
TEMPLATE & LT; TypeName ForwardITerator, TypeName Randomaccessiterator, TypeName Key = Identity & GT;
Void Counting_Sort (
  ForwardITERATOR First, ForwardIterator Last, // Input sequence
  Randomaccessiterator Out, // Result
  Key Key = Identity) // Function issuing element key
{
  // Check that the sequence is not empty.
  If (first == Last)
    Return;
  // Determine the minimum and maximum keys of the elements.
  AUTO COMPARE = ​​[& amp;] (Const Auto & Amp; LHS, Const Auto & Amp; RHS) {Return Key (LHS) & LT; Key (RHS); };
  auto minmax = std :: minmax_element (first, last, compare);
  Auto min_Key = Key (* minmax.first);
  AUTO MAX_KEY = KEY (* minmax.second);
  // If the keys do not differ, the sequence is already sorted.
  if (min_key == max_key) {
    STD :: COPY (FIRST, LAST, OUT);
    Return;
  }
  // Select an array for counting items.
  // Here you can optimize memory consumption if you use smaller counters
  // than Size_t, if the size of the input sequence is small enough.
  Std :: Vector & lt; STD :: Size_T & gt; Count (Max_Key - min_key + 1);
  // Count the number of items with the same key.
  STD :: FOR_EACH (FIRST, LAST, [& amp;] (const auto & amp; x) {++ Count [Key (X) - min_key];});
  // reset the first counter and calculate partial sums.
  // If after counting in Count it was {2,2,2,2},
  // then after partial_sum there will be {0,2,4,6},
  // i.e. Indices for which elements with the same key must be lying.
  COUNT [0] = 0;
  STD :: PARTIAL_SUM (count.begin (), count.end (), count.begin ());
  // Copy the items in the output array, increasing indexes in "count".
  // Copy can be replaced by movement.
  STD :: FOR_EACH (FIRST, LAST, [& amp;] (Auto & amp; x) {Out [Count [Key (X) - Min_Key] ++] = x;});
  // Count "Count [Key (X) - min_key]" meets twice, and it can be taken into a separate function, for example
  // Auto Count_ref = [& amp; x) - & gt; STD :: SIZE_T & AMP; {Return Count [Key (X) - min_key]; };
}

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions