Why function template 'among' is of complexity O(1) and not O(n)?

Ali Çehreli acehreli at yahoo.com
Wed Feb 19 11:45:39 PST 2014


On 02/19/2014 01:46 AM, Gopan wrote:

 > On Wednesday, 19 February 2014 at 09:09:25 UTC, Tobias Pankrath wrote:
 >> On Wednesday, 19 February 2014 at 08:58:10 UTC, Gopan wrote:
 >>> Recently, I came across the following thread
 >>> http://forum.dlang.org/thread/l8nocr$1dv5$1@digitalmars.com?page=2
 >>>
 >>> On Monday, 16 December 2013 at 22:10:52 UTC, Andrei Alexandrescu wrote:
 >>>> On 12/16/13 1:45 PM, Walter Bright wrote:
 >>>>> On 12/16/2013 12:38 PM, Andrei Alexandrescu wrote:
 >>>>>> uint among(T, Us...)(T v, Us vals)
 >>>>>> {
 >>>>>>   foreach (i, U; Us)
 >>>>>>   {
 >>>>>>       if (v == vals[i]) return i + 1;
 >>>>>>   }
 >>>>>>   return 0;
 >>>>>> }
 >>>>>
 >>>>> This has O(n) behavior, which might be unexpected for the user.
 >>>>
 >>>> It's O(1) because the data size is in the source text. There's no
 >>>> variable n.
 >>>
 >>> To me, it looks like a Linear Search and hence of complexity O(n).
 >>> Could somebody please elaborate why it is O(1) and not O(n)?
 >>> If there is an article/document that I am to read to understand this,
 >>> please cite it.
 >>>
 >>> (I am a beginner level programmer and new to D Language.)
 >>>
 >>> Thanks,
 >>> Gopan.
 >>
 >> It's O(k) with k = vals.length, which is the number of arguments given
 >> to the function, which is a compile time constant and not dependent on
 >> any input of the final program. In O(n) the n always relates to the
 >> input somehow.
 >
 > I agree that vals.length is known at compile time.  But while running
 > the application, it iterates through every val in the input list until a
 > match is found.
 > So, how can that be considered O(1)?
 >
 > See my test app and output.
 >
 > uint among(T, Us...)(T v, Us vals)
 > {
 >      foreach (i, U; Us)
 >      {
 >      writeln("checking ", v, " == ", vals[i]);
 >          if (v == vals[i])
 >          return i + 1;
 >      }
 >      return 0;
 > }
 >
 > void main()
 > {
 >      uint index = among(3, 1,2,5,3);
 >      writeln("Index of 3 in (1,2,5,3) is ", index);
 > }
 >
 > outrput of running the app:
 > checking 3 == 1
 > checking 3 == 2
 > checking 3 == 5
 > checking 3 == 3
 > Index of 3 in (1,2,5,3) is 4
 >
 > Or, is my undertanding about Big-O notation of complexity wrong?

You get that output only because you have inserted the writeln() 
expressions in there.

That foreach over variadic template arguments is a "compile-time 
foreach"[1]. For example, if v were 2 and vals were "1, 2, 3", the 
original code would be expanded to the following:

     if (2 == 1) return 1;    // i == 0
     if (2 == 2) return 2;    // i == 1
     if (2 == 3) return 3;    // i == 3

Since all of those conditions is known to be true or false at compile 
time, the compiler will reduce the code to the following:

     return 2;

Ali

[1] http://ddili.org/ders/d.en/tuples.html



More information about the Digitalmars-d-learn mailing list