Interview on sorting algorithm - c++

Given a big array which has numbers in range from 1 to 100. What's the best approach to sort it out?
The interviewer was emphasizing on the word range ie max number which is present in the array is 100.

try this:
long result[100] = {0};
for (iterator it = vec.begin(); it != vec.end(); ++it)
{
result[*it - 1]++;
}
So, you will move linear over your vector and count all numbers there exist. As result you will receive how many 1 you had, how many 2 you had and etc, i.e. it will be as sorted.
UPD: as KillianDS wrote, I mean counting sort. It's the fast one.

Well since the answer was basically given, example code. There's no need to copy data from the original array; it can be generated from the data in the histogram, called a variant algorithm in the wiki counting sort variant section:
std::vector <size_t> hist(101, 0); // using index 1 to 100 inclusive
size_t i, j, n;
for (i = 0; i < vec.size(); i++)
hist[vec[i]]++;
i = 0;
for(j = 1; j <= 100; j++)
for(n = hist[j]; n; n--)
vec[i++] = j;

May be they wanted to hear about radix sort.

It seems counting sort is the most suitable algorithm for this problem, it's O(n), stable, and easy to implement. http://en.wikipedia.org/wiki/Counting_sort

Related

Sort array of n elements which has k sorted sections

What is the best way to sort an section-wise sorted array as depicted in the second image?
The problem is performing a quick-sort using Message Passing Interface. The solution is performing quick-sort on array sections obtained by using MPI_Scatter() then joining the sorted
pieces using MPI_Gather().
Problem is that the array as a whole is unsorted but sections of it are.
Merging the sub-sections similarly to this solution seems like the best way of sorting the array, but considering that the sub-arrays are already within a single array other sorting algorithms may prove better.
The inputs for a sort function would be the array, it's length and the number of equally sorted sub-sections.
A signature would look something like int* sort(int* array, int length, int sections);
The sections parameter can have any value between 1 and 25. The length parameter value is greater than 0, a multiple of sections and smaller than 2^32.
This is what I am currently using:
int* merge(int* input, int length, int sections)
{
int* sub_sections_indices = new int[sections];
int* result = new int[length];
int section_size = length / sections;
for (int i = 0; i < sections; i++) //initialisation
{
sub_sections_indices[i] = 0;
}
int min, min_index, current_index;
for (int i = 0; i < length; i++) //merging
{
min_index = 0;
min = INT_MAX;
for (int j = 0; j < sections; j++)
{
if (sub_sections_indices[j] < section_size)
{
current_index = j * section_size + sub_sections_indices[j];
if (input[current_index] < min)
{
min = input[current_index];
min_index = j;
}
}
}
sub_sections_indices[min_index]++;
result[i] = min;
}
return result;
}
Optimizing for performance
I think this answer that maintains a min-heap of the smallest item of each sub-array is the best way to handle arbitrary input. However, for small values of k, think somewhere between 10 and 100, it might be faster to implement the more naive solutions given in the question you linked to; while maintaining the min-heap is only O(log n) for each step, it might have a higher overhead for small values of n than the simple linear scan from the naive solutions.
All these solutions create a copy of the input, and they maintain O(k) state.
Optimizing for space
The only way to save space I see is to sort in-place. This will be a problem for the algorithms mentioned above. An in-place algorithm will have two swap elements, but any swaps will likely destroy the property that each sub-array is sorted, unless the larger of the swapped pair is re-sorted into the sub-array it is being swapped to, which will result in an O(n²) algorithm. So if you really do need to conserve memory, I think a regular in-place sorting algorithm would have to be used, which defeats your purpose.

Performance optimization nested loops

I am implementing a rather complicated code and in one of the critical sections I need to basically consider all the possible strings of numbers following a certain rule. The naive implementation to explain what I do would be such a nested loop implementation:
std::array<int,3> max = { 3, 4, 6};
for(int i = 0; i <= max.at(0); ++i){
for(int j = 0; j <= max.at(1); ++j){
for(int k = 0; k <= max.at(2); ++k){
DoSomething(i, j, k);
}
}
}
Obviously I actually need more nested for and the "max" rule is more complicated but the idea is clear I think.
I implemented this idea using a recursive function approach:
std::array<int,3> max = { 3, 4, 6};
std::array<int,3> index = {0, 0, 0};
int total_depth = 3;
recursive_nested_for(0, index, max, total_depth);
where
void recursive_nested_for(int depth, std::array<int,3>& index,
std::array<int,3>& max, int total_depth)
{
if(depth != total_depth){
for(int i = 0; i <= max.at(depth); ++i){
index.at(depth) = i;
recursive_nested_for(depth+1, index, max, total_depth);
}
}
else
DoSomething(index);
}
In order to save as much as possible I declare all the variable I use global in the actual code.
Since this part of the code takes really long is it possible to do anything to speed it up?
I would also be open to write 24 nested for if necessary to avoid the overhead at least!
I thought that maybe an approach like expressions templates to actually generate at compile time these nested for could be more elegant. But is it possible?
Any suggestion would be greatly appreciated.
Thanks to all.
The recursive_nested_for() is a nice idea. It's a bit inflexible as it is currently written. However, you could use std::vector<int> for the array dimensions and indices, or make it a template to handle any size std::array<>. The compiler might be able to inline all recursive calls if it knows how deep the recursion is, and then it will probably be just as efficient as the three nested for-loops.
Another option is to use a single for loop for incrementing the indices that need incrementing:
void nested_for(std::array<int,3>& index, std::array<int,3>& max)
{
while (index.at(2) < max.at(2)) {
DoSomething(index);
// Increment indices
for (int i = 0; i < 3; ++i) {
if (++index.at(i) >= max.at(i))
index.at(i) = 0;
else
break;
}
}
}
However, you can also consider creating a linear sequence that visits all possible combinations of the iterators i, j, k and so on. For example, with array dimensions {3, 4, 6}, there are 3 * 4 * 6 = 72 possible combinations. So you can have a single counter going from 0 to 72, and then "split" that counter into the three iterator values you need, like so:
for (int c = 0; c < 72; c++) {
int k = c % 6;
int j = (c / 6) % 4;
int i = c / 6 / 4;
DoSomething(i, j, k);
}
You can generalize this to as many dimensions as you want. Of course, the more dimensions you have, the higher the cost of splitting the linear iterator. But if your array dimensions are powers of two, it might be very cheap to do so. Also, it might be that you don't need to split it at all; for example if you are calculating the sum of all elements of a multidimensional array, you don't care about the actual indices i, j, k and so on, you just want to visit all elements once. If the array is layed out linearly in memory, then you just need a linear iterator.
Of course, if you have 24 nested for loops, you'll notice that the product of all the dimension's sizes will become a very large number. If it doesn't fit in a 32 bit integer, your code is going to be very slow. If it doesn't fit into a 64 bit integer anymore, it will never finish.

Optimize counting sort?

Given that the input will be N numbers from 0 to N (with duplicates) how I can optimize the code bellow for both small and big arrays:
void countingsort(int* input, int array_size)
{
int max_element = array_size;//because no number will be > N
int *CountArr = new int[max_element+1]();
for (int i = 0; i < array_size; i++)
CountArr[input[i]]++;
for (int j = 0, outputindex = 0; j <= max_element; j++)
while (CountArr[j]--)
input[outputindex++] = j;
delete []CountArr;
}
Having a stable sort is not a requirement.
edit: In case it's not clear, I am talking about optimizing the algorithm.
IMHO there's nothing wrong here. I highly recommend this approach when max_element is small, numbers sorted are non sparse (i.e. consecutive and no gaps) and greater than or equal to zero.
A small tweak, I'd replace new / delete and just declare a finite array using heap, e.g. 256 for max_element.
int CountArr[256] = { }; // Declare and initialize with zeroes
As you bend these rules, i.e. sparse, negative numbers you'd be struggling with this approach. You will need to find an optimal hashing function to remap the numbers to your efficient array. The more complex the hashing becomes the benefit between this over well established sorting algorithms diminishes.
In terms of complexity this cannot be beaten. It's O(N) and beats standard O(NlogN) sorting by exploiting the extra knowledge that 0<x<N. You cannot go below O(N) because you need at least to swipe through the input array once.

Sum of all contiguous subarray optimisation

I am solving a problem where I have a larger array and for given two numbers, I need to find sum of all contiguous sub-arrays between them.
All I could think is of this O(n2) code
for(i = min; i<= max; ++i)
{
sum = 0;
for(j = i; j <= max; ++j)
{
sum+=a[j];
printf("%lld\n", sum);
}
}
Can anyone please help me in optimising this code ?
Using dynamic programming you can achieve O(n) answer. The idea basically is to calculate prefix sums accumulated for all elements.
Let A(i) be the summation of elements from 0 to i. This can be calculated easily in O(n) by:
// let your array by Src[Max]
int A[MAX];
A[0] = Src[0];
for(int i=1; i<MAX; i++) A[i] +=A[i-1] + (i+1)*Src[i];
Then for any elements i and j, you can calculate sum(i,j) = A[j] - A[i] (adjust for boundaries depending on input requirements).
When max-min+1 is n, there would be n(n-1)/2 sums that you need to print. That's O(n2) values. The fastest possible algorithm to produce O(n2) values would have time complexity of O(n2), so your solution is already optimal.
There is no faster solution.
Since your output size is O(n2), not algorithm can be faster.
For insanely large block of computation or things like real time data analysis, since the content of arrays do not change, you may do the calculation in parallel threads.
For general cases, just loop them and let the compiler unroll and use vectorized instructions.

Comparing all elements of an array

For a program that I am writing for fun (one that finds the Highest Common Factor and the Lowest Common Multiple for you); I've come across some difficulty.
I have two arrays that contain 14 numbers. To find the Lowest Common Multiple of all the numbers, I need to compare every element in each array. So far I've got this test:
for(int i = 0; i < C_I_14; i++)
{
for(int j = 0; j < C_I_14; j++)
{
if(array[i] == arr[j])
{
tesst[i] = array[i];
}
}
}
(where C_I_14 = 14)
The thing is, there are endless amounts of things that could go wrong with:
tesst[i] = array[i]
So, can anyone help me sort out my little algorithm?
Sort each of your input arrays, then get the intersection using std::set_intersection.
If the ordering matters, you will find
std::mismatch
std::lexicographical_compare
quite useful
Otherwise, look at
std::sort (!! important) followed by
std::set_intersection