caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Brian Hurt <bhurt@spnz.org>
To: james woodyatt <jhw@wetware.com>
Cc: Ocaml Trade <caml-list@inria.fr>
Subject: Re: [Caml-list] looping recursion
Date: Thu, 29 Jul 2004 14:25:05 -0500 (CDT)	[thread overview]
Message-ID: <Pine.LNX.4.44.0407291406350.6739-100000@localhost.localdomain> (raw)
In-Reply-To: <B449A1C2-E187-11D8-9C86-000A958FF2FE@wetware.com>

On Thu, 29 Jul 2004, james woodyatt wrote:

> On 29 Jul 2004, at 09:12, Brian Hurt wrote:
> > On Thu, 29 Jul 2004, brogoff wrote:
> >>
> >> Some problems are just way easier to solve with imperative programming
> >> though. Have you ever taken a look at purely functional catenable 
> >> deques?
> >
> > Just got added to extlib, for the record.  A simplistic version that
> > actually isn't that much more complicated than the imperitive
> > implementation.
> 
> This is extraordinary!  Do you really mean to say the deques are purely 
> functional, catenable *and* offering the same complexity as the 
> non-persistent implementation?  Which algorithm was added to extlib?
> 

The version added is O(1) ammoritized.  It has the same problem as 
quicksort and hashtables, in that on average about 1 operation in N has 
cost O(N), instead of strict O(1).

The library added was the simplest double list implementation.  Basically, 
the queue is broken into two parts- a front part and a back part, both 
kept in lists.  The back part list is kept in reverse order- so to add an 
element to the end of the queue, you prepend it to the back part list.  
You remove elements from head of the front part queue, and when it's 
empty, you replace it with the reverse of the back part list.

Every element that goes through the queue is touched precisely three 
times- once when it's added to the end of the queue, once when it's 
removed from the head of the queue, and once when we reverse the back half 
to become the new front half.  So adding and then removing N elements from 
the list costs O(N).

The core code looks like this:

type 'a deque = 'a list * 'a list

let empty = ([], []) (* the empty queue *)

let add q x =
    match q with
        | ([], []) -> (* We add the first element to the front *)
            ([x], [])
        | ([], _) -> assert false
        | (front, back) -> (front, x :: back)

let remove q =
    match q with
        | ([], []) -> invalid_arg "remove"
        | ([], _) -> assert false
        | (h :: [], back) -> h, ((List.rev back), [])
        | (h :: front, back) -> h, (front, back)

I will note that if you use a capability that applicative semantics give 
us, you can get into trouble.  Imagine the following scenario: you create 
an empty queue and add 1000 new elements.  You then remove one element.  
This does a List.rev on a 999 element list.  You then throw the modified 
queue away, and remove the first element from the original queue again, 
reversing the same 999 element list.  Repeat- every removing reverses the 
same list.

The solution to this is "don't do that!"  Note that pushing an element 
onto the head of the queue is strict O(1):

let push x (front, back) = (x :: front, back)

Rather than using the applicative semantics to undo the removal, use push 
to push back the removed elements.  This way, you only reverse the back 
half of the list once.

-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


  reply	other threads:[~2004-07-29 19:17 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-07-27 23:43 briand
2004-07-28  0:27 ` John Prevost
2004-07-28  0:38   ` John Prevost
2004-07-28  1:17     ` skaller
2004-07-28  1:05   ` briand
2004-07-28  1:43     ` Brian Hurt
2004-07-28  2:49       ` briand
2004-07-28  3:12         ` Brian Hurt
2004-07-28  3:20         ` Brian Hurt
2004-07-28  5:54         ` brogoff
2004-07-28  7:22           ` Alex Baretta
2004-07-28 16:38             ` brogoff
2004-07-28 19:40               ` Jon Harrop
2004-07-28 20:18                 ` Brandon J. Van Every
2004-07-29  6:01                   ` Alex Baretta
2004-07-28 21:22                 ` brogoff
2004-07-29  9:13                   ` Daniel Andor
2004-07-29  9:25                     ` Keith Wansbrough
2004-07-29  9:41                       ` Nicolas Cannasse
2004-07-29  9:57                       ` Xavier Leroy
2004-07-29 10:44                         ` Daniel Andor
2004-07-29 12:56                           ` brogoff
2004-07-29 10:11                     ` skaller
2004-07-29 12:41                     ` brogoff
2004-07-29  6:28               ` Alex Baretta
2004-07-29 14:58                 ` brogoff
2004-07-29 16:12                   ` Brian Hurt
2004-07-29 17:49                     ` james woodyatt
2004-07-29 19:25                       ` Brian Hurt [this message]
2004-07-29 20:01                         ` brogoff
2004-07-30  4:42                           ` james woodyatt
2004-07-29 17:44                   ` james woodyatt
2004-07-29 23:12                     ` skaller
2004-07-29 22:42                   ` Alex Baretta
2004-07-30  2:38                     ` Corey O'Connor
     [not found]                     ` <200407300136.14042.jon@jdh30.plus.com>
2004-07-30 12:45                       ` Alex Baretta
2004-07-30 17:07                     ` brogoff
2004-07-30 18:25                       ` [Caml-list] kaplan-okasaki-tarjan deque (was "looping recursion") james woodyatt
2004-07-30 21:20                         ` brogoff
2004-07-31  5:37                           ` james woodyatt
2004-07-28  7:27       ` [Caml-list] looping recursion skaller
2004-07-28 14:36         ` Brian Hurt
2004-07-28 22:05           ` skaller
2004-07-28  0:37 ` skaller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.44.0407291406350.6739-100000@localhost.localdomain \
    --to=bhurt@spnz.org \
    --cc=caml-list@inria.fr \
    --cc=jhw@wetware.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).