## ## Datastructures: GAP package providing common datastructures. ## ## Copyright (C) 2015-2017 The datastructures team. ## For list of the team members, please refer to the COPYRIGHT file. ## ## This package is licensed under the GPL 2 or later, please refer ## to the COPYRIGHT.md and LICENSE files for details. ##
# This file implements double ended queues (deques) using a circular buffer # stored in a GAP plain list. # # The four positions in a deque Q have the following purpose # # Q[1] - head, the index in Q[4] of the first element in the deque # Q[2] - tail, the index in Q[4] of the last element in the deque # Q[3] - capacity, the allocated capacity in the deque # Q[4] - factor by which storage is resized if capacity is exceeded # Q[5] - GAP plain list with storage for capacity many entries # # Global constants QHEAD, QTAIL, QCAPACITY, QFACTOR, and QDATA are bound to # reflect the above. # # When a push fills the deque, its capacity is resized by QFACTO R using # PlistDequeExpand. A new empty plist is allocated and all current entries of # the deque are copied into the new plist with the head entry at index 1. # # The deque is empty if and only if head = tail and the entry that head and tail # point to in the storage list is unbound.
InstallGlobalFunction(PlistDeque, function(arg)
local capacity, factor, result;
if Length(arg) >= 1then if not IsPosInt(arg[1]) then
ErrorNoReturn("<capacity> must be a positive integer"); fi;
capacity := arg[1]; fi; if Length(arg) >= 2then if not IsRat(arg[2]) or (arg[2] <= 1) then
ErrorNoReturn("<factor> must be a rational greater than 1"); fi;
factor := arg[2]; fi;
result := [1, 1, capacity, factor, EmptyPlist(capacity)];
Objectify(PlistDequeType, result);
return result; end);
InstallGlobalFunction(PlistDequePushBack, function(deque, item)
local head, tail, last;
if item = fail then
ErrorNoReturn("<item> must not equal 'fail'"); fi;
head := deque![QHEAD];
tail := deque![QTAIL];
last := deque![QCAPACITY];
# Special case for empty deque, # head = tail and deque![QDATA][tail] is # not bound if not IsBound(deque![QDATA][tail]) then
deque![QDATA][tail] := item; else if tail = last then
tail := 1; else
tail := tail + 1; fi;
deque![QDATA][tail] := item;
deque![QTAIL] := tail;
# If deque is full expand if ((head = 1) and (tail = last))
or (tail + 1 = head) then
PlistDequeExpand(deque); fi; fi; end);
InstallGlobalFunction(PlistDequePushFront, function(deque, item)
local head, tail, last;
if item = fail then
ErrorNoReturn("<item> must not equal 'fail'"); fi;
head := deque![QHEAD];
tail := deque![QTAIL];
last := deque![QCAPACITY];
# If the deque is empty if not IsBound(deque![QDATA][head]) then
deque![QDATA][head] := item; else if head = 1then
head := last; else
head := head - 1; fi;
deque![QDATA][head] := item;
deque![QHEAD] := head;
if (head = 1 and tail = last)
or (tail + 1 = head) then
PlistDequeExpand(deque); fi; fi; end);
InstallGlobalFunction(PlistDequePopFront, function(deque)
local head, tail, last, result;
if IsEmpty(deque) then
return fail; fi;
head := deque![QHEAD];
tail := deque![QTAIL];
last := deque![QCAPACITY];
result := deque![QDATA][head];
Unbind(deque![QDATA][head]); if head <> tail then if head = last then
head := 1; else
head := head + 1; fi;
deque![QHEAD] := head; fi;
return result; end);
InstallGlobalFunction(PlistDequePopBack, function(deque)
local head, tail, last, result;
if IsEmpty(deque) then
return fail; fi;
head := deque![QHEAD];
tail := deque![QTAIL];
last := deque![QCAPACITY];
result := deque![QDATA][tail];
Unbind(deque![QDATA][tail]);
if head <> tail then if tail = 1then
tail := last; else
tail := tail - 1; fi;
deque![QTAIL] := tail; fi;
return result; end);
InstallGlobalFunction(PlistDequePeekFront, function(deque) if IsEmpty(deque) then
return fail; fi;
return deque![QDATA][deque![QHEAD]]; end);
InstallGlobalFunction(PlistDequePeekBack, function(deque) if IsEmpty(deque) then
return fail; fi;
return deque![QDATA][deque![QTAIL]]; end);
InstallGlobalFunction(PlistDequeExpand, function(deque)
local result, p, head, tail, last, factor;
head := deque![QHEAD];
tail := deque![QTAIL];
last := deque![QCAPACITY];
factor := deque![QFACTOR];
deque![QCAPACITY] := Int(factor * last); if deque![QCAPACITY] = last then # TODO: Maybe display a warning here # might require introducing an # InfoClass
deque![QCAPACITY] := last + 5; fi;
result := EmptyPlist(deque![QCAPACITY]);
# Copy data into new list.
p := 1; while head <> tail do
result[p] := deque![QDATA][head];
p := p + 1;
head := head + 1; if head > last then
head := 1; fi;
od;
result[p] := deque![QDATA][head];
InstallMethod(PushBack, "for IsPlistDeque and an object",
[IsPlistDequeRep, IsObject],
PlistDequePushBack);
InstallMethod(PushFront, "for IsPlistDeque and an object",
[IsPlistDequeRep, IsObject],
PlistDequePushFront);
InstallMethod(PopFront, "for IsPlistDeque and an object",
[IsPlistDequeRep],
PlistDequePopFront);
InstallMethod(PopBack, "for IsPlistDeque and an object",
[IsPlistDequeRep],
PlistDequePopBack);
InstallOtherMethod(IsEmpty, "for IsPlistDeque",
[IsPlistDequeRep], function(deque)
local head;
head := deque![QHEAD];
return not IsBound(deque![QDATA][head]); end);
InstallOtherMethod(Size, "for IsPlistDeque",
[IsPlistDequeRep], function(deque)
local head, tail;
head := deque![QHEAD];
tail := deque![QTAIL];
if not IsBound(deque![QDATA][head]) then
return 0; else if tail >= head then
return tail - head + 1; else
return Capacity(deque) - (head - tail) + 1; fi; fi; end);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.