Count Number of Digits in an array (c++) - c++

let's say I have an array
arr[5]={5,2,3,2,5} and i wrote following program for it
#include <iostream>
using namespace std;
int main()
{
int n;
cout<<"Enter Length of Elements= ";
cin>>n;
int arr[50];
for(int i=0;i<n;i++)
{
cout<<"Enter Number=";
cin>>arr[i];
}
for(int i=0;i<n;i++)
{
int countNum=1;
for(int j=i+1;j<n;j++)
{
if(arr[i]==arr[j])
{
if(i>0)
{
int countNum2=0;
for(int k=0;k>i;k++)
{
//bool repeat=false;
if(arr[i]==arr[k])
{
//repeat=false;
}
else
{
countNum2++;
}
}
if(countNum2==i)
{
countNum++;
}
}
else
{
countNum++;
}
}
else
{
for(int k=0;k<i;k++)
{
if(arr[k]==arr[i])
{
}
else
{
countNum=1;
}
}
}
}
cout<<arr[i]<<" has appeared "<<countNum<< "Times"<<endl;
}
return 0;
}
but why I am getting
5 has appeared 2 Times
2 has appeared 1 Time
3 has appeared 1 Time
2 has appeared 1 Time
5 has appeared 1 Time
instead of
5 has appeared 2 Times
2 has appeared 2 Times
3 has appeared 1 Times
so how to fix my program
help!

That's what you exactly need (amount of each number in array):
// we'll store amounts of numbers like key-value pairs.
// std::map does exactly what we need. As a key we will
// store a number and as a key - corresponding counter
std::map<int, size_t> digit_count;
// it is simpler for explanation to have our
// array on stack, because it helps us not to
// think about some language-specific things
// like memory management and focus on the algorithm
const int arr[] = { 5, 2, 3, 2, 5 };
// iterate over each element in array
for(const auto elem : arr)
{
// operator[] of std::map creates default-initialized
// element at the first access. For size_t it is 0.
// So we can just add 1 at each appearance of the number
// in array to its counter.
digit_count[elem] += 1;
}
// Now just iterate over all elements in our container and
// print result. std::map's iterator is a pair, which first element
// is a key (our number in array) and second element is a value
// (corresponding counter)
for(const auto& elem : digit_count) {
std::cout << elem.first << " appeared " << elem.second << " times\n";
}
https://godbolt.org/z/_WTvAm
Well, let's write some basic code, but firstly let's consider an algorithm (it is not the most efficient one, but more understandable):
The most understandable way is to iterate over each number in array and increment some corresponding counter by one. Let it be a pair with the first element to be our number and the second to be a counter:
struct pair {
int number;
int counter;
};
Other part of algorithm will be explained in code below
// Say that we know an array length and its elements
size_t length = // user-defined, typed by user, etc.
int* arr = new int[length];
// input elements
// There will be no more, than length different numbers
pair* counts = new pair[length];
// Initialize counters
// Each counte will be initialized to zero explicitly (but it is not obligatory,
// because in struct each field is initialized by it's default
// value implicitly)
for(size_t i = 0; i < length; i++) {
counts[i].counter = 0;
}
// Iterate over each element in array: arr[i]
for(size_t i = 0; i < length; i++)
{
// Now we need to find corresponding counter in our counters.
size_t index_of_counter = 0;
// Corresponding counter is the first counter with 0 value (in case when
// we meet current number for the first time) or the counter that have
// the corresponding value equal to arr[i]
for(; counts[index_of_counter].counter != 0 && counts[index_of_counter].number != arr[i]; index_of_counter++)
; // Do nothing here - index_of_counter is incrementing in loop-statement
// We found an index of our counter
// Let's assign the value (it will assign a value
// to newly initialized pair and won't change anything
// in case of already existing value).
counts[index_of_counter].number = arr[i];
// Increment our counter. It'll became 1 in case of new
// counter, because of zero assigned to it a bit above.
counts[index_of_counter].counter += 1;
}
// Now let's iterate over all counters until we reach the first
// containing zero (it means that this counter and all after it are not used)
for(size_t i = 0; i < length && counts[i].counter > 0; i++) {
std::cout << counts[i].number << " appeared " << counts[i].counter << " times\n";
}
// correctly delete dynamically allocated memory
delete[] counts;
delete[] arr;
https://godbolt.org/z/hN33Pn
Moreover it is exactly the same solution like with std::map (the same idea), so I hope it can help you to understand, how the first solution works inside

The problem with your code is that you don't remove the duplicates or assign an array which effectively stores the count of each unique element in your array.
Also the use of so many loops is completely unnecessary.
You just need to implement two loops, outer one going through all the elements and the inner one checking for dupes first (using an array to check frequency/occurence status) and counting appearance of each element seperately with a variable used as a counter.
Set a counter array (with the corresponding size of your taken array) with a specific value (say zero) and change that value when same element occurs while traversing the array, to trigger not to count for that value again.
Then transfer the count value from the counter variable to the counter array (the one which we set and which distinguishes between duplicates) each time the inner loop finishes iterating over the whole array. (i.e. place it after the values are counted)
With a little bit of modification, your code will work as you would want it to:
#include <iostream>
using namespace std;
int main()
{
int n;
cout<<"Enter Length of Elements = ";
cin>>n;
int arr[50];
for(int i=0;i<n;i++)
{
cout<<"Enter Number = ";
cin>>arr[i];
}
int counter[50];
for(int i=0; i<n; i++)
counter[i]=0;
// Our counter variable, but counts will be transferred to count[] later on:
int tempcount;
for(int i=0; i<n; i++)
{ // Each distinct element occurs once atleast so initialize to one:
tempcount = 1;
for(int j=i+1; j<n; j++)
{
// If dupe is found:
if(arr[i]==arr[j])
{
tempcount++;
// Ensuring not to count frequency of same element again:
counter[j] = 1;
}
}
// If occurence of current element is not counted before:
if(counter[i] != 1)
counter[i] = tempcount;
}
for(int i=0; i<n; i++)
{
if(counter[i] != 0)
printf("%d has appeared %d times.\n", arr[i], counter[i]);
}
return 0;
}
I used a variable tempcount to count occurence of each element and a zero-initialized array count to get the dupes checked (by setting it to 1 for a duplicate entry, and not counting it if it qualifies as 1) first. Then I transferred the counted occurence values to counter[] from tempcount at each outer loop iteration. (for all the unique elements)

Related

Copying array indexes to another array

I am a beginner in C++ trying to figure out how I could solve the following exercise:
Given an array of whole numbers, count how many times one element is present in the array. After that, copy the array indexes to another array and print them. In other words, apart from printing the amount of times one chosen number is present in the array, I need to print the indexes of that chosen number from a second array (by copying them from the first array to the second).
Example:
int myvect [ ] = {10, 42, 20, 10, 13, 20}
Assuming I choose the number 10 using the keyboard. The program will have to output the following:
The chosen element is present: 2 times
The chosen element is present in the following indexes: 0, 3
I don't have problems outputting how many times one element is present. I just added a counter and it works perfectly. My problem is i don't know how to select those specific indexes, copy them to another array to finally print them.
Here is my code:
#include <iostream>
#define max 20
using namespace std;
int main()
{
int vett[max],n,i,num,app=0,cont=0,pos[50];
bool flag;
cout<<"inserisci un numero massimo elementi del vettore:";
cin>>n;
cout<<endl;
flag=false;
for (i=0; i<n; i++) {
cout<<"inserisci elementi del vettore:";
cin>>vett[i];
}
cout<<"inserisci elemento da trovare: ";
cin>>num;
cout<<endl;
i=0;
for (i=0; i<n; i++) {
if(vett[i]==num) {
cout<<"trovato"<<endl;
flag=true;
app=i;
cont++;
}
}
if(flag==true) {
cout<<"elemento trovato"<<endl;
if(cont>1) {
cout<<"l'elemento e' stato trovato "<< cont<<" volte"<<endl;
}
else if(cont==1) {
cout<<"l'elemento e' stato trovato "<< cont<<" volta"<<endl;
}
cout<<"Posizioni Salvate: "<<vett[i]<<endl;
}
else {
cout<<"elemento non trovato"<<endl;
}
system("pause");
return 0;
}
As you can see, I did define a second array in the beginning. I don't know how to use it to solve the problem
Any help will be appreciated. Thank you very much
I usually make modifications to the OP's code as a part of my answer, but I cannot understand your language in the code. So, I will give you the basic algorithm to help you solve your problem keeping the structure of your attempted code intact.
Let the array of required indexes be int indexes[max];
Let k be the current index of indexes to keep track of the insertion
Each time you find the element in your i loop, insert the value of i into indexes[k] and increment the value of k
Demo:
int indexes[max], k = 0;
for (int i = 0; i < n; ++i)
{
if (vett[i] == num)
{
// Do the Part 1 of your task
// This line will help you achieve the Part 2:
indexes[k++] = i;
}
}
You could use std::find
An example:
std::array<int, 5> data{10, 2, 3, 4, 10};
std::vector<int> indices;
int num = 10;
auto it = data.begin();
while ((it = std::find(it, data.end(), num))!= data.end())
{
indices.push_back(std::distance(data.begin(), it));
it++;
}
indices then contains the indices of the elements that match your search criterion.
In your loop:
for (i=0; i<n; i++) {
if(vett[i]==num) {
cout<<"trovato"<<endl;
flag=true;
app=i;
cont++;
}
}
You are trying to test if number at index i is your desired number. Well, what about storing that i index into another array everytime the condition is true.
// create array with the same size as input array
int found_indexes[max];
size_t current_position = 0;
// now your loop
for (i=0; i<n; i++) {
if(vett[i]==num) {
cout<<"trovato"<<endl;
flag=true;
app=i;
cont++;
// save index at current position and advance by one after saving
found_indexes[current_position++] = i;
}
}
// at the end print all indexes from array
// this is done by printing all values until we meet with current_position index
if (current_position == 0)
cout << "No indexes found.\n";
else
{
// Printing spaces somewhat nicely.
cout << found_indexes[0];
for(size_t i = 1; i < current_position; i++)
cout << ' ' << found_indexes[i];
}
I think you are trying to do that
#include <iostream>
#include <stdlib.h>
#define max 20
using namespace std;
int main()
{
int vett[max],n,i,num,cont=0,pos[50];
bool flag;
cout<<"Enter how many numbers:";
cin>>n;
cout<<endl;
flag=false;
for (i=0; i<n; i++)
{
cout<<"Enter "<<i+1<<" Element:";
cin>>vett[i];
}
cout<<"\nEnter what to find: ";
cin>>num;
cout<<endl;
for (i=0; i<n; i++)
{
if(vett[i]==num)
{
flag=true;
pos[cont++]=i;
}
}
if(flag==true)
{
cout<<"The chosen element is present:"<<cont<<" times"<<endl;
cout<<"The chosen element is present in the following indexes:";
for(i=0;i<cont;i++)
cout<<pos[i]<<","; //it prints a number followed by a comma.
cout<<endl;
}
else
cout<<"No Element"<<endl;
system("pause");
return 0;
}
Output:
Enter how many numbers:6
Enter 1 Element:10
Enter 2 Element:42
Enter 3 Element:20
Enter 4 Element:10
Enter 5 Element:13
Enter 6 Element:20
Enter what to find: 10
The chosen element is present:2 times
The chosen element is present in the following indexes:0,3,
Press any key to continue . . .
Process returned 0 (0x0) execution time : 29.955 s
Press any key to continue.
Edit:
if you did not want comma after last element use this
for(i=0;i<cont;i++)
{
cout<<pos[i];
if((i+1)!=cont)
cout<<",";
}
I think that the appropriate data structure here is std::map<int, std::set<int> > which is the hash map representing the value mapped to the set of indices where this value is present. The size of set tells you the number of occurrences of the particular value. Simple implementation might look like this:
std::map<int, std::set<int> > values_to_indices;
for (int i = 0; i < input_array.size(); i++)
{
values_to_indices[input_array[i]].insert(i); // we can use operator[] because when element is not yet in the map, std::set will be default constructed
}
for (auto elem : values_to_indices)
{
std::cout << "element: " << elem.first << " is repeated " << elem.second.size() << " times\n";
// here you can also print std set of indices of that element
}
This doc explains that using operator[] on the map constructs the element if it was not present before. The values in the set are guaranteed to be unique because we iterate once from 0 to input array size.
=== EDIT ===
As suggested in the comment, instead of int you might use size_t as a type representing indices:
std::map<int, std::set<size_t> > values_to_indices;
for (size_t i = 0; i < input_array.size(); i++)
{
values_to_indices[input_array[i]].insert(i);
}
Just be aware of unsigned integer underflow if later you plan to do some things with that indices.

How to reduce the execution time further?

I'm trying a problem for a contest.The requirement is as below.
Problem:
Input_format:
Output_expected:
My C++ code is:-
#include <iostream>
using namespace std;
int main() {
long long n,i,j,k=0,p,q;
cin>>n;//takes size of string//
char s[n];
cin>>s;
cin>>p;//Number of test cases//
for(i=0;i<p;i++)
{
cin>>q;//takes index to check till//
for(j=0;j<q-1;j++)
{
if(s[j]==s[q-1])//checks if characters are equal//
{
k++;//if yes then counts it//
}
}
cout<<k<<endl;
k=0;//makes cout 0 for next iteration//
}
return 0;
}
So it seems the code works for most of the cases but there's this time constraint that seems exceeding for some cases.What more can be done to reduce the time.Thanks in advance for taking time to read this.
Let's say we have an array cnt which stores the number of occurrences of each letter in the before the ith character of the string, for some i. We can easily update this array to include the ith character by simply incrementing the relevant element. So we'll iterate through the string updating this array, and at the ith iteration the cnt array will contain counts of every letter before index i.
Now, at the ith iteration, the information in the cnt array which would be useful for answering queries is cnt[s[i]], since that contains the number of occurrences of the character at index i in the part of the string preceding index i. We'll store this information in a[i], where a is some other array. So now a[i] is the number of occurrences of the letter at index i in all positions before i, which is exactly what we want for a query at index i. Therefore, we can now answer queries using the array.
Possible implementation:
#include <iostream>
#include <string>
#include <vector>
int main()
{
//read input
int n;
std::string s;
std::cin >> n >> s;
//iterate through string maintaining cnt array and adding relevant values to array a
int cnt[26] = { 0 };
std::vector<int> a;
a.reserve(n);
for (int i = 0; i < n; i++)
{
int c = s[i] - 'a';
a.push_back(cnt[c]);
cnt[c]++;
}
//answer queries
int q;
std::cin >> q;
for (int i = 0; i < q; i++)
{
int p;
std::cin >> p;
p--;
std::cout << a[p] << '\n';
}
}
First, this declaration:
long long n
cin>>n;//takes size of string//
char s[n];
Is non-standard. g++ supports it, but I don't believe variable sized arrays have made it into the C++ standard as it has for C. And I doubt you need long long as your index type unless you are scaling beyond 2 billion items.
Better:
int n;
cin>>n; //takes size of string
vector<char> s(n);
s is effectively the same as an array as for as accessing it at index locations with the [] operation.
Back to the solution:
Use a hash table that maps between a character and the number of occurrences of that character as you scan the s array once. Then use another array to keep track of how many times the character at that index was seen up to that point.
std::vector<int> positionCount(n);
std::unordered_map<char, int> table;
Insert your characters from s into the table and positionCount table as follows
for (int i = 0; i < n; i++)
{
char c = s[i];
// table[c] is the number of occurrences that "c" was seen in the input array so far
table[c]++;
// since table[c] is getting updated as we iterate,
// Keep track of the count of the char at position i in a separate array
positionCount[i] = table[c];
};
Then for each test case:
for(i=0;i<p;i++)
{
cin>>q; //takes index to check till
q--; // off by 1 fix since the array is described as 1..N
long result = positionCount[q];
result--; // off by 1 fix again since the output is the preceeding count and doesn't include the character at position q.
cout << result << endl;
}
All of the above is intuitively faster since there's no inner for loop. Hash table insertion and lookup is O(1) as is each array lookup.
And if you are into the whole brevity thing, you can simplify the above into this:
for (int i = 0; i < n; i++)
{
positionTable[i] = table[s[i]]++;
}
for(i=0;i<p;i++)
{
cin >> q;
cout << positionTable[q-1] << endl;
}

This sorting array code cause the last element dissapear

So, I tried to make an array using input first, then sorting it out from smallest to biggest, then display the array to monitor.
So I come up with this code :
#include <iostream>
using namespace std;
void pancakeSort(int sortArray[], int sortSize);
int main()
{
// Input The Array Element Value
int pancake[10];
for(int i=0; i<10; i++)
{
cout << "Person " << i+1 << " eat pancakes = ";
cin >> pancake[i];
}
// call pancake sorting function
pancakeSort(pancake, 10);
}
void pancakeSort(int sortArray[], int sortSize)
{
int length = 10;
int temp;
int stop = 10;
// this is where the array get sorting out from smallest to biggest number
for(int counter = length-1; counter>=0; counter--)
{
for(int j=0; j<stop; j++)
{
if(sortArray[j]>sortArray[j+1])
{
temp = sortArray[j+1];
sortArray[j+1] = sortArray[j];
sortArray[j]=temp;
}
}
stop--;
}
// after that, the array get display here
for(int x=0; x<sortSize; x++)
{
cout << sortArray[x] << " ";
}
}
but the output is weird :
enter image description here
the function is successfully sorting the array from smallest to biggest,
but there is 2 weird things :
1. The biggest value element (which is 96 from what I input and it's the 10th element after got sorted out), disappear from the display.
2. For some reason, there is value 10 , which I didn't input on the array.
So, what happened?
In the loop
for(int j=0; j<stop; j++)
{
if(sortArray[j]>sortArray[j+1])
{
temp = sortArray[j+1];
sortArray[j+1] = sortArray[j];
sortArray[j]=temp;
}
}
stop is the length of the array, and you are iterating through values of j = 0 to stop - 1. When j reaches stop - 1, the next element that is j+1 becomes stop (10 in this case). But since your array has a length of 10, sortArray[10] is not part of the array, but is referring to some other object in memory which is usually a garbage value. The garbage value is 10 in this case. When you swap sortArray[10] and sortArray[9], the garbage value becomes part of the array and the value at index 9 leaves the array. This keeps on happening till the outer loop ends.
The end result is that unless the garbage value < largest element in the array, the garbage value is pushed in the array and the greatest value of the array is put at sortArray[10] which is not part of the array. If the garbage value is greater than all the values of the array, it'll be found at sortArray[10] which is again not part of the array and your code will return the desired result.
Essentially, what you are doing is giving the function an array of 10 (or stop) elements, but the function is actually working with an array of 11 (or stop + 1) elements, with the last element being a garbage value. The simple fix is to change the conditional of the loop to j < stop - 1.
Note that if you had written this code in a managed (or a comparatively higher level) language like Java or C#, it would have raised an IndexOutOfBoundsException.
At index 9, j+1 is out of bounds. So to fix this, you only need to check till index 8
for(int counter = length-1; counter>=0; counter--)
{
for(int j=0; j<stop-1; j++)
{
if(sortArray[j]>sortArray[j+1])
{
temp = sortArray[j+1];
sortArray[j+1] = sortArray[j];
sortArray[j]=temp;
}
}
stop--;
}
Look carefully at the inner loop condition j<stop-1

Distinct numbers in array

I have no idea what to do. Please help me with code or tell me what textbook to look up or something; I need code to finish this program and I would love an explanation of what I'm looking at..
#include<iostream>
using namespace std;
int main()
{
short num[100], size, //declare an array of type short that has 100 elements
unique[100], number, // declare a second array to help solve the problem; number counts the number of unique values
k; // loop control variable; may need other variables
cout<<"enter the number of values to store in the array\n";
cin>>size;
cout<<”enter the “<<size<<” values to be used as data for this program\n”;
for(k=0; k<size; k++)
cin>>num[k];
// print the contents of the array
cout<<"\nthere are "<<size<<" values in the array\n";
for(k=0; k<size; k++)
cout<<num[k]<<’ ‘; // there is one space between each number in the display
cout<<endl; // cursor moved to next output line
cout<<"the program will count the number of different (distinct) values found in the array\n";
//************************************************************
//Put the code here that counts the number of unique values stored in the
//array num. The variable number will contain the count.
//************************************************************
cout<<endl<<number<<" unique values were found in the "<<size<<" element array\n";
// pause the program to see the results
system("pause");
//return 0;
}
I have to do one of these two things and I don't know what they mean?
Algorithm – unique array is used to help find the solution, used to avoid counting any value more than one time
Set number to 0 - this represents the number of distinct values in the data set; also used as a subscript in the unique array
Loop from 0 to size by one, proceeding through successive elements of the data (num) array
Store value of current array element in non-array variable (SV)
Set event_flag to 0
Loop from 0 to number by one, proceeding through successive elements of unique array
If SV is equal to current element of unique array
Set event_flag to 1
Break (stop) inner loop
End of inner loop
If event_flag is equal to 0 (value not found in unique array and not previously counted)
Store SV in element number of unique array
Increment the value of number
End of outer loop
Solution – the variable number contains the count of distinct values in the data array
Alternate Algorithm
Algorithm that does not use the event_flag (loop control variable can be used to determine if event occurred)
Algorithm – unique array is used to help find the solution, used to avoid counting any value more than one time
Set number to 0 - this represents the number of distinct values in the data set; also used as a subscript in the unique array
Loop from 0 to size by one, proceeding through successive elements of the data (num) array
Store value of current array element in non-array variable (SV)
Loop from 0 to number by one, proceeding through successive elements of unique array
If SV is equal to current element of unique array
Break (stop) inner loop
End of inner loop
If loop control variable of inner loop is equal to value of number (SV not found in unique array and not previously counted)
Store SV in element number of unique array
Increment the value of number
End of outer loop
Solution – the variable number contains the count of distinct values in the data array
I put this in mine:
//************************************************************
//Put the code here that counts the number of unique values stored in the array num. The variable number will contain the count.
for(k=0; k<size; k++)
num=SV;
event_flag=0;
for(k=1; k<number; k++)
if(SV=unique)
return true;
return false;
//************************************************************
It's not working, obviously.
This is my code, it seems to work
//************************************************************
//Put the code here that counts the number of unique values
//stored in the array num. The variable number will contain the count.
number = 0;
for (k = 0; k < size; ++k)
{
short sv = num[k];
short event_flag = 0;
for (int i = 0; i < number; ++i)
{
if (sv == unique[i])
{
event_flag = 1;
break;
}
}
if (event_flag == 0)
{
unique[number] = sv;
++number;
}
}
For the alternative ,
his is my code, it seems to work
//************************************************************
//Put the code here that counts the number of unique values
//stored in the array num. The variable number will contain the count.
number = 0;
for (k = 0; k < size; ++k)
{
short sv = num[k];
int i;
for (i = 0; i < number; ++i)
if (sv == unique[i])
break;
if (number == i)
{
unique[number] = sv;
++number;
}
}
You are roughly asked to do the following:
#include <iostream>
using namespace std;
int main()
{
// This is the given array.
int given_array[5] = { 1, 1, 2, 2, 3 };
// This is the array where unique values will be stored.
int unique_array[5];
// This index is used to keep track of the size
// (different from capacity) of unique_array.
int unique_index = 0;
// This is used to determine whether we can
// insert an element into unique_array or not.
bool can_insert;
// This loop traverses given_array.
for (int i = 0; i < 5; ++i)
{
// Initially assume that we can insert elements
// into unique_array, unless told otherwise.
can_insert = true;
// This loop traverses unique_array.
for (int j = 0; j < unique_index; ++j)
{
// If the element is already in unique_array,
// then don't insert it again.
if (unique_array[j] == given_array[i])
{
can_insert = false;
break;
}
}
// This is the actual inserting.
if (can_insert)
{
unique_array[unique_index] = given_array[i];
unique_index++;
}
}
// Tell us how many elements are unique.
cout << unique_index;
return 0;
}
Try out this one...
You can insert cout statements wherever required.
#include <iostream>
using namespace std;
int main()
{
int Input[100], Unique[100], InSize, UniLength = 0;
cin >> InSize;
for (int ii = 0 ; ii < InSize ; ii++ )
{
cin >> Input[ii];
}
Unique[0] = Input[0];
UniLength++;
bool IsUnique;
for ( int ii = 1 ; ii < InSize ; ii++ )
{
IsUnique=true;
for (int jj = 0 ; jj < UniLength ; jj++ )
{
if ( Input[ii] == Unique[jj] )
{
IsUnique=false;
break;
}
}
if ( IsUnique )
{
Unique[UniLength] = Input[ii];
UniLength++;
}
}
cout<<"We've "<<UniLength<<" Unique elements and We're printing them"<<endl;
for ( int jj = 0 ; jj < UniLength ; jj++ )
{
cout << Unique[jj] << " ";
}
}
I hope this is what you were looking for.....
Have a nice day.
Here is my approach. Hope so it will helpful.
#include<iostream>
#include<algorithm>
int main(){
int arr[] = {3, 2, 3, 4, 1, 5, 5, 5};
int len = sizeof(arr) / sizeof(*arr); // Finding length of array
std::sort(arr, arr+len);
int unique_elements = std::unique(arr, arr+len) - arr;
std::cout << unique_elements << '\n'; // The output will 5
return 0;
}

Radix Sort implemented in C++

I am trying to improve my C++ by creating a program that will take a large amount of numbers between 1 and 10^6. The buckets that will store the numbers in each pass is an array of nodes (where node is a struct I created containing a value and a next node attribute).
After sorting the numbers into buckets according to the least significant value, I have the end of one bucket point to the beginning of another bucket (so that I can quickly get the numbers being stored without disrupting the order). My code has no errors (either compile or runtime), but I've hit a wall regarding how I am going to solve the remaining 6 iterations (since I know the range of numbers).
The problem that I'm having is that initially the numbers were supplied to the radixSort function in the form of a int array. After the first iteration of the sorting, the numbers are now stored in the array of structs. Is there any way that I could rework my code so that I have just one for loop for the 7 iterations, or will I need one for loop that will run once, and another loop below it that will run 6 times before returning the completely sorted list?
#include <iostream>
#include <math.h>
using namespace std;
struct node
{
int value;
node *next;
};
//The 10 buckets to store the intermediary results of every sort
node *bucket[10];
//This serves as the array of pointers to the front of every linked list
node *ptr[10];
//This serves as the array of pointer to the end of every linked list
node *end[10];
node *linkedpointer;
node *item;
node *temp;
void append(int value, int n)
{
node *temp;
item=new node;
item->value=value;
item->next=NULL;
end[n]=item;
if(bucket[n]->next==NULL)
{
cout << "Bucket " << n << " is empty" <<endl;
bucket[n]->next=item;
ptr[n]=item;
}
else
{
cout << "Bucket " << n << " is not empty" <<endl;
temp=bucket[n];
while(temp->next!=NULL){
temp=temp->next;
}
temp->next=item;
}
}
bool isBucketEmpty(int n){
if(bucket[n]->next!=NULL)
return false;
else
return true;
}
//print the contents of all buckets in order
void printBucket(){
temp=bucket[0]->next;
int i=0;
while(i<10){
if(temp==NULL){
i++;
temp=bucket[i]->next;
}
else break;
}
linkedpointer=temp;
while(temp!=NULL){
cout << temp->value <<endl;
temp=temp->next;
}
}
void radixSort(int *list, int length){
int i,j,k,l;
int x;
for(i=0;i<10;i++){
bucket[i]=new node;
ptr[i]=new node;
ptr[i]->next=NULL;
end[i]=new node;
}
linkedpointer=new node;
//Perform radix sort
for(i=0;i<1;i++){
for(j=0;j<length;j++){
x=(int)(*(list+j)/pow(10,i))%10;
append(*(list+j),x);
printBucket(x);
}//End of insertion loop
k=0,l=1;
//Linking loop: Link end of one linked list to the front of another
for(j=0;j<9;j++){
if(isBucketEmpty(k))
k++;
if(isBucketEmpty(l) && l!=9)
l++;
if(!isBucketEmpty(k) && !isBucketEmpty(l)){
end[k]->next=ptr[l];
k++;
if(l!=9) l++;
}
}//End of linking for loop
cout << "Print results" <<endl;
printBucket();
for(j=0;j<10;j++)
bucket[i]->next=NULL;
cout << "End of iteration" <<endl;
}//End of radix sort loop
}
int main(){
int testcases,i,input;
cin >> testcases;
int list[testcases];
int *ptr=&list[0];
for(i=0;i<testcases;i++){
cin>>list[i];
}
radixSort(ptr,testcases);
return 0;
}
I think you're severely overcomplicating your solution. You can implement radix using the single array received in the input, with the buckets in each step represented by an array of indices that mark the starting index of each bucket in the input array.
In fact, you could even do it recursively:
// Sort 'size' number of integers starting at 'input' according to the 'digit'th digit
// For the parameter 'digit', 0 denotes the least significant digit and increases as significance does
void radixSort(int* input, int size, int digit)
{
if (size == 0)
return;
int[10] buckets; // assuming decimal numbers
// Sort the array in place while keeping track of bucket starting indices.
// If bucket[i] is meant to be empty (no numbers with i at the specified digit),
// then let bucket[i+1] = bucket[i]
for (int i = 0; i < 10; ++i)
{
radixSort(input + buckets[i], buckets[i+1] - buckets[i], digit+1);
}
}
Of course buckets[i+1] - buckets[i] will cause a buffer overflow when i is 9, but I omitted the extra check or readability's sake; I trust you know how to handle that.
With that, you just have to call radixSort(testcases, sizeof(testcases) / sizeof(testcases[0]), 0) and your array should be sorted.
To speed up the process with better memory management, create a matrix for the counts that get converted into indices by making a single pass over the array. Allocate a second temp array the same size as the original array, and radix sort between the two arrays until the array is sorted. If an odd number of radix sort passes is performed, then the temp array will need to be copied back to the original array at the end.
To further speed up the process, use base 256 instead of base 10 for the radix sort. This only takes 1 scan pass to create the matrix and 4 radix sort passes to do the sort. Example code:
typedef unsigned int uint32_t;
uint32_t * RadixSort(uint32_t * a, size_t count)
{
size_t mIndex[4][256] = {0}; // count / index matrix
uint32_t * b = new uint32_t [COUNT]; // allocate temp array
size_t i,j,m,n;
uint32_t u;
for(i = 0; i < count; i++){ // generate histograms
u = a[i];
for(j = 0; j < 4; j++){
mIndex[j][(size_t)(u & 0xff)]++;
u >>= 8;
}
}
for(j = 0; j < 4; j++){ // convert to indices
m = 0;
for(i = 0; i < 256; i++){
n = mIndex[j][i];
mIndex[j][i] = m;
m += n;
}
}
for(j = 0; j < 4; j++){ // radix sort
for(i = 0; i < count; i++){ // sort by current lsb
u = a[i];
m = (size_t)(u>>(j<<3))&0xff;
b[mIndex[j][m]++] = u;
}
std::swap(a, b); // swap ptrs
}
delete[] b;
return(a);
}
Since your values are ints in the range of 0 ... 1,000,000
You can create a int array of of size 1,000,001, and do the whole thing in two passes
Init the second array to all zeros.
Make a pass through your input array, and use the value as a subscript
to increment the value in the second array.
Once you do that then the second pass is easy.
walk through the second array, and each element tells you how many times that
number appeared in the original array. Use that information to repopulate
your input array.