mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-06 08:46:42 +08:00
463 lines
11 KiB
C
463 lines
11 KiB
C
/*********************************************************************************************************
|
|
* ------------------------------------------------------------------------------------------------------
|
|
* file description
|
|
* ------------------------------------------------------------------------------------------------------
|
|
* \file dList.c
|
|
* \unit dList
|
|
* \brief This is a C language doubly linked list
|
|
* \author Lamdonn
|
|
* \version v1.0.0
|
|
* \license GPL-2.0
|
|
* \copyright Copyright (C) 2023 Lamdonn.
|
|
********************************************************************************************************/
|
|
#include "dList.h"
|
|
#include <string.h>
|
|
|
|
dList *dList_create(void)
|
|
{
|
|
dList *list;
|
|
|
|
/* Allocate memory for the dList structure */
|
|
list = (dList *)malloc(sizeof(dList));
|
|
if (!list) return NULL;
|
|
|
|
/* Initialize structural parameters */
|
|
list->next = list;
|
|
list->prev = list;
|
|
list->data = NULL;
|
|
list->size = 0;
|
|
|
|
return list;
|
|
}
|
|
|
|
void dList_delete(dList *list)
|
|
{
|
|
dList *temp = NULL;
|
|
|
|
if (!list) return;
|
|
|
|
temp = list->prev;
|
|
temp->next = NULL;
|
|
|
|
while (list)
|
|
{
|
|
/* Save the next pointer before freeing the current node */
|
|
temp = list->next;
|
|
|
|
/* Free the data associated with the current node */
|
|
if (list->data) free(list->data);
|
|
|
|
/* Free the memory allocated for the current node */
|
|
free(list);
|
|
|
|
/* Move to the next node in the list */
|
|
list = temp;
|
|
}
|
|
}
|
|
|
|
dList *dList_attach(dList **listRef, int index, dList *attach)
|
|
{
|
|
dList *list, *temp;
|
|
|
|
/* Input value validity check */
|
|
if (!listRef) return NULL;
|
|
if (!(list = *listRef)) return NULL;
|
|
if (!attach) return NULL;
|
|
|
|
if (list->next == list)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
*listRef = attach;
|
|
case 1:
|
|
case -1:
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (index > 0)
|
|
{
|
|
/* Iterative movement to obtain the prev node to be inserted at the location */
|
|
while ((--index) && (list->next != *listRef))
|
|
{
|
|
list = list->next;
|
|
}
|
|
|
|
/* Return NULL if the index is out of bounds */
|
|
if (index > 0) return NULL;
|
|
}
|
|
else if (index < 0)
|
|
{
|
|
/* Iterative movement to obtain the prev node to be inserted at the location */
|
|
while ((++index) && (list->prev != *listRef))
|
|
{
|
|
list = list->prev;
|
|
}
|
|
list = list->prev;
|
|
|
|
/* Return NULL if the index is out of bounds */
|
|
if (index < 0) return NULL;
|
|
}
|
|
else
|
|
{
|
|
list = list->prev;
|
|
*listRef = attach;
|
|
}
|
|
}
|
|
|
|
temp = attach->prev;
|
|
|
|
temp->next = list->next;
|
|
list->next->prev = temp;
|
|
|
|
list->next = attach;
|
|
attach->prev = list;
|
|
|
|
return attach;
|
|
}
|
|
|
|
static int dList_locate2(dList *list, int begin, int end, dList **beginNodeRef, dList **endNodeRef)
|
|
{
|
|
dList *beginNode = NULL, *endNode = NULL;
|
|
|
|
if (begin >= 0)
|
|
{
|
|
/* Move to the position in the original list where the sublist should be attached */
|
|
beginNode = dList_to(list, begin);
|
|
if (!beginNode) return 0;
|
|
|
|
/* Forward positioning of end node */
|
|
if (end > 0)
|
|
{
|
|
/* Ensure the correctness of the start and end positions */
|
|
if (end < begin) return 0;
|
|
|
|
/* Starting from the begin node, iteratively move to the specified position node */
|
|
endNode = beginNode;
|
|
while ((begin < end) && (endNode->next != list))
|
|
{
|
|
endNode = endNode->next;
|
|
begin++;
|
|
}
|
|
|
|
/* Return NULL if the index is out of bounds */
|
|
if (begin != end) return 0;
|
|
}
|
|
else
|
|
{
|
|
/* Iterative movement to obtain the prev node to be inserted at the location */
|
|
endNode = list->prev;
|
|
while ((++end) && (endNode != beginNode))
|
|
{
|
|
endNode = endNode->prev;
|
|
}
|
|
|
|
/* Return NULL if the index is out of bounds */
|
|
if (end < 0) return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Starting from the beginning in reverse, it is not allowed to position the end from the forward direction */
|
|
if (end > 0) return 0;
|
|
|
|
/* Ensure the correctness of the start and end positions */
|
|
if (end < begin) return 0;
|
|
|
|
/* Move to the position in the original list where the sublist should be attached */
|
|
endNode = dList_to(list, end);
|
|
if (!endNode) return 0;
|
|
|
|
/* Starting from the end node, iteratively move to the specified position node */
|
|
beginNode = endNode;
|
|
begin -= (end + 1);
|
|
while ((++begin) && (beginNode != list))
|
|
{
|
|
beginNode = beginNode->prev;
|
|
}
|
|
|
|
/* Return NULL if the index is out of bounds */
|
|
if (begin < 0) return 0;
|
|
}
|
|
|
|
*beginNodeRef = beginNode;
|
|
*endNodeRef = endNode;
|
|
|
|
return 1;
|
|
}
|
|
|
|
dList *dList_detach(dList **listRef, int begin, int end, dList **outPrev)
|
|
{
|
|
dList *list, *detach = NULL, *prev = NULL, *beginNode = NULL, *endNode = NULL;
|
|
|
|
/* Input value validity check */
|
|
if (!listRef) return 0;
|
|
if (!(list = *listRef)) return 0;
|
|
|
|
if (!dList_locate2(list, begin, end, &beginNode, &endNode)) return NULL;
|
|
|
|
/* Update the head of the list to point to the node following the detached sublist */
|
|
if (beginNode == *listRef) *listRef = endNode->next;
|
|
|
|
prev = beginNode->prev;
|
|
|
|
/* Adjusting the orientation of two circular doubly linked lists */
|
|
prev->next = endNode->next;
|
|
endNode->next->prev = prev;
|
|
|
|
beginNode->prev = endNode;
|
|
endNode->next = beginNode;
|
|
|
|
detach = beginNode;
|
|
|
|
/* Store the pointer to the previous node of the detached sublist */
|
|
if (outPrev) *outPrev = prev;
|
|
|
|
return detach;
|
|
}
|
|
|
|
dList *dList_insert(dList **listRef, int index, void *data, int size)
|
|
{
|
|
dList *node;
|
|
|
|
/* Input value validity check */
|
|
if (!listRef) return NULL;
|
|
|
|
/* Create a new node */
|
|
node = dList_create();
|
|
if (!node) return NULL;
|
|
|
|
/* Set the data for the new node */
|
|
if (!dList_set(node, data, size)) goto FAIL;
|
|
|
|
/* Insert the new node at the specified position */
|
|
if (!*listRef)
|
|
{
|
|
if (index == 0 || index == -1) *listRef = node;
|
|
else goto FAIL;
|
|
}
|
|
else
|
|
{
|
|
/* Jump to the failure label if attaching the new node fails */
|
|
if (!dList_attach(listRef, index, node)) goto FAIL;
|
|
}
|
|
|
|
return node;
|
|
|
|
FAIL:
|
|
/* Delete the new node in case of failure */
|
|
dList_delete(node);
|
|
return NULL;
|
|
}
|
|
|
|
int dList_erase(dList **listRef, int index, dList **outPrev)
|
|
{
|
|
dList *node;
|
|
|
|
/* Detach the node at the specified position */
|
|
node = dList_detach(listRef, index, index, outPrev);
|
|
if (!node) return 0;
|
|
|
|
/* Delete the detached node */
|
|
dList_delete(node);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int dList_pushFront(dList **listRef, void *data, int size)
|
|
{
|
|
return dList_insert(listRef, 0, data, size) ? 1 : 0;
|
|
}
|
|
|
|
int dList_pushBack(dList **listRef, void *data, int size)
|
|
{
|
|
return dList_insert(listRef, -1, data, size) ? 1 : 0;
|
|
}
|
|
|
|
int dList_popFront(dList **listRef)
|
|
{
|
|
return dList_erase(listRef, 0, NULL);
|
|
}
|
|
|
|
int dList_popBack(dList **listRef)
|
|
{
|
|
return dList_erase(listRef, -1, NULL);
|
|
}
|
|
|
|
int dList_append(dList *list, dList **append)
|
|
{
|
|
dList *prev;
|
|
|
|
/* Input value validity check */
|
|
if (!list) return 0;
|
|
if (!append || !*append) return 0;
|
|
|
|
/* Move to the last node of the list */
|
|
prev = list->prev;
|
|
|
|
/* Connect the last node of the list to the head of the sublist */
|
|
(*append)->prev->next = list;
|
|
list->prev = (*append)->prev;
|
|
|
|
prev->next = (*append);
|
|
(*append)->prev = prev;
|
|
|
|
/* Update the sublist pointer to NULL */
|
|
*append = NULL;
|
|
|
|
return 1;
|
|
}
|
|
|
|
dList *dList_copy(dList *list, int begin, int end)
|
|
{
|
|
dList *copy = NULL, *node = NULL, *beginNode = NULL, *endNode = NULL;
|
|
|
|
if (!dList_locate2(list, begin, end, &beginNode, &endNode)) return NULL;
|
|
|
|
if (!dList_pushBack(©, beginNode->data, beginNode->size)) goto FAIL;
|
|
|
|
for (node = beginNode->next; node != endNode->next; node = node->next)
|
|
{
|
|
/* Jump to the failure label if inserting a node fails */
|
|
if (!dList_pushBack(©, node->data, node->size)) goto FAIL;
|
|
}
|
|
|
|
return copy;
|
|
|
|
FAIL:
|
|
/* Delete the copied sublist in case of failure */
|
|
dList_delete(copy);
|
|
return NULL;
|
|
}
|
|
|
|
int dList_reverse(dList *list, int begin, int end)
|
|
{
|
|
dList *beginNode = NULL, *endNode = NULL;
|
|
void *data;
|
|
int s;
|
|
|
|
/* Input value validity check */
|
|
if (!list) return 0;
|
|
|
|
if (begin == end) return 0;
|
|
|
|
if (!dList_locate2(list, begin, end, &beginNode, &endNode)) return 0;
|
|
|
|
/* Traverse the specified interval in the list for reversing */
|
|
for ( ; (beginNode->next != endNode) && (beginNode->next != endNode->prev); beginNode = beginNode->next, endNode = endNode->prev)
|
|
{
|
|
/* Swap the data and size between the current node and the corresponding node at the end position */
|
|
data = beginNode->data;
|
|
beginNode->data = endNode->data;
|
|
endNode->data = data;
|
|
|
|
s = beginNode->size;
|
|
beginNode->size = endNode->size;
|
|
endNode->size = s;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int dList_size(dList *list)
|
|
{
|
|
dList* node;
|
|
int size = 0;
|
|
|
|
/* Input value validity check */
|
|
if (!list) return 0;
|
|
|
|
for (node = list; node; node = ((node->next == list) ? NULL : node->next))
|
|
{
|
|
/* Increment the size counter */
|
|
size++;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
dList *dList_to(dList *list, int index)
|
|
{
|
|
dList *node = list;
|
|
|
|
/* Input value validity check */
|
|
if (!list) return NULL;
|
|
|
|
if (index > 0)
|
|
{
|
|
/* Iterative movement to obtain the prev node to be inserted at the location */
|
|
while ((index--) && (node->next != list))
|
|
{
|
|
node = node->next;
|
|
}
|
|
|
|
/* Return NULL if the index is out of bounds */
|
|
if (index >= 0) return NULL;
|
|
}
|
|
else if (index < 0)
|
|
{
|
|
/* Iterative movement to obtain the prev node to be inserted at the location */
|
|
node = node->prev;
|
|
while ((++index) && (node != list))
|
|
{
|
|
node = node->prev;
|
|
}
|
|
|
|
/* Return NULL if the index is out of bounds */
|
|
if (index < 0) return NULL;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
int dList_set(dList *list, void* data, int size)
|
|
{
|
|
void* d = NULL;
|
|
|
|
/* Input value validity check */
|
|
if (!list) return 0;
|
|
if (size < 0) return 0;
|
|
|
|
/* If the incoming data size is 0, set the air sensitive data directly */
|
|
if (size == 0)
|
|
{
|
|
if (list->data) free(list->data);
|
|
list->data = NULL;
|
|
list->size = 0;
|
|
return 1;
|
|
}
|
|
|
|
/* If the data size is inconsistent, update the data storage space */
|
|
if (size != list->size)
|
|
{
|
|
d = realloc(list->data, size);
|
|
if (!d) return 0;
|
|
}
|
|
list->data = d;
|
|
|
|
/* Data assignment */
|
|
if (data) memcpy(list->data, data, size);
|
|
|
|
/* Update data size */
|
|
list->size = size;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int dList_get(dList *list, void* data, int size)
|
|
{
|
|
/* Input value validity check */
|
|
if (!list) return 0;
|
|
if (!data) return 0;
|
|
if (size < list->size) return 0;
|
|
|
|
/* Data assignment */
|
|
memcpy(data, list->data, list->size);
|
|
|
|
return 1;
|
|
}
|