/
CDC-1.2b/
CDC-1.2b/src/
parent $frob_class
object $heap_class

var $root child_index 0
var $root owners [$heap_class]
var $root owned [$heap_class]
var $root fertile 0
var $root inited 1
var $root manager $heap_class
var $root writable [$heap_class]
var $root readable ['parameters, 'methods, 'code]
var $root dbref 'heap_class

method new
    arg list, [key];
    var ret_heap;
    
    // returns list as a valid heap sorted on key || 1
    key = [@key, 1][1];
    if (!list)
        return <this(), #[['key, key], ['data, []]]>;
    ret_heap = .new([], key);
    while (list) {
        ret_heap = ret_heap.add(list[1]);
        list = delete(list, 1);
    }
    return ret_heap;
.

method data
    arg self;
    
    return self['data];
.

method should_swap
    arg self, element1, element2;
    
    // returns true iff data[element2] should appear earlier in the list to maintain
    // consistent data structure.
    // re-define in children of $heap_class to adjust sort order
    return 0;
.

method swap
    arg self, a, b;
    
    return <this(), self.replace('data, $list.swap(self['data], a, b))>;
.

method add
    arg self, element;
    var swap, cur_element, element_above;
    
    // add element to self
    // tack it on the end and change self from rep (a dict) to heap_class
    self = <this(), self.replace('data, (self['data]) + [element])>;
    
    // loop percolates new element up
    cur_element = self.length();
    element_above = cur_element / 2;
    swap = 1;
    while (element_above && swap) {
        if (self.should_swap(element_above, cur_element))
            self = self.swap(element_above, cur_element);
        else
            swap = 0;
        cur_element = element_above;
        element_above = cur_element / 2;
    }
    return self;
.

method del
    arg self, element;
    var data, cur_element, next_element, len;
    
    // remove element'th element from self
    // this method works by pushing element down the heap, swapping it with
    // the element below it that should be on top (of the two).
    // self rep changed to frob for swapping
    self = <this(), self>;
    
    // data = self['data];
    len = self.length();
    if ((element > len) || (element < 1))
        throw(~range, "Element index out of range.");
    cur_element = element;
    next_element = cur_element * 2;
    while (next_element < len) {
        if (self.should_swap(next_element, next_element + 1))
            next_element = next_element + 1;
        self = self.swap(cur_element, next_element);
        cur_element = next_element;
        next_element = cur_element * 2;
    }
    
    // if it didn't trickle down to the end...
    if (cur_element != len) {
        // swap cur w/ last (so we can delete it)
        self = self.swap(cur_element, len);
    
        // tricle swapped element up
        next_element = cur_element / 2;
        while (next_element) {
            if (self.should_swap(next_element, cur_element))
                self = self.swap(next_element, cur_element);
            else
                next_element = 0;
            cur_element = next_element;
            next_element = cur_element / 2;
        }
    }
    self = self._drop_last();
    return self;
.

method _drop_last
    arg rep;
    
    if (!(rep['data]))
        throw(~range, "Attempt to kill last element of null heap.");
    return <this(), rep.replace('data, delete(rep['data], listlen(rep['data])))>;
.

method element
    arg self, index;
    
    return (self['data])[index];
.

method length
    arg self;
    
    return listlen(self['data]);
.

method heaped
    arg self;
    var element;
    
    // returns true if data structure is consistent
    if (!(self['data]))
        return 1;
    element = 1;
    
    // loop through elements
    while (1) {
        if ((!(| .should_swap(self, element, element * 2) |)) && (!(| .should_swap(self, element, (element * 2) + 1) |)))
            element = element + 1;
        else
            return 0;
        if (element >= ((.length(self)) / 2))
            return 1;
    }
.