std.container & ranges

Steven Schveighoffer schveiguy at yahoo.com
Sat Nov 5 16:55:03 PDT 2011


On Sat, 05 Nov 2011 17:28:34 -0400, Marco Leise <Marco.Leise at gmx.de> wrote:

> Am 02.11.2011, 12:48 Uhr, schrieb Steven Schveighoffer  
> <schveiguy at yahoo.com>:
>> In dcollections, removing a specific element (using the default  
>> comparison operator for that element) on a *fast lookup* container is  
>> as simple as:
>>
>> container.remove(container.find(x));
>>
>> Which removes the element x if it's found.  However, this is not  
>> defined for containers which use O(n) time to search (such as linked  
>> list), you must use std.algorithm.find for that:
>>
>> container.remove(find(container[], x).begin);
>>
>> Should work, and takes O(n) time.
>>
>> -Steve
>
> While I stumble over this. I found that I sometimes need a certain  
> container (data structure/algorithm), but with an additional fast  
> removal or lookup. So I returned a "handle" (a pointer or array index)  
> for any inserted element that you can store (in the element itself for  
> example) and use for lookup/removal. Templates bake the correct struct  
> for this:
>
> // The element I want to store
>
> struct Element {
>    // ... actual data
>    size_t handle; // a pointer to a node in disguise, returned from  
> insert(...)
> }
>
> // A collection node
>
> struct Node {
>    Element e;
>    Node* prev;
>    Node* next;
> }
>
> // Usage
>
> elem.handle = list.insert(elem);
> list.remove(elem.handle);

You should be able to do this with dcollections:

struct Element(T) {
    T data;
    List!T.cursor handle;
}

elem.handle = list.insert(list.end, elem.data); // x is the value being  
inserted
list.remove(elem.handle);  // removes the element you inserted earlier.

Note, you have to specify an insertion point (this is similar to C++).   
But note that you can't exactly create a handle to a list of the Element  
type, because you need that cursor type to define Element.

> Now you have a double-linked list with O(1) removal, as long as you keep  
> the handle around. The limitation is, that the handle has to remain  
> constant. So a binary heap with the elements embedded in an array and no  
> indirection through a pointer would not work. As soon as elements are  
> reorganized, their handle (array index in this case) becomes invalid.
> But the point is, that you can reduce the time complexity for removal in  
> every data structure like this in an implementation agnostic way (unless  
> plain array of elements) and I think it is better than Java's approach  
> that just works, but may result in an O(n) lookup operation.
> Iterators with remove functionality overlap with this partially. (They  
> don't need an extra handle stored somewhere, but generally go over the  
> complete list.)

Definitely.  This is the benefit of iterators/cursors.  The ability to  
refer to exactly one element makes things much more straightforward.  It's  
why dcollections has cursors.

-Steve


More information about the Digitalmars-d-learn mailing list