blob: 89c3276f44a3439af7ea23ce7902f1749f090909 [file] [log] [blame]
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * LISTS * */
/* * * */
/* * $Module: LIST * */
/* * * */
/* * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 * */
/* * MPI fuer Informatik * */
/* * * */
/* * This program is free software; you can redistribute * */
/* * it and/or modify it under the terms of the GNU * */
/* * General Public License as published by the Free * */
/* * Software Foundation; either version 2 of the License, * */
/* * or (at your option) any later version. * */
/* * * */
/* * This program is distributed in the hope that it will * */
/* * be useful, but WITHOUT ANY WARRANTY; without even * */
/* * the implied warranty of MERCHANTABILITY or FITNESS * */
/* * FOR A PARTICULAR PURPOSE. See the GNU General Public * */
/* * License for more details. * */
/* * * */
/* * You should have received a copy of the GNU General * */
/* * Public License along with this program; if not, write * */
/* * to the Free Software Foundation, Inc., 59 Temple * */
/* * Place, Suite 330, Boston, MA 02111-1307 USA * */
/* * * */
/* * * */
/* $Revision$ * */
/* $State$ * */
/* $Date$ * */
/* $Author$ * */
/* * * */
/* * Contact: * */
/* * Christoph Weidenbach * */
/* * MPI fuer Informatik * */
/* * Stuhlsatzenhausweg 85 * */
/* * 66123 Saarbruecken * */
/* * Email: weidenb@mpi-sb.mpg.de * */
/* * Germany * */
/* * * */
/* ********************************************************** */
/**************************************************************/
/* $RCSfile$ */
#include "list.h"
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * MEMORY MANAGEMENT * */
/* * * */
/* ********************************************************** */
/**************************************************************/
LIST list_Copy(const LIST List)
/**************************************************************
INPUT: A List.
RETURNS: The copy of the list.
CAUTION: The entries of the list are NOT copied !
the function needs time O(n), where <n> is the length
of the list.
***************************************************************/
{
LIST Copy;
LIST Scan1,Scan2;
if (list_Empty(List))
return list_Nil();
Copy = list_List(list_Car(List));
Scan1 = Copy;
Scan2 = list_Cdr(List);
while (!list_Empty(Scan2)) {
list_Rplacd(Scan1, list_List(list_Car(Scan2)));
Scan1 = list_Cdr(Scan1);
Scan2 = list_Cdr(Scan2);
}
return Copy;
}
LIST list_CopyWithElement(const LIST List, POINTER (*CopyElement)(POINTER))
/**************************************************************
INPUT: A List and a copy function for the elements.
RETURNS: The copy of the list.
CAUTION: The entries of the list are NOT copied !
The function needs time O(n*c), where <n> is the length
of the list and <c> is the time for a call of the
element copy function.
***************************************************************/
{
LIST Copy;
LIST Scan1,Scan2;
if (list_Empty(List))
return list_Nil();
Copy = list_List(CopyElement(list_Car(List)));
Scan1 = Copy;
Scan2 = list_Cdr(List);
while (!list_Empty(Scan2)) {
list_Rplacd(Scan1, list_List(CopyElement(list_Car(Scan2))));
Scan1 = list_Cdr(Scan1);
Scan2 = list_Cdr(Scan2);
}
return Copy;
}
void list_InsertNext(LIST List, POINTER Pointer)
/**************************************************************
INPUT: A list and a pointer to anything.
RETURNS: A list with Pointer being added at the position that
follows List.
SUMMARY: We enqueue the element at position list_Cdr(List);
The function needs time O(1).
***************************************************************/
{
#ifdef CHECK
if (Pointer == NULL) {
misc_StartErrorReport();
misc_ErrorReport("\n In list_InsertNext: NULL Pointer. ");
misc_FinishErrorReport();
}
#endif
list_Rplacd(List, list_Cons(Pointer, list_Cdr(List)));
}
void list_NMapCar(LIST List, POINTER (*ElementFunc)(POINTER))
/**************************************************************
INPUT: A List and a function for the elements.
RETURNS: The List where all elements are replaced by the result of
the function calls of <ElementFunc> to the elements
CAUTION: The List is not copied !
The function needs time O(n*f), where <n> is the length
of the list and <f> is the time for a call of the
element function.
***************************************************************/
{
LIST Scan;
for (Scan = List; !list_Empty(Scan); Scan = list_Cdr(Scan))
list_Rplaca(Scan, ElementFunc(list_Car(Scan)));
}
void list_Apply(void (*Function)(POINTER), LIST List)
/**************************************************************
INPUT: A non-resulting function and a list.
SUMMARY: Apply the function to all members of the list.
The function needs time O(n*f), where <n> is the length
of the list and <f> is the time for a call of the
element function.
***************************************************************/
{
while (!list_Empty(List)) {
Function(list_Car(List));
List = list_Cdr(List);
}
}
LIST list_Reverse(const LIST List)
/**************************************************************
INPUT: A list.
RETURNS: A new list where the order of the elements is reversed.
EFFECT: The function needs time O(n), where <n> is the length
of the list.
***************************************************************/
{
LIST ReverseList;
LIST Scan;
ReverseList = list_Nil();
for (Scan=List;!list_Empty(Scan);Scan=list_Cdr(Scan))
ReverseList = list_Cons(list_Car(Scan), ReverseList);
return ReverseList;
}
LIST list_NReverse(LIST List)
/**************************************************************
INPUT: A list
RETURNS: The same list with reversed order of items.
CAUTION: Destructive.
The function needs time O(n), where <n> is the length
of the list.
***************************************************************/
{
LIST ReverseList;
LIST Scan1;
LIST Scan2;
ReverseList = list_Nil();
for (Scan1=List; !list_Empty(Scan1); Scan1=list_Cdr(Scan1))
ReverseList = list_Cons(list_Car(Scan1),ReverseList);
for (Scan1=List, Scan2=ReverseList;
!list_Empty(Scan1);
Scan1=list_Cdr(Scan1), Scan2=list_Cdr(Scan2))
list_Rplaca(Scan1, list_Car(Scan2));
list_Delete(ReverseList);
return List;
}
static __inline__ BOOL list_PointerLower (POINTER A, POINTER B)
{
return (NAT) A < (NAT) B;
}
LIST list_PointerSort(LIST List)
/**************************************************************
INPUT: A list
RETURNS: The same list where the elements are sorted as pointers.
EFFECT: The function needs time O(n log n), where <n> is the length
of the list.
CAUTION: Destructive.
***************************************************************/
{
return list_Sort(List, list_PointerLower);
}
BOOL list_SortedInOrder(LIST L, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: A list, and an ordering function.
RETURNS: TRUE, if the list is ordered with respect to the
ordering function, FALSE otherwise.
EFFECT: The function needs time O(n), where <n> is the
length of the list.
***************************************************************/
{
LIST Scan1, Scan2;
if (!(list_Empty(L) || list_Empty(list_Cdr(L)))) {
Scan1 = L;
Scan2 = list_Cdr(Scan1);
/* Scan the list. */
do {
/* If all elements are ordered, then every element */
/* is <= its successor with respect to the ordering */
/* function. */
/* We might have a strictly ordering Test function, */
/* which implements < instead of <=, so let's test */
/* for equality first. */
if (!Test(list_Car(Scan1), list_Car(Scan2)) &&
Test(list_Car(Scan2), list_Car(Scan1)))
/* It is really strictly greater, so return FALSE. */
return FALSE;
Scan1 = list_Cdr(Scan1);
Scan2 = list_Cdr(Scan1);
} while (!list_Empty(Scan2));
}
return TRUE;
}
LIST list_Merge(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: Two sorted lists List1 and List2, and an ordering function.
RETURNS: The merged list ordered with respect to the ordering function.
EFFECT: The function needs time O(n), where <n> is the length of the list.
***************************************************************/
{
LIST Scan1, Scan2, Result, ResultStart;
#ifdef CHECK
if (!list_SortedInOrder(List1, Test)) {
/* print an error message and exit */
misc_StartErrorReport();
misc_ErrorReport("\n In list_Merge: First argument is not sorted.");
misc_FinishErrorReport();
}
else if (!list_SortedInOrder (List2, Test)) {
/* print an error message and exit */
misc_StartErrorReport();
misc_ErrorReport("\n In list_Merge: Second argument is not sorted.");
misc_FinishErrorReport();
}
#endif
if (list_Empty(List1))
return List2;
if (list_Empty(List2))
return List1;
/* This version is derived from list_NNumberMerge, but it doesn't need */
/* to allocate and deallocate memory, so it should be more efficient. */
/* Use the list with the least element as result list. */
if (Test(list_Car(List1), list_Car(List2))) {
ResultStart = List1;
Scan1 = list_Cdr(List1);
Scan2 = List2;
}
else {
ResultStart = List2;
Scan1 = List1;
Scan2 = list_Cdr(List2);
}
/* Result is the last element of the merged list. */
Result = ResultStart;
while (!list_Empty(Scan1) && !list_Empty(Scan2)) {
/* This function doesn't implement stable merging. */
/* Add another test if you need it. */
if (Test(list_Car(Scan1), list_Car(Scan2))) {
list_Rplacd(Result,Scan1);
Scan1 = list_Cdr(Scan1);
}
else {
list_Rplacd(Result,Scan2);
Scan2 = list_Cdr(Scan2);
}
Result = list_Cdr(Result);
}
if (list_Empty(Scan1))
list_Rplacd(Result, Scan2);
else
list_Rplacd(Result, Scan1);
return ResultStart;
}
void list_Split(LIST L, LIST *Half1, LIST *Half2)
/**************************************************************
INPUT: A list, and two pointers to lists.
RETURNS: Nothing.
EFFECT: The input list is split in two. <Half1> and
<Half2> point to the resulting halves.
The input list is destructively changed!
If the list length is odd, <Half2> is assigned the
bigger part.
The function needs time O(n), where <n> is the
length of the input list.
***************************************************************/
{
/* Adapted code from proofcheck ... MergeSort. */
LIST SingleStep, DoubleStep, Prev;
if (list_Empty(L) || list_Empty(list_Cdr(L))) {
*Half1 = list_Nil();
*Half2 = L;
}
else {
/* divide list in two halves */
Prev = L;
SingleStep = list_Cdr(L);
DoubleStep = list_Cdr(SingleStep);
while (!list_Empty(DoubleStep) && !list_Empty(list_Cdr(DoubleStep))) {
Prev = SingleStep;
SingleStep = list_Cdr(SingleStep);
DoubleStep = list_Cdr(list_Cdr(DoubleStep));
}
*Half1 = L;
*Half2 = SingleStep;
list_Rplacd(Prev, list_Nil());
}
}
LIST list_MergeSort (LIST L, BOOL (*Test) (POINTER, POINTER))
/**************************************************************
INPUT: A list, and an ordering function.
RETURNS: The list sorted with respect to the ordering function.
EFFECT: The function needs time O((n log n) * t), where
<n> is the length of the input list and <t> is the
execution time of the ordering function.
***************************************************************/
{
LIST Result;
#ifdef CHECK
NAT originallength;
originallength = list_Length(L);
#endif
/* Only sort if list has more than one element */
if (!list_Empty(L) && !list_Empty(list_Cdr(L))) {
LIST lowerhalf;
LIST greaterhalf;
LIST *lowerhalfptr;
LIST *greaterhalfptr;
lowerhalfptr = &lowerhalf;
greaterhalfptr = &greaterhalf;
list_Split(L, lowerhalfptr, greaterhalfptr);
#ifdef CHECK
if((list_Length(lowerhalf) + list_Length(greaterhalf))
!= originallength) {
/* output an error message and exit */
misc_StartErrorReport();
misc_ErrorReport("\n In list_MergeSort: Split lists' total sizes");
misc_ErrorReport("\n don't match original list's size.");
misc_FinishErrorReport();
}
#endif
lowerhalf = list_MergeSort(lowerhalf, Test);
greaterhalf = list_MergeSort(greaterhalf, Test);
#ifdef CHECK
if((list_Length(lowerhalf) + list_Length(greaterhalf))
!= originallength) {
/* output an error message and exit */
misc_StartErrorReport();
misc_ErrorReport("\n In list_MergeSort: Mergesorted lists' total sizes");
misc_ErrorReport("\n don't match original list's size.");
misc_FinishErrorReport();
}
#endif
Result = list_Merge(lowerhalf, greaterhalf, Test);
#ifdef CHECK
if(list_Length(Result) != originallength) {
/* output an error message and exit */
misc_StartErrorReport();
misc_ErrorReport("\n In list_MergeSort: Merged list's size doesn't match ");
misc_ErrorReport("\n original list's size.");
misc_FinishErrorReport();
}
#endif
}
else {
Result = L;
}
return Result;
}
LIST list_InsertionSort(LIST List, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: A list and a 'less' function on the elements.
RETURNS: The same list where the elements are sorted with
respect to Test.
EFFECT: The function needs time O(n^2*t), where <n> is the
length of the list and <t> is the time for the test
function.
CAUTION: Destructive.
***************************************************************/
{
LIST Scan1,Scan2,Min;
POINTER Exchange;
for (Scan1=List; !list_Empty(Scan1); Scan1=list_Cdr(Scan1)) {
Min = Scan1;
for (Scan2 = list_Cdr(Scan1); !list_Empty(Scan2); Scan2 = list_Cdr(Scan2))
if (Test(list_Car(Scan2), list_Car(Min))) {
Exchange = list_Car(Min);
list_Rplaca(Min, list_Car(Scan2));
list_Rplaca(Scan2, Exchange);
}
}
return List;
}
LIST list_Sort(LIST List, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: A list and a 'less' function on the elements.
RETURNS: The same list where the elements are sorted with
respect to Test.
EFFECT: The function needs time O((n log n) *t), where <n>
is the length of the list and <t> is the time for
the test function.
CAUTION: Destructive.
***************************************************************/
{
LIST Result;
#ifdef CHECK
NAT originallength;
originallength = list_Length(List);
#endif
Result = list_MergeSort(List, Test);
#ifdef CHECK
if (!list_SortedInOrder(Result, Test)) {
misc_StartErrorReport();
misc_ErrorReport("\n In list_Sort: list_MergeSort did not sort properly.");
misc_FinishErrorReport();
}
if (list_Length(Result) != originallength) {
misc_StartErrorReport();
misc_ErrorReport("\n In list_Sort: list_MergeSort lost elements. ");
misc_FinishErrorReport();
}
#endif
return Result;
}
/* Help Variable used to store a pointer to the numbering function to use
in element comparisons.
*/
static NAT (*NumberFunction)(POINTER) = NULL;
static __inline__ BOOL list_PointerNumberedLower(POINTER A, POINTER B)
{
return (BOOL) (NumberFunction(A) < NumberFunction(B));
}
static __inline__ BOOL list_PointerNumberedLowerOrEqual(POINTER A, POINTER B)
{
return (BOOL) (NumberFunction(A) <= NumberFunction(B));
}
static __inline__ BOOL list_PointerNumberedGreater(POINTER A, POINTER B)
{
return (BOOL) (NumberFunction(A) > NumberFunction(B));
}
LIST list_NumberSort(LIST List, NAT (*Number)(POINTER))
/**************************************************************
INPUT: A list and function mapping elements to numbers.
RETURNS: The same list where the elements are sorted with
respect to < and the Number function.
EFFECT: The function needs time O((n log n) * f), where <n>
is the length of the list and <f> is the time for a
call of the <Number> function.
CAUTION: Destructive.
***************************************************************/
{
/* Use number function as temporary variable. It is used as
an implicit parameter in list_PointerLower.
We can't make it an explicit parameter, because of the
prototype of list_Sort.
*/
NumberFunction = Number;
return list_Sort(List, list_PointerNumberedLower);
}
LIST list_GreaterNumberSort(LIST List, NAT (*Number)(POINTER))
/**************************************************************
INPUT: A list and function mapping elements to numbers.
RETURNS: The same list where the elements are sorted with
respect to > and the Number function.
EFFECT: The function needs time O((n log n) * f), where <n>
is the length of the list and <f> is the time for a
call of the <Number> function.
CAUTION: Destructive.
***************************************************************/
{
/* Use number function as temporary variable. It is used as
an implicit parameter in list_PointerLower.
We can't make it an explicit parameter, because of the
prototype of list_Sort.
*/
NumberFunction = Number;
return list_Sort(List, list_PointerNumberedGreater);
}
LIST list_NNumberMerge(LIST List1, LIST List2, NAT (*Number)(POINTER))
/**************************************************************
INPUT: Two sorted lists and function mapping elements to
numbers.
RETURNS: The merge of the lists where the elements are sorted
with respect to < and the Number function.
CAUTION: Destructive on both lists.
***************************************************************/
{
NumberFunction = Number;
return list_Merge(List1, List2, list_PointerNumberedLowerOrEqual);
}
POINTER list_DequeueNext(LIST List)
/**************************************************************
INPUT: A list
RETURNS: A pointer to a dequeued element.
SUMMARY: We dequeue the element pointed to by list_Cdr(List).
The function needs time O(1).
***************************************************************/
{
POINTER Pointer;
LIST Memo;
if (list_Empty(List))
return NULL;
Memo = list_Cdr(List);
if (list_Empty(Memo))
return NULL;
Pointer = list_Car(Memo);
list_Rplacd(List, Memo->cdr);
list_Free(Memo);
return Pointer;
}
POINTER list_NthElement(LIST List, NAT Number)
/**************************************************************
INPUT: A List and a natural number.
RETURNS: The <Number>th element of the list, NULL otherwise.
EFFECT: The function needs time O(Number).
***************************************************************/
{
while (!list_Empty(List) && --Number > 0)
List = list_Cdr(List);
if (list_Empty(List))
return NULL;
else
return list_Car(List);
}
void list_DeleteWithElement(LIST List, void (*ElementDelete)(POINTER))
/**************************************************************
INPUT: A list and a delete function for the elements.
RETURNS: Nothing.
EFFECT: The list and all its elements are deleted.
The function needs time O(n*d), where <n> is the length
of the list and <d> is the time for the delete function.
***************************************************************/
{
LIST Scan;
while (!list_Empty(List)) {
Scan = list_Cdr(List);
ElementDelete(list_Car(List));
list_Free(List);
List = Scan;
}
}
NAT list_DeleteWithElementCount(LIST List, void (*ElementDelete)(POINTER))
/**************************************************************
INPUT: A List and a delete function for the elements.
RETURNS: The number of deleted elements.
EFFECT: The List and all its elements are deleted.
The function needs time O(n*d), where <n> is the length
of the list and <d> is the time for the delete function.
***************************************************************/
{
int Result;
LIST Scan;
Result = 0;
while (!list_Empty(List)) {
Scan = list_Cdr(List);
ElementDelete(list_Car(List));
list_Free(List);
List = Scan;
Result++;
}
return Result;
}
LIST list_DeleteElement(LIST List, POINTER Element, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: A list, an element pointer, an equality test for
elements
RETURNS: The list where Element is deleted from List with
respect to Test.
EFFECTS: If List contains Element with respect to EqualityTest,
Element is deleted from List
CAUTION: Destructive. Be careful, the first element of a
list cannot be changed destructively by call by
reference.
***************************************************************/
{
LIST Scan1,Scan2;
while (!list_Empty(List) && Test(Element, list_Car(List))) {
Scan1 = list_Cdr(List);
list_Free(List);
List = Scan1;
}
if (list_Empty(List))
return list_Nil();
Scan2 = List;
Scan1 = list_Cdr(List);
while (!list_Empty(Scan1)) {
if (Test(Element, list_Car(Scan1))) {
list_Rplacd(Scan2, list_Cdr(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
}
else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
return List;
}
LIST list_DeleteElementIf(LIST List, BOOL (*Test)(POINTER))
/**************************************************************
INPUT: A list and a test for elements.
RETURNS: The list where an element is deleted if <Test> on it
succeeds.
CAUTION: Destructive. Be careful, the first element of a list
cannot be changed destructively by call by
reference.
***************************************************************/
{
LIST Scan1,Scan2;
while (!list_Empty(List) && Test(list_Car(List))) {
Scan1 = list_Cdr(List);
list_Free(List);
List = Scan1;
}
if (list_Empty(List))
return list_Nil();
Scan2 = List;
Scan1 = list_Cdr(List);
while (!list_Empty(Scan1)) {
if (Test(list_Car(Scan1))) {
list_Rplacd(Scan2, list_Cdr(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
}
else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
return List;
}
LIST list_DeleteElementIfFree(LIST List, BOOL (*Test)(POINTER),
void (*Delete)(POINTER))
/**************************************************************
INPUT: A list, a test for elements and a delete function
for elements.
RETURNS: The list where an element is deleted if <Test> on it
succeeds.
The element is deleted with <Delete>.
CAUTION: Destructive. Be careful, the first element of a list
cannot be changed destructively by call by reference.
***************************************************************/
{
LIST Scan1,Scan2;
while (!list_Empty(List) && Test(list_Car(List))) {
Scan1 = list_Cdr(List);
Delete(list_Car(List));
list_Free(List);
List = Scan1;
}
if (list_Empty(List))
return list_Nil();
Scan2 = List;
Scan1 = list_Cdr(List);
while (!list_Empty(Scan1)) {
if (Test(list_Car(Scan1))) {
Delete(list_Car(Scan1));
list_Rplacd(Scan2, list_Cdr(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
}
else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
return List;
}
LIST list_DeleteElementFree(LIST List, POINTER Element,
BOOL (*Test)(POINTER, POINTER),
void (*Free)(POINTER))
/**************************************************************
INPUT: A list, an element pointer, an equality test for
elements and a free function for elements.
RETURNS: The list where Element is deleted from List with
respect to Test.
EFFECTS: If the list contains <Element> with respect to <Test>,
<Element> is deleted from the list and freed.
CAUTION: Destructive. Be careful, the first element of a list
cannot be changed destructively by call by reference.
***************************************************************/
{
LIST Scan1,Scan2;
while (!list_Empty(List) && Test(Element, list_Car(List))) {
Scan1 = list_Cdr(List);
Free(list_Car(List));
list_Free(List);
List = Scan1;
}
if (list_Empty(List))
return list_Nil();
Scan2 = List;
Scan1 = list_Cdr(List);
while (!list_Empty(Scan1)) {
if (Test(Element, list_Car(Scan1))) {
list_Rplacd(Scan2, list_Cdr(Scan1));
Free(list_Car(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
}
else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
return List;
}
LIST list_DeleteOneElement(LIST List, POINTER Element, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: A list, an element pointer and an equality test for
elements.
RETURNS: The list where at most one element was deleted from
<List> if the Test between <Element> and the element
succeeds.
EFFECT: The function needs time O(n*t) in the worst case, and
time O(t) in the best case, where <n> is the length of
the list and t is the time for a call of the test function.
CAUTION: Destructive. Be careful, the first element of a list
cannot be changed destructively by call by
reference.
The memory of the deleted element is not freed.
***************************************************************/
{
LIST scan1, scan2;
if (list_Empty(List))
return List;
else {
if (Test(Element, list_Car(List)))
return list_Pop(List);
}
for (scan2 = List, scan1 = list_Cdr(List); !list_Empty(scan1);
scan2 = scan1, scan1 = list_Cdr(scan1)) {
if (Test(Element, list_Car(scan1))) {
list_Rplacd(scan2, list_Cdr(scan1));
list_Free(scan1);
scan1 = list_Cdr(scan2);
return List;
}
}
return List;
}
LIST list_PointerDeleteElement(LIST List, POINTER Element)
/**************************************************************
INPUT: A list and an element pointer
RETURNS: The list where Element is deleted from List with respect to
pointer equality.
EFFECTS: If <List> contains <Element> with respect to pointer equality,
<Element> is deleted from <List>.
This function needs time O(n), where <n> is the length of the list.
CAUTION: Destructive. Be careful, the first element of a list cannot
be changed destructively by call by reference.
***************************************************************/
{
LIST Scan1,Scan2;
while (!list_Empty(List) && Element == list_Car(List)) {
Scan1 = list_Cdr(List);
list_Free(List);
List = Scan1;
}
if (list_Empty(List))
return list_Nil();
Scan2 = List;
Scan1 = list_Cdr(List);
while (!list_Empty(Scan1)) {
if (Element == list_Car(Scan1)) {
list_Rplacd(Scan2, list_Cdr(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
}
else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
return List;
}
LIST list_PointerDeleteElementFree(LIST List, POINTER Element,
void (*Free)(POINTER))
/**************************************************************
INPUT: A list, an element pointer and a free function for
elements.
RETURNS: The list where Element is deleted from List with
respect to pointer equality and freed.
EFFECTS: If List contains Element with respect to pointer
equality, Element is deleted from List
CAUTION: Destructive. Be careful, the first element of a list
cannot be changed destructively by call by
reference.
***************************************************************/
{
LIST Scan1,Scan2;
while (!list_Empty(List) && Element == list_Car(List)) {
Scan1 = list_Cdr(List);
Free(list_Car(List));
list_Free(List);
List = Scan1;
}
if (list_Empty(List))
return list_Nil();
Scan2 = List;
Scan1 = list_Cdr(List);
while (!list_Empty(Scan1)) {
if (Element == list_Car(Scan1)) {
list_Rplacd(Scan2, list_Cdr(Scan1));
Free(list_Car(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
}
else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
return List;
}
LIST list_PointerDeleteOneElement(LIST List, POINTER Element)
/**************************************************************
INPUT: A list and an element pointer.
RETURNS: The list where one occurrence of Element is deleted from List
with respect to pointer equality.
EFFECTS: If List contains Element with respect to pointer equality,
Element is deleted from List.
CAUTION: Destructive. Be careful, the first element of a list cannot
be changed destructively by call by reference.
***************************************************************/
{
LIST Scan1,Scan2;
if (list_Empty(List))
return List;
else {
if (Element == list_Car(List))
return list_Pop(List);
}
Scan2 = List;
Scan1 = list_Cdr(List);
while (!list_Empty(Scan1)) {
if (Element == list_Car(Scan1)) {
list_Rplacd(Scan2, list_Cdr(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
return List;
}
else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
return List;
}
BOOL list_DeleteFromList(LIST* List, POINTER Element)
/**************************************************************
INPUT: A list and an element pointer
RETURNS: TRUE, if Element was deleted; FALSE, otherwise.
EFFECTS: If List contains Element with respect to pointer equality,
all occurrences of Element are deleted from List.
CAUTION: Destructive. Be careful, the first element of a list cannot
be changed destructively by call by reference.
***************************************************************/
{
BOOL Found;
LIST Scan1;
Found = FALSE;
while (list_Exist(*List) && Element == list_Car(*List)) {
Scan1 = list_Cdr(*List);
list_Free(*List);
*List = Scan1;
Found = TRUE;
}
if (list_Exist(*List)) {
LIST Scan2;
Scan2 = *List;
Scan1 = list_Cdr(*List);
while (list_Exist(Scan1)) {
if (Element == list_Car(Scan1)) {
list_Rplacd(Scan2, list_Cdr(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
Found = TRUE;
} else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
}
return Found;
}
BOOL list_DeleteOneFromList(LIST* List, POINTER Element)
/**************************************************************
INPUT: A list and an element pointer
RETURNS: TRUE, if <Element> was deleted; FALSE, otherwise.
EFFECTS: If <List> contains <Element> with respect to pointer equality,
the first occurrence of <Element> is deleted from <List>.
CAUTION: Destructive.
***************************************************************/
{
if (list_Exist(*List)) {
LIST Scan1;
/* special treatment for the first element */
if (Element == list_Car(*List)) {
Scan1 = list_Cdr(*List);
list_Free(*List);
*List = Scan1;
return TRUE;
} else {
LIST Scan2;
for (Scan2 = *List, Scan1 = list_Cdr(*List); list_Exist(Scan1); ) {
if (Element == list_Car(Scan1)) {
list_Rplacd(Scan2, list_Cdr(Scan1));
list_Free(Scan1);
Scan1 = list_Cdr(Scan2);
return TRUE;
} else {
Scan2 = Scan1;
Scan1 = list_Cdr(Scan1);
}
}
}
}
return FALSE;
}
BOOL list_IsSetOfPointers(LIST L)
/**************************************************************
INPUT: A list.
RETURNS: TRUE, if <L> is a set of pointers (without duplicates),
FALSE, otherwise.
EFFECT: The function needs n(n-1)/2 comparisons in the worst case,
where n is the length of the list. So its time complexity
is O(n^2).
***************************************************************/
{
for ( ; !list_Empty(L); L = list_Cdr(L)) {
if (list_PointerMember(list_Cdr(L), list_Car(L)))
return FALSE;
}
return TRUE;
}
LIST list_DeleteDuplicates(LIST List, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: A list, an equality test for elements
RETURNS: The list where multiple occurrences are deleted.
CAUTION: Destructive.
***************************************************************/
{
LIST Scan;
Scan = List;
while (!list_Empty(Scan)) {
list_Rplacd(Scan,
list_DeleteElement(list_Cdr(Scan), list_Car(Scan), Test));
Scan = list_Cdr(Scan);
}
return List;
}
LIST list_DeleteDuplicatesFree(LIST List, BOOL (*Test)(POINTER, POINTER),
void (*Free)(POINTER))
/**************************************************************
INPUT: A list, an equality test for elements, and a free
function for elements.
RETURNS: The list where multiple occurrences are deleted.
CAUTION: Destructive and frees all duplicates.
***************************************************************/
{
LIST Scan;
Scan = List;
while (!list_Empty(Scan)) {
list_Rplacd(Scan, list_DeleteElementFree(list_Cdr(Scan), list_Car(Scan), Test, Free));
Scan = list_Cdr(Scan);
}
return List;
}
LIST list_PointerDeleteDuplicates(LIST List)
/**************************************************************
INPUT: A list
RETURNS: The list where multiple occurrences are deleted.
CAUTION: Destructive.
EFFECT: The function needs
***************************************************************/
{
LIST Scan;
Scan = List;
while (!list_Empty(Scan)) {
list_Rplacd(Scan, list_PointerDeleteElement(list_Cdr(Scan),
list_Car(Scan)));
Scan = list_Cdr(Scan);
}
return List;
}
LIST list_NPointerUnion(LIST List1, LIST List2)
/**************************************************************
INPUT: Two lists.
RETURNS: Regarding both lists as sets, the union of the sets.
CAUTION: Destructive.
***************************************************************/
{
return list_PointerDeleteDuplicates(list_Nconc(List1,List2));
}
LIST list_NUnion(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: Two lists and an equality test for the elements.
RETURNS: Regarding both lists as sets, the union of the sets.
CAUTION: Destructive.
***************************************************************/
{
return list_DeleteDuplicates(list_Nconc(List1,List2), Test);
}
LIST list_NListTimes(LIST List1, LIST List2)
/**************************************************************
INPUT: Two lists of lists.
RETURNS: The list of combinations of element lists.
CAUTION: Destroys List1 and List2.
***************************************************************/
{
LIST Result, Scan1, Scan2;
Result = list_Nil();
if (!list_Empty(List2)) {
for (Scan1=List1; !list_Empty(Scan1); Scan1=list_Cdr(Scan1))
for (Scan2=List2; !list_Empty(Scan2); Scan2=list_Cdr(Scan2))
Result = list_Cons(list_Append(((LIST)list_Car(Scan1)),
list_Copy((LIST)list_Car(Scan2))),
Result);
}
list_DeleteWithElement(List1, (void (*)(POINTER))list_Delete);
list_DeleteWithElement(List2, (void (*)(POINTER))list_Delete);
return Result;
}
LIST list_NIntersect(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: Two lists and an equality test for the elements.
RETURNS: Regarding both lists as sets, the intersection of the sets.
CAUTION: Destructive on List1
***************************************************************/
{
LIST Scan1, Scan2;
while (!list_Empty(List1) && !list_Member(List2, list_Car(List1), Test)) {
Scan1 = list_Cdr(List1);
list_Free(List1);
List1 = Scan1;
}
if (list_Empty(List1))
return List1;
Scan1 = List1;
Scan2 = list_Cdr(List1);
while (!list_Empty(Scan2)) {
if (list_Member(List2, list_Car(Scan2), Test)) {
Scan2 = list_Cdr(Scan2);
Scan1 = list_Cdr(Scan1);
}
else {
list_Rplacd(Scan1, list_Cdr(Scan2));
list_Free(Scan2);
Scan2 = list_Cdr(Scan1);
}
}
return List1;
}
LIST list_NPointerIntersect(LIST List1, LIST List2)
/**************************************************************
INPUT: Two lists.
RETURNS: Regarding both lists as sets, the intersection of the sets.
CAUTION: Destructive on List1
***************************************************************/
{
LIST Scan1, Scan2;
while (!list_Empty(List1) && !list_PointerMember(List2, list_Car(List1))) {
Scan1 = list_Cdr(List1);
list_Free(List1);
List1 = Scan1;
}
if (list_Empty(List1))
return List1;
Scan1 = List1;
Scan2 = list_Cdr(List1);
while (!list_Empty(Scan2)) {
if (list_PointerMember(List2, list_Car(Scan2))) {
Scan2 = list_Cdr(Scan2);
Scan1 = list_Cdr(Scan1);
}
else {
list_Rplacd(Scan1, list_Cdr(Scan2));
list_Free(Scan2);
Scan2 = list_Cdr(Scan1);
}
}
return List1;
}
void list_NInsert(LIST List1, LIST List2)
/**************************************************************
INPUT: Two lists where <List1> must not be empty.
EFFECT: <List2> is destructively concatenated after
the first element of <List1>.
RETURNS: void.
CAUTION: Destructive on List1 and List2.
***************************************************************/
{
LIST Help;
#ifdef CHECK
if (list_Empty(List1)) {
misc_StartErrorReport();
misc_ErrorReport("\n In list_NInsert: Empty list argument.");
misc_FinishErrorReport();
}
#endif
Help = list_Cdr(List1);
list_Rplacd(List1,List2);
List2 = List1;
while (!list_Empty(list_Cdr(List2)))
List2 = list_Cdr(List2);
list_Rplacd(List2,Help);
}
BOOL list_HasIntersection(LIST List1, LIST List2)
/**************************************************************
INPUT: Two lists .
RETURNS: TRUE iff List1 and List2 have a common element.
EFFECT: The function needs time O(n*m), where n and m are the
lengths of the lists.
***************************************************************/
{
LIST Scan;
if (!list_Empty(List2)) {
for (Scan=List1; !list_Empty(Scan); Scan=list_Cdr(Scan))
if (list_PointerMember(List2, list_Car(Scan)))
return TRUE;
}
return FALSE;
}
LIST list_NPointerDifference(LIST List1, LIST List2)
/**************************************************************
INPUT: Two lists.
RETURNS: The list List1-List2.
CAUTION: Destructive on List1.
***************************************************************/
{
LIST Scan;
if (!list_Empty(List1)) {
for (Scan=List2; !list_Empty(Scan); Scan=list_Cdr(Scan))
List1 = list_PointerDeleteElement(List1, list_Car(Scan));
}
return List1;
}
LIST list_NDifference(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: Two lists and an equality test for elements.
RETURNS: The list List1-List2 wrt. <Test>.
CAUTION: Destructive on List1.
***************************************************************/
{
LIST Scan;
if (!list_Empty(List1)) {
for (Scan=List2; !list_Empty(Scan); Scan=list_Cdr(Scan))
List1 = list_DeleteElement(List1, list_Car(Scan), Test);
}
return List1;
}
LIST list_NMultisetDifference(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER))
/**************************************************************
INPUT: Two lists representing multisets and an equality
test for elements.
RETURNS: The multiset difference List1-List2 wrt. <Test>.
CAUTION: Destructive on List1. The memory of deleted
elements is not freed.
***************************************************************/
{
LIST scan;
/* Delete equal arguments */
if (!list_Empty(List1)) {
for (scan = List2; !list_Empty(scan); scan = list_Cdr(scan))
/* Delete at most one element from List1 equal to */
/* the actual element of List2. */
List1 = list_DeleteOneElement(List1, list_Car(scan), Test);
}
return List1;
}
BOOL list_PointerReplaceMember(LIST List, POINTER Old, POINTER New)
/**************************************************************
INPUT: A list, a pointer to an old element, a pointer to a new element
RETURNS: TRUE iff <Old> was replaced.
EFFECT: The first occurrence of <Old> in the list is replaced by <New>.
***************************************************************/
{
while (!list_Empty(List)) {
if (Old == list_Car(List)) {
list_Rplaca(List, New);
return TRUE;
}
List = list_Cdr(List);
}
return FALSE;
}
void list_DeleteAssocListWithValues(LIST List, void (*ValueDelete)(POINTER))
/**************************************************************
INPUT: An association list and a delete function for the values.
RETURNS: void.
EFFECT: The assoc list and its values are deleted.
***************************************************************/
{
LIST Scan;
for (Scan=List;!list_Empty(Scan);Scan = list_Cdr(Scan)) {
ValueDelete(list_PairSecond(list_Car(Scan)));
list_PairFree(list_Car(Scan));
}
list_Delete(List);
}
POINTER list_AssocListValue(LIST List, POINTER Key)
/**************************************************************
INPUT: An association list and a key.
RETURNS: The value for <key> in the list. If <key> is not
contained, NULL.
***************************************************************/
{
LIST Scan;
for (Scan=List;!list_Empty(Scan);Scan = list_Cdr(Scan))
if (Key == list_PairFirst(list_Car(Scan)))
return list_PairSecond(list_Car(Scan));
return NULL;
}
LIST list_AssocListPair(LIST List, POINTER Key)
/**************************************************************
INPUT: An association list and a key.
RETURNS: The (<key>.<value) in the list. If <key> is not
contained, the NULL pair.
***************************************************************/
{
LIST Scan;
for (Scan=List;!list_Empty(Scan);Scan = list_Cdr(Scan))
if (Key == list_PairFirst(list_Car(Scan)))
return list_Car(Scan);
return list_PairNull();
}
LIST list_MultisetDistribution(LIST Multiset)
/**************************************************************
INPUT: A list representing a multiset.
RETURNS: The associative list of pairs (<element>.<occurrences>)
representing the distribution of elements in the list.
If the input multiset is empty, the NULL pair.
***************************************************************/
{
LIST Distribution;
LIST Scan;
Distribution = list_PairNull();
for (Scan = Multiset; !list_Empty(Scan); Scan = list_Cdr(Scan)) {
LIST Count;
POINTER Element;
int Occurences;
Element = list_Car(Scan);
Count = list_AssocListPair(Distribution, Element);
if (Count != list_PairNull()) {
Occurences = (int) list_PairSecond(Count);
list_PairRplacSecond(Count, (POINTER) (Occurences + 1));
}
else {
Distribution = list_AssocCons(Distribution, Element, (POINTER) 1);
}
}
return Distribution;
}
int list_CompareElementDistribution(LIST LeftPair, LIST RightPair)
/**************************************************************
INPUT: Two lists, representing single element frequency
counts.
RETURNS: 1 if left > right, -1 if left < right, 0 otherwise.
EFFECT: Compares two element frequencies.
***************************************************************/
{
if ((int) list_PairSecond(LeftPair) < (int) list_PairSecond(RightPair)) {
return -1;
}
else if ((int) list_PairSecond(LeftPair) > (int) list_PairSecond(RightPair)) {
return 1;
}
return 0;
}
BOOL list_CompareElementDistributionLEQ(LIST LeftPair, LIST RightPair) {
/**************************************************************
INPUT: Two lists, representing single element frequency
counts.
RETURNS: TRUE if left <= right, FALSE otherwise.
EFFECT: Compares two element frequencies.
***************************************************************/
return (list_CompareElementDistribution(LeftPair, RightPair) <= 0);
}
static int list_CompareDistributions(LIST Left, LIST Right)
/**************************************************************
INPUT: Two lists, representing element distributions.
RETURNS: 1 if left > right, -1 if left < right, 0 otherwise.
EFFECT: Compares the two distributions by comparing the
element frequencies from left to right.
CAUTION: Expects the distributions to be sorted.
***************************************************************/
{
LIST scan, scan2;
int result;
result = 0;
scan = Left;
scan2 = Right;
/* Compare distributions. */
while ( !(list_Empty(scan) || list_Empty(scan2))) {
result = list_CompareElementDistribution(list_Car(scan), list_Car(scan2));
if (result != 0) {
break;
}
scan = list_Cdr(scan);
scan2 = list_Cdr(scan2);
}
/* If the result is 0, and a distribution still
has elements left, it is declared to be greater.
*/
if (result == 0) {
if (list_Empty(scan) && !list_Empty(scan2))
result = -1;
else if (!list_Empty(scan) && list_Empty(scan2))
result = 1;
}
return result;
}
int list_CompareMultisetsByElementDistribution(LIST Left, LIST Right)
/**************************************************************
INPUT: Two lists, representing multisets.
RETURNS: 1 if left > right, -1 if left < right, 0 otherwise.
EFFECT: Compares two multisets by counting their element
frequencies, sorting them, and comparing the
resulting multisets over natural numbers.
***************************************************************/
{
LIST lmsd, rmsd; /* multiset distributions. */
int result;
/* Convert multiset of elements into a
multiset of pairs (element, occurrences).
*/
lmsd = list_MultisetDistribution(Left);
rmsd = list_MultisetDistribution(Right);
/* Sort multiset distributions in order
to make them comparable.
*/
lmsd = list_Sort(lmsd, (BOOL (*) (POINTER, POINTER)) list_CompareElementDistributionLEQ);
rmsd = list_Sort(rmsd, (BOOL (*) (POINTER, POINTER)) list_CompareElementDistributionLEQ);
result = list_CompareDistributions(lmsd, rmsd);
list_DeleteDistribution(lmsd);
list_DeleteDistribution(rmsd);
return result;
}
NAT list_Length(LIST List)
/**************************************************************
INPUT: A List.
RETURNS: The number of elements..
EFFECT: The function needs time O(n), where <n> is the length
of the list.
***************************************************************/
{
NAT Result;
Result = 0;
while (!list_Empty(List)) {
Result++;
List = list_Cdr(List);
}
return Result;
}
NAT list_Bytes(LIST List)
/**************************************************************
INPUT: A List.
RETURNS: The number of Bytes occupied by the list structure of <List>
EFFECT: the function needs time O(n), where <n> is the length
of the list.
***************************************************************/
{
return (list_Length(List)*sizeof(LIST_NODE));
}