From 864ffd4973e85b563ade91e4970b896529ea99f3 Mon Sep 17 00:00:00 2001 From: Peter Wehrfritz Date: Mon, 12 Feb 2007 22:47:46 +0000 Subject: [PATCH] add ecore_dlist_sort() and ecore_dlist_mergesort() SVN revision: 28330 --- legacy/ecore/src/lib/ecore/Ecore_Data.h | 8 ++ legacy/ecore/src/lib/ecore/ecore_list.c | 169 ++++++++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/legacy/ecore/src/lib/ecore/Ecore_Data.h b/legacy/ecore/src/lib/ecore/Ecore_Data.h index 92cf6ed595..88adfffc3a 100644 --- a/legacy/ecore/src/lib/ecore/Ecore_Data.h +++ b/legacy/ecore/src/lib/ecore/Ecore_Data.h @@ -192,6 +192,14 @@ extern "C" { EAPI void *ecore_dlist_next(Ecore_DList * list); EAPI void *ecore_dlist_previous(Ecore_DList * list); + /* Sorting the list */ + EAPI int ecore_dlist_sort(Ecore_DList *list, Ecore_Compare_Cb compare, + char order); + EAPI int ecore_dlist_mergesort(Ecore_DList *list, Ecore_Compare_Cb compare, + char order); +# define ecore_dlist_heapsort(list, compare, order) \ + ecore_list_heapsort(list, compare, order) + /* Check to see if there is any data in the list */ EAPI int ecore_dlist_is_empty(Ecore_DList * _e_dlist); diff --git a/legacy/ecore/src/lib/ecore/ecore_list.c b/legacy/ecore/src/lib/ecore/ecore_list.c index 97a1e12b9b..f137cfb4f7 100644 --- a/legacy/ecore/src/lib/ecore/ecore_list.c +++ b/legacy/ecore/src/lib/ecore/ecore_list.c @@ -40,6 +40,12 @@ static Ecore_List_Node *_ecore_list_node_merge(Ecore_List_Node *first, Ecore_List_Node *second, Ecore_Compare_Cb compare, int order); +static Ecore_List_Node *_ecore_dlist_node_mergesort(Ecore_List_Node *first, + int n, Ecore_Compare_Cb compare, int order); +static Ecore_List_Node *_ecore_dlist_node_merge(Ecore_List_Node *first, + Ecore_List_Node *second, + Ecore_Compare_Cb compare, + int order); /* Private double linked list functions */ static void *_ecore_dlist_previous(Ecore_DList * list); @@ -1151,6 +1157,7 @@ ecore_list_sort(Ecore_List *list, Ecore_Compare_Cb compare, char order) return 1; } + /** * Sort data in @p list using the compare function @p compare * @param list The list. @@ -1979,6 +1986,168 @@ ecore_dlist_clear(Ecore_DList *list) return TRUE; } +/** + * Sort data in @p list using the compare function @p compare + * @param list The list. + * @param compare The function to compare the data of @p list + * @param order The sort direction + * + * @return true on success + * + * This is a wrapper function for mergesort and heapsort. It + * tries to choose the fastest algorithm depending on the + * number of notes. Note: The sort may be unstable. + */ +EAPI int +ecore_dlist_sort(Ecore_List *list, Ecore_Compare_Cb compare, char order) +{ + CHECK_PARAM_POINTER_RETURN("list", list, 0); + + if (list->nodes < 2) + return 1; + if (list->nodes < ECORE_MERGESORT_LIMIT) + return ecore_dlist_mergesort(list, compare, order); + if (!ecore_dlist_heapsort(list, compare, order)) + return ecore_dlist_mergesort(list, compare, order); + + return 1; +} + +/** + * Sort data in @p list using the compare function @p compare + * @param list The list. + * @param compare The function to compare the data of @p list + * @param order The sort direction + * + * @return true on success + * + * Mergesort is a stable, in-place sorting algorithm + */ +EAPI int +ecore_dlist_mergesort(Ecore_DList *list, Ecore_Compare_Cb compare, char order) +{ + Ecore_List_Node *node; + + CHECK_PARAM_POINTER_RETURN("list", list, 0); + if (list->nodes < 2) + return 1; + + if (order == ECORE_SORT_MIN) + order = 1; + else + order = -1; + + node = _ecore_dlist_node_mergesort(list->first, list->nodes, compare, order); + list->first = node; + + /* maybe there is a better way to do that but our last node has changed */ + while (node->next) + node = node->next; + list->last = node; + + _ecore_list_goto_first(list); + + return 1; +} + +/* this is the internal recrusive function for the merge sort */ +static Ecore_List_Node * +_ecore_dlist_node_mergesort(Ecore_List_Node *first, int n, + Ecore_Compare_Cb compare, int order) +{ + Ecore_List_Node *middle; + Ecore_List_Node *premid; + int mid; + int i; + + mid = n/2; + + if (n < 2) + return first; + else if (n == 2) + { + if (compare(first->data, first->next->data) * order > 0) + { + /* swap the data */ + void *data; + data = first->next->data; + first->next->data = first->data; + first->data = data; + } + return first; + } + + /* first find the premiddle node*/ + for (premid = first, i = 0; i < mid - 1; i++) + premid = premid->next; + + /* split the list */ + middle = premid->next; + premid->next = NULL; + ECORE_DLIST_NODE(middle)->previous = NULL; + + /* sort the the partial lists */ + first = _ecore_dlist_node_mergesort(first, mid, compare, order); + middle = _ecore_dlist_node_mergesort(middle, n - mid, compare, order); + + return _ecore_dlist_node_merge(first, middle, compare, order); +} + +/* this function is used to merge the partial sorted lists */ +static Ecore_List_Node * +_ecore_dlist_node_merge(Ecore_List_Node *first, Ecore_List_Node *second, + Ecore_Compare_Cb compare, int order) +{ + Ecore_List_Node *list; + Ecore_List_Node *l; + + /* select the first node outside the loop, because we need to keep + * a pointer to it */ + if (compare(first->data, second->data) * order > 0) + { + list = l = second; + second = second->next; + } + else + { + list = l = first; + first = first->next; + } + + /* and now start the merging */ + while (first && second) + { + if (compare(first->data, second->data) * order > 0) + { + ECORE_DLIST_NODE(second)->previous = ECORE_DLIST_NODE(l); + l = l->next = second; + second = second->next; + } + else + { + ECORE_DLIST_NODE(first)->previous = ECORE_DLIST_NODE(l); + l = l->next = first; + first = first->next; + } + } + + /* append the rest or set it to NULL */ + if (first) + { + ECORE_DLIST_NODE(first)->previous = ECORE_DLIST_NODE(l); + l->next = first; + } + else if (second) + { + ECORE_DLIST_NODE(second)->previous = ECORE_DLIST_NODE(l); + l->next = second; + } + else + l->next = NULL; + + return list; +} + /* * @brief Initialize a node to sane starting values * @param node: the node to initialize