In the mists of memory I recall hearing of such exploits. Sorry, I have no reference.

I don't have a tacit tail-recursion for quicksort, but an explicit one would look like

qsort =: 3 : 0
region =. 0 , <: #y  NB. The region being sorted here
while. there is data do.
  choose pivot;
  NB. partition (sortregion =. region ;.0 y) so that indexes in
  NB. ({. region to <: ppoint) are before (ppoint to {: region)
  'y ppoint' =. partition y
  NB. get start/end points of partition
  intervals =. 1 0 1 #^:_1!.ppoint region
  NB. Get the index of the smaller region
  recursionindex =. >/ 2 -~/\ intervals
  NB. recur to sort the smaller interval
  y =. (qsort on the smaller interval) (smaller interval)} y
  NB. loop back to process the larger interval (tail recursion)
  region =. recursionindex { 2 ]\ intervals
end.
)

Untested!

The idea is, sort in-place, and recur only on the smaller partition, leaving a change of 'region' to control which part of the array you are sorting in the loop. The loop sorts the larger partition, the recursion the smaller, and since you recur only for the smaller partition you are guaranteed stack depth of no more than lg(n).

Not that this solves all problems! You still have an algorithm that runs in O(n^2) time in the worst case, even though it won't overrun the stack. If the Evil People send you a malformed array, you won't crash, but you will go silent for a very long time.

The best practice to avoid this is, I think, a hybrid that runs quicksort until the stack depth exceeds some large value, and then switches over to heapsort (which has guaranteed performance, though a bit slower than quicksort) to avoid pathological cases.


Me, I don't see Evil People, so I just use /:~ .

Henry Rich

On 8/28/2014 9:27 PM, Thomas Costigliola wrote:
Henry, out of sheer curiosity, if you have a story of such evil follies I
would be delighted to hear it. More seriously, do you have a tacit tail
recursive verb for quicksort to share ? This is related to this post
http://www.jsoftware.com/pipermail/programming/2014-August/039023.html



On Thu, Aug 28, 2014 at 9:18 PM, Henry Rich <[email protected]> wrote:

On the contrary, stack depth is a killer for quicksort.  In the worst
case, the stack depth is the number of items, as each partitioning gives a
partition of just one element.  Tail recursion solves this problem.

Not likely, you say?  If your code is deployed somewhere important, Evil
People will send it an array that will produce a worst case.

Perhaps you can use a random pivot... as long as the Evil People can't
guess your sequence.

Henry Rich


On 8/28/2014 9:13 PM, Raul Miller wrote:

I guess I'd like to see your code to better understand how you are
thinking.

You might have a good point. You might be overlooking something. But I do
not know yet.

(This sounds fun, but stack depth is unlikely to be a problem for
quicksort. Also, quicksort is often overkill and /:~ or bare /: are also
worth considering.)

Thanks,

  ----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to