3

I had been given a homework to do a program to sort an array in ascending order.I did this:

#include <stdio.h>
int main()
 {
    int a[100],i,n,j,temp;
    printf("Enter the number of elements: ");
    scanf("%d",&n);
    for(i=0;i<n;++i)
      {
       printf("%d. Enter element: ",i+1);
       scanf("%d",&a[i]);
     }
    for(j=0;j<n;++j)
    for(i=j+1;i<n;++i)
     {
         if(a[j]>a[i])
          {
             temp=a[j];
             a[j]=a[i];
             a[i]=temp;
         }
    }
    printf("Ascending order: ");
    for(i=0;i<n;++i)
        printf("%d  ",a[i]);
    return 0;
}

The input will not be more than 10 numbers. Can this be done in less amount of code than i did here? I want the code to be as shortest as possible.Any help will be appreciated.Thanks!

haccks
  • 104,019
  • 25
  • 176
  • 264
Pruthvi Raj
  • 3,016
  • 2
  • 22
  • 36
  • Code golf and efficiency are two different things. Which is of higher priority? Also, if reducing the SLOC reduces readability/maintainability, it is not a good idea. – C.B. Feb 25 '14 at 15:39
  • 7
    Of course you can write a C program to sort an array shorter, by using the standard library function `qsort()`. :) I guess you're not allowed to do that, but it should be mentioned since it's typically the best approach for real programs. – unwind Feb 25 '14 at 15:39
  • Code golf is of higher priority and No i am not allowed to use qsort – Pruthvi Raj Feb 25 '14 at 15:40
  • If the input will not be more than 10 numbers, why is it declared `a[100]`?? – abelenky Feb 25 '14 at 15:42
  • I'm saying that the program won't be tested against a lot of numbers and i just took a[100] – Pruthvi Raj Feb 25 '14 at 15:43
  • Possible duplicate of [How to sort a list with given range in O(n)](https://stackoverflow.com/questions/20308822/how-to-sort-a-list-with-given-range-in-on) – Bernhard Barker Aug 22 '17 at 03:52
  • Duplicate - [Is there an O(n) integer sorting algorithm?](https://stackoverflow.com/questions/2352313/is-there-an-on-integer-sorting-algorithm?rq=1) Code golf is off topic for this site. – Bernhard Barker Aug 22 '17 at 03:53

2 Answers2

4

You have 10 lines doing the sorting. If you're allowed to use someone else's work (subsequent notes indicate that you can't do this), you can reduce that by writing a comparator function and calling the standard C library qsort() function:

static int compare_int(void const *v1, void const *v2)
{
    int i1 = *(int *)v1;
    int i2 = *(int *)v2;
    if (i1 < i2)
        return -1;
    else if (i1 > i2)
        return +1;
    else
        return 0;
}

And then the call is:

qsort(a, n, sizeof(a[0]), compare_int);

Now, I wrote the function the way I did for a reason. In particular, it avoids arithmetic overflow which writing this does not:

static int compare_int(void const *v1, void const *v2)
{
    return *(int *)v1 - *(int *)v2;
}

Also, the original pattern generalizes to comparing structures, etc. You compare the first field for inequality returning the appropriate result; if the first fields are unequal, then you compare the second fields; then the third, then the Nth, only returning 0 if every comparison shows the values are equal.

Obviously, if you're supposed to write the sort algorithm, then you'll have to do a little more work than calling qsort(). Your algorithm is a Bubble Sort. It is one of the most inefficient sorting techniques — it is O(N2). You can look up Insertion Sort (also O(N2)) but more efficient than Bubble Sort), or Selection Sort (also quadratic), or Shell Sort (very roughly O(N3/2)), or Heap Sort (O(NlgN)), or Quick Sort (O(NlgN) on average, but O(N2) in the worst case), or Intro Sort. The only ones that might be shorter than what you wrote are Insertion and Selection sorts; the others will be longer but faster for large amounts of data. For small sets like 10 or 100 numbers, efficiency is immaterial — all sorts will do. But as you get towards 1,000 or 1,000,000 entries, then the sorting algorithms really matter. You can find a lot of questions on Stack Overflow about different sorting algorithms. You can easily find information in Wikipedia for any and all of the algorithms mentioned.

Incidentally, if the input won't be more than 10 numbers, you don't need an array of size 100.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thanks for the response. But I am not allowed to use the qsort function. – Pruthvi Raj Feb 25 '14 at 15:48
  • 1
    Please state important limitations like "I cannot use the obvious answer" in your question. – Jonathan Leffler Feb 25 '14 at 15:55
  • I'm sorry. Will state from next time :3. Thanks for your answer. Learned a lot from it ;) – Pruthvi Raj Feb 25 '14 at 15:56
  • I've adopted [`(*a > *b) - (*a < *b)`](http://stackoverflow.com/a/10997428/315052) as my integer comparison function implementation of choice. – jxh Feb 25 '14 at 16:26
  • @jxh: yes; for simple types like integers, that's a good way to do it; it would reduce the comparator to 3 lines in the body of the function (two variable definitions and initializations, one `return` statement). It always does two comparisons where the written out code sometimes does just one, but it is unlikely that would be a factor in the performance. – Jonathan Leffler Feb 25 '14 at 16:30
  • 1
    @JonathanLeffler: True, it probably wouldn't affect overall performance of the sort, but the linked question did measure a significant performance improvement of this branchless version over my previously preferred `(*a < *b) ? -1 : (*a > *b)`. – jxh Feb 25 '14 at 16:34
4

If you know the range of the array elements, one way is to use another array to store the frequency of each of the array elements ( all elements should be int :) ) and print the sorted array. I am posting it for large number of elements (106). You can reduce it according to your need:

#include <stdio.h>
#include <malloc.h>

int main(void){
    int t, num, *freq = malloc(sizeof(int)*1000001);

    memset(freq, 0, sizeof(int)*1000001);   // Set all elements of freq to 0
    scanf("%d",&t);                         // Ask for the number of elements to be scanned (upper limit is 1000000)

    for(int i = 0; i < t; i++){
        scanf("%d", &num);
        freq[num]++;
    }

    for(int i = 0; i < 1000001; i++){
        if(freq[i]){
            while(freq[i]--){
                printf("%d\n", i);
            }
        }
    }
}  

This algorithm can be modified further. The modified version is known as Counting sort and it sorts the array in Θ(n) time.

Counting sort:1

Counting sort assumes that each of the n input elements is an integer in the range 0 to k, for some integer k. When k = O(n), the sort runs in Θ(n) time. Counting sort determines, for each input element x, the number of elements less than x. It uses this information to place element x directly into its position in the output array. For example, if 17 elements are less than x, then x belongs in output position 18. We must modify this scheme slightly to handle the situation in which several elements have the same value, since we do not want to put them all in the same position.

In the code for counting sort, we assume that the input is an array A[1...n] and thus A.length = n. We require two other arrays: the array B[1....n] holds the sorted output, and the array C[0....k] provides temporary working storage.

The pseudo code for this algo:

for i ← 1 to k do
c[i] ← 0
for j ← 1 to n do
    c[A[j]] ← c[A[j]] + 1
//c[i] now contains the number of elements equal to i
for i ← 2 to k do
    c[i] ← c[i] + c[i-1]
// c[i] now contains the number of elements ≤ i
for j ← n downto 1 do
    B[c[A[i]]] ← A[j]
    c[A[i]] ← c[A[j]] - 1  

1. Content has been taken from Introduction to Algorithms by Thomas H. Cormen and others.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • Amusing; it works, of course, but it does not generalize well. It doesn't handle negative integers; it doesn't handle values larger than 1,000,000. It really isn't limited by the number of values, but rather by the range of those values. You couldn't apply this algorithm to sorting floating point numbers, and for all practical purposes, it wouldn't work for sorting strings, either. – Jonathan Leffler Feb 25 '14 at 16:05
  • Perhaps the type of `freq` should be made `uint16_t *` and `num` also cast to `uint16_t` before incrementing and add appropriate offset applied when printing to support `int16_t` elements – this should be fine for the question since the original type `int` is not guaranteed to be any larger. You could then also optimise away the `if (freq[i])` line as unsigned underflow is ok. – Arkku Feb 25 '14 at 16:10
  • @JonathanLeffler; Agreed. I posted this answer keeping in my mind that OP wants to sort an `int` array. – haccks Feb 25 '14 at 16:36
  • 1
    @PruthviRaj Note that the first solution in this answer won't work reliably if the elements of the array are negative, or greater than 1000000. Due to the nature of C, it may accidentally look like it works even in those cases sometimes, so beware. – Arkku Feb 25 '14 at 16:58