Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. Friday's Coding Challenge

Friday's Coding Challenge

Scheduled Pinned Locked Moved The Lounge
c++architectureperformancehelplounge
76 Posts 35 Posters 6 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P PIEBALDconsult

    SELECT TOP n FROM Sample ORDER BY Value Edit: How should we handle duplicates?

    K Offline
    K Offline
    KP Lee
    wrote on last edited by
    #67

    That won't work in sql. :) (n isn't a number and value isn't selected)

    1 Reply Last reply
    0
    • T Trajan McGill

      Ahh, shoot, you're right. The requirements didn't specify a non-destructive algorithm. Your method, turned into an actual function, with a few optimizations and a bit of non-essential character elimination, reduces to:

      void g(int*a,int m,int n){int i=0,j,k,t;for(;ia[j])k=j;}

      which beats mine by 50 characters (49 if I chop out the one removable whitespace character I missed in my solution). If we modify it further to toss out the array notation and instead do horrible things with pointers, we can even save 6 more:

      void g(int*a,int m,int n){int*i=a,*j,*k,t;for(;i*j)k=j;}

      Y Offline
      Y Offline
      YvesDaoust
      wrote on last edited by
      #68

      And as said in my next post (have a look into the future), passing argument n is unessential, use m instead and spare 6 characters.

      T 1 Reply Last reply
      0
      • T Trajan McGill

        Ahh, shoot, you're right. The requirements didn't specify a non-destructive algorithm. Your method, turned into an actual function, with a few optimizations and a bit of non-essential character elimination, reduces to:

        void g(int*a,int m,int n){int i=0,j,k,t;for(;ia[j])k=j;}

        which beats mine by 50 characters (49 if I chop out the one removable whitespace character I missed in my solution). If we modify it further to toss out the array notation and instead do horrible things with pointers, we can even save 6 more:

        void g(int*a,int m,int n){int*i=a,*j,*k,t;for(;i*j)k=j;}

        Y Offline
        Y Offline
        YvesDaoust
        wrote on last edited by
        #69

        You can also get rid of variable i by working backwards, and benefit from a little of C's syntaxic sugar:

        void g(int a[], int m)
        {
        while (m)
        {
        int k= --m, j= m;
        while (j)
        k= a[k] < a[--j] ? k : j;

        	int s= a\[m\]; a\[m\]= a\[k\]; a\[k\]= s;
        }
        

        }

        (This code guaranteed unchecked for correctness :-)) Applying your transforms should give something shorter than ever.

        1 Reply Last reply
        0
        • C Chris Maunder

          What's the smallest code you can come up with to find the n smallest numbers in a random sample of m numbers where n < m. Any language, speed is not an issue.

          cheers, Chris Maunder The Code Project | Co-founder Microsoft C++ MVP

          Y Offline
          Y Offline
          YvesDaoust
          wrote on last edited by
          #70

          This is a straight selection sort, processing back to front and doing immediate swaps to avoid index bookeeping.

          void g(int a[], int m)
          {
          for (int s, p; p= --m;)
          while (p--)
          if (s= a[m], a[p] > s)
          a[m]= a[p], a[p]= s;
          }

          or, said shortly,

          void g(int*a,int m){for(int s,p;p=--m;)while(p--)if(s=a[m],a[p]>s)a[m]=a[p],a[p]=s;}

          The requested solution lies in a[0..n-1]. I guess it will be hard to improve on this straight selection approach, given that - two nested loops are required, - two decreasing indexes are required (m and p), - a swap variable is required (s), - a key comparison is required, - three assignments are required for the swaps, wherever they take place.

          T 1 Reply Last reply
          0
          • Y YvesDaoust

            And as said in my next post (have a look into the future), passing argument n is unessential, use m instead and spare 6 characters.

            T Offline
            T Offline
            Trajan McGill
            wrote on last edited by
            #71

            Good point, once you're doing a sort like this, you might as well just sort the whole array.

            Y 2 Replies Last reply
            0
            • T Trajan McGill

              Good point, once you're doing a sort like this, you might as well just sort the whole array.

              Y Offline
              Y Offline
              YvesDaoust
              wrote on last edited by
              #72

              Yep, they say running time is for free...

              1 Reply Last reply
              0
              • T Trajan McGill

                Good point, once you're doing a sort like this, you might as well just sort the whole array.

                Y Offline
                Y Offline
                YvesDaoust
                wrote on last edited by
                #73

                And by the way, I have explored an approach where the high values in the array are allowed to be destroyed. Just passing parameter n spoils this effort !

                1 Reply Last reply
                0
                • Y YvesDaoust

                  This is a straight selection sort, processing back to front and doing immediate swaps to avoid index bookeeping.

                  void g(int a[], int m)
                  {
                  for (int s, p; p= --m;)
                  while (p--)
                  if (s= a[m], a[p] > s)
                  a[m]= a[p], a[p]= s;
                  }

                  or, said shortly,

                  void g(int*a,int m){for(int s,p;p=--m;)while(p--)if(s=a[m],a[p]>s)a[m]=a[p],a[p]=s;}

                  The requested solution lies in a[0..n-1]. I guess it will be hard to improve on this straight selection approach, given that - two nested loops are required, - two decreasing indexes are required (m and p), - a swap variable is required (s), - a key comparison is required, - three assignments are required for the swaps, wherever they take place.

                  T Offline
                  T Offline
                  Trajan McGill
                  wrote on last edited by
                  #74

                  Actually, we can do away with one of the loops if we make use of some evaluation short circuiting trickery to make one loop act like two. Thus this:

                  void g(int*a,int m){for(int s,p;p=--m;)while(p--)if(s=a[m],a[p]>s)a[m]=a[p],a[p]=s;}

                  becomes this:

                  void g(int*a,int m){for(int s,p=0;p--||(p=--m);)if(s=a[m],a[p]>s)a[m]=a[p],a[p]=s;}

                  which saves us one whole character. :) It might be possible to figure out a way to cut off a couple more, I'm not sure. I've considered, but not had enough time to exhaust, possibilities like going forward vs. backward on either one or both of the iterators, using a pointer rather than an index into the array, whether sorting in reverse order (putting the smallest elements at the end of the array rather than the beginning) might help, and the possibility of somehow using the array itself for swapping to eliminate a variable, but probably most of these are going to add code rather than reduce it. There's also the possibility of a recursive solution, but I haven't really tried that at all. I have to go do some real work, unfortunately, but this C solution is getting surprisingly close in length to some of the solutions using languages with handy built-in functions to do this sort of thing.

                  Y 1 Reply Last reply
                  0
                  • T Trajan McGill

                    Actually, we can do away with one of the loops if we make use of some evaluation short circuiting trickery to make one loop act like two. Thus this:

                    void g(int*a,int m){for(int s,p;p=--m;)while(p--)if(s=a[m],a[p]>s)a[m]=a[p],a[p]=s;}

                    becomes this:

                    void g(int*a,int m){for(int s,p=0;p--||(p=--m);)if(s=a[m],a[p]>s)a[m]=a[p],a[p]=s;}

                    which saves us one whole character. :) It might be possible to figure out a way to cut off a couple more, I'm not sure. I've considered, but not had enough time to exhaust, possibilities like going forward vs. backward on either one or both of the iterators, using a pointer rather than an index into the array, whether sorting in reverse order (putting the smallest elements at the end of the array rather than the beginning) might help, and the possibility of somehow using the array itself for swapping to eliminate a variable, but probably most of these are going to add code rather than reduce it. There's also the possibility of a recursive solution, but I haven't really tried that at all. I have to go do some real work, unfortunately, but this C solution is getting surprisingly close in length to some of the solutions using languages with handy built-in functions to do this sort of thing.

                    Y Offline
                    Y Offline
                    YvesDaoust
                    wrote on last edited by
                    #75

                    Nice trick !

                    1 Reply Last reply
                    0
                    • C Chris Maunder

                      What's the smallest code you can come up with to find the n smallest numbers in a random sample of m numbers where n < m. Any language, speed is not an issue.

                      cheers, Chris Maunder The Code Project | Co-founder Microsoft C++ MVP

                      M Offline
                      M Offline
                      Member 8085210
                      wrote on last edited by
                      #76

                      Let x be such a sample. Then x[rank(x)<=n] is such a subsample, in R. If there are elements in the sample that are repeated and you want the first n different numbers, it is a bit more complicated, since you have to check first that there are at least n different elements in your sample, using ux<-unique(x), for instance.

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups