/**************************************************************/ /* ********************************************************** */ /* * * */ /* * 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: 21527 $ * */ /* $State$ * */ /* $Date: 2005-04-24 21:10:28 -0700 (Sun, 24 Apr 2005) $ * */ /* $Author: duraid $ * */ /* * * */ /* * 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 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 is the length of the list and 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 to the elements CAUTION: The List is not copied ! The function needs time O(n*f), where is the length of the list and 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 is the length of the list and 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 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 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 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 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 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. and point to the resulting halves. The input list is destructively changed! If the list length is odd, is assigned the bigger part. The function needs time O(n), where 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 is the length of the input list and 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 is the length of the list and 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 is the length of the list and 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 is the length of the list and is the time for a call of the 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 is the length of the list and is the time for a call of the 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 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 is the length of the list and 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 is the length of the list and 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 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 on it succeeds. The element is deleted with . 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 with respect to , 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 if the Test between 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 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 contains with respect to pointer equality, is deleted from . This function needs time O(n), where 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 was deleted; FALSE, otherwise. EFFECTS: If contains with respect to pointer equality, the first occurrence of is deleted from . 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 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 must not be empty. EFFECT: is destructively concatenated after the first element of . 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. . 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. . 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 was replaced. EFFECT: The first occurrence of in the list is replaced by . ***************************************************************/ { 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 in the list. If 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 (. 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 (.) 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 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 EFFECT: the function needs time O(n), where is the length of the list. ***************************************************************/ { return (list_Length(List)*sizeof(LIST_NODE)); }