From: Brian H. <bri...@ql...> - 2003-04-30 15:58:25
|
On Wed, 30 Apr 2003, Nicolas Cannasse wrote: > > I'm playing (while waiting for compiles) at writting a circular, mutable, > > doubly linked list data structure. The advantage of this is that inserts > > anywhere into the list are O(1), if you have a pointer into the list. > > > > Enum is almost a perfect vehicle for this- internal to the enum I'm > > keeping a reference to the current element. If I could just 'reach into' > > the enum and snag this reference, all would be good with the world. But I > > can't figure out how to do that (this may be because it's friday afternoon > > of a long, stressfull week and my brain is mush). > > With circular lists, your next() function will of course never raise > No_more_elements, and count() should also be something like : > let rec infinite_count() = infinite_count() > And doing an *.of_enum with a cicular list will of course run until you kill > the process or run out of memory, same for Enum.iter... You could hack > something like waiting for physical equality with the first element to break > the loop, but if there is a map done before, you will never get it ! Sorry, I wasn't clear. It's internal structure is circular so that I don't have to define a NULL. But externally it will be a finite list, and have a most definate end and begining. This circularness will be hidden internally. Here's the basic idea I have so far and some example functions: type 'a dllist_elem_t = { datum : 'a; mutable next : 'a dllist_elem_t; mutable prev : 'a dllist_elem_t } type 'a dllist_head_t = Empty | NotEmpty of 'a dllist_elem_t type 'a dllist_t = 'a dllist_head_t ref let head dllist = match !dllist with Empty -> assert false (* or something *) | NotEmpty head -> head.datum let prepend dllist x = let rec newelem = { datum = x ; next = newelem ; prev = newelem } in match !dllist with Empty -> dllist := (NotEmpty newelem) | NotEmpty head -> newelem.next <- head; newelem.prev <- head.prev; head.prev <- newelem; newelem.prev.next <- newelem; dllist := NotEmpty(newelem) let count dllist = match !dllist with Empty -> 0 | NotEmpty head -> let tail = head.prev in let rec loop elem cnt = if elem == tail then (cnt + 1) else loop (elem.next) (cnt + 1) in loop head 0 let iter f dllist = match !dllist with Empty -> () | NotEmpty head -> let tail = head.prev in let rec loop elem = f elem; if (elem == tail) then () else loop elem.next in loop head Notice in head- I don't return the dllist_elem_t, I return the element in it. This is how I want it to work- dllist_elem_t never "leaks" out of the internal representation. Also note that although I have a double dereference to get to the first element (the reference and the enumerated type) after that everything else is just 1 reference away. But this actually raises problems with doing a pointer type external from the linked list. I suppose what I want is sort of an OO interface, with a "protected" inteface seen only inside the module, and a "public" interface I can put into the .mli and everyone can use. But I'm not 100% sure how to do this. Brian |