MathGroup Archive 2001

[Date Index] [Thread Index] [Author Index]

Search the Archive

RE: Re: Question involving scope/recursion/arguments

  • To: mathgroup at smc.vnet.net
  • Subject: [mg27776] RE: [mg27731] Re: Question involving scope/recursion/arguments
  • From: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.de>
  • Date: Wed, 14 Mar 2001 04:07:34 -0500 (EST)
  • Sender: owner-wri-mathgroup at wolfram.com

Eric,

you can transpose the recursive procedure Quicksort to Mathematica. However
you must be careful with passing of the array to be sorted. In a common
procedural language this is done either by reference or by value of a
pointer. The substitute for that within Mathematica is to pass an
unevaluated symbol. This is best done, by giving the function an appropriate
Hold-Attribute. Here is a direct (and unpolished) transposition of Quicksort
as given by Robert Sedgewick "Algorithms in C++" p.118:

In[1]:= Attributes[qsort] = HoldFirst
In[2]:=
qsort[a_Symbol, l_Integer, r_Integer] :=
  If[r > l, Block[{v = a[[r]], i = l - 1, j = r},
      While[True,
        While[a[[++i]] < v,];
        While[a[[--j]] > v,];
        If[i >= j, Break[]];
        a[[{i, j}]] = a[[{j, i}]];];
      a[[{i, r}]] = a[[{r, i}]];
      qsort[a, l, i - 1];
      qsort[a, i + 1, r];]]

As you see, all manipulation is done within the array a, no copy is being
made.

In[5]:= l = Table[Random[Integer, {1, 10}], {10}]
Out[5]=
{2, 1, 7, 6, 8, 1, 10, 7, 7, 7}

In[6]:= qsort[l, 1, 10]
In[7]:= l
Out[7]=
{1, 1, 2, 6, 7, 7, 7, 7, 8, 10}

So l has been sorted ("in place").


Now we test for n log n - behaviour:

In[8]:= SeedRandom[99999999]
In[9]:=
Table[l = Table[Random[Integer, {1, 2^#}], {2^#}]; 
      Timing[qsort[l, 1, 2^#]][[1]]] & /@ Range[8, 16]
Out[9]=
{0.13 Second, 0.271 Second, 0.621 Second, 1.342 Second, 2.884 Second, 
  6.119 Second, 14.1 Second, 27.53 Second, 57.833 Second}


Generally in Mathematica we like to look out for a functional alternative.
Here is one for quicksort:
 
In[2]:= qs[{p_, r__}, s_] :=
  With[{low = Cases[{r}, x_ /; x < p], upp = Cases[{r}, x_ /; x >= p]},
    qs[low, {p, qs[upp, s]}]]

In[3]:= qs[a_, b_] := {a, b}

In[4]:= qsort2[l_] := Flatten[qs[l, {}]]

You see that for each recursion step new Lists ("arrays") are generated (by
Cases), but this is not a slow operation of Order n for each step, and we
have only log n recursions. The trick to separate Quicksort into the
recursive function qs, and then flattening once at the single, final step is
decisive here. If flattening is done within the recursion the algorithm
becomes very bad ~ O[n^2].


Again we test for n log n - behaviour

In[7]:= SeedRandom[99999999]
In[8]:=
ll = Table[Random[Integer, {1, 2^#}], {2^#}] & /@ Range[8, 16];
In[9]:=
Timing[qsort2[#]][[1, 1]] & /@ ll
Out[9]=
{0.12, 0.23, 0.521, 1.152, 2.303, 5.128, 10.905, 22.683, 49.371}

We see that this slightly better than the procedural approach!
However this all cannot cope with Mathematica's built-in Sort, which is
faster by two orders of magnitude, but there programming is done at machine
level.


It may be interesting to look at the result of qs, when it terminates:
 
In[16]:= l = Table[Random[Integer, {1, 10}], {10}]
Out[16]=
{6, 4, 9, 1, 3, 6, 1, 6, 7, 2}

In[17]:= qs[l, {}]
Out[17]=
{{}, {1, {{}, {1, {{2}, {3, {{}, {4, {{}, {6, {{}, {6, {{}, {6, {{7}, {9, \
{{}, {}}}}}}}}}}}}}}}}}}

In[18]:= qsort2[l]
Out[18]= {1, 1, 2, 3, 4, 6, 6, 6, 7, 9}

-- Hartmut



> -----Original Message-----
> From: John Eric Hanson [mailto:jhanson1 at stny.rr.com]
To: mathgroup at smc.vnet.net
> Sent: Tuesday, March 13, 2001 9:53 AM
> To: mathgroup at smc.vnet.net
> Subject: [mg27776] [mg27731] Re: Question involving scope/recursion/arguments
> 
> 
> Paul-
> 
> One common example of what I'm trying to do is the quicksort 
> algorithm -
> where a list or an array is sorted in place recursively.  I 
> am finding greta
> frustration trying to find the Mathematica technique which 
> would result in
> behavior similar to passing an argument by reference or a 
> pointer to an
> argument.
> 
> I can do this with a global variable, but then, as far as I 
> can see, I'm
> bound to passing in an argument with the same name as the 
> global variable
> I'm using (else I have to make a copy of the variable unless 
> Mathematica
> will allow two variables to reference the same data in memory - I'm
> obviously reasonably new to Mathematica).
> 
> Thanks again,
> 
> Eric
> 
> 
> > Well, you don't specify what you want to do, so I can only 
> offer this
> > generic advice:
> >
> > f[list_,a_,b_] := (g[list], If[r, list = f[list_,c,d], STOP])
> >
> > Or you can make the list global, not a passed argument.
> >
> > --
> > Paul Lutus
> > www.arachnoid.com
> >
> >
> >
> >
> 
> 



  • Prev by Date: RE: plot matrix
  • Next by Date: Re: Re: Question involving scope/recursion/arguments
  • Previous by thread: Re: Question involving scope/recursion/arguments
  • Next by thread: Re: Re: Question involving scope/recursion/arguments