varch/doc/sList.en.md

487 lines
12 KiB
Markdown

### Introduction
A linked list is a data structure where data elements are logically consecutive but can be physically stored in a dispersed manner. It can link multiple data blocks of the same type into a complete sequence through pointers and plays an important role in the implementation of data structures.
The sList module is a general-purpose single-linked list module. It stores a linear data collection through a series of interconnected nodes. Each node contains a data field and a pointer field that points to the next node.
### Interface
#### Creating sList
```c
sList *sList_create(void);
```
In sList, sList is both a linked list and a node (because a node can be regarded as a linked list with a length of 1). So this method creates an empty linked list with a length of 1 (that is, creates an empty node).
#### Deleting sList
```c
void sList_delete(sList *list);
```
This method will delete the linked list (including all its nodes).
#### Setting and Getting sList Node Contents
```c
int sList_set(sList *list, void* data, int size);
int sList_get(sList *list, void* data, int size);
```
After a node is created, its data field is initially empty. The `sList_set` method is needed to set the content of its data field, and the `sList_get` method can be used to obtain the content of the node's data field. The `sList_set` method will overwrite the original data, and it can also be used to delete the data content of the sList node by specifying the `size` as **0**.
```c
static void test_set(void)
{
sList *list = NULL;
int dataInt = 3;
char *dataString = "Hello sList";
char outBuffer[32];
list = sList_create();
if (!list)
{
printf("sList_create Fail!\r\n");
return;
}
printf("sList_create Success!\r\n");
sList_set(list, &dataInt, sizeof(dataInt));
printf("list->data %d\r\n", sList_ref(list, int));
sList_set(list, dataString, strlen(dataString) + 1);
printf("list->data %s\r\n", ((char *)(list->data)));
sList_get(list, outBuffer, sizeof(outBuffer));
printf("get data %s\r\n", outBuffer);
sList_delete(list);
}
```
**Results**:
```
sList_create Success!
list->data 3
list->data Hello sList
get data Hello sList
```
The `sList_ref` in the example is for data reference, and its specific usage will be introduced later.
#### sList Inserting Data
```c
sList *sList_insert(sList **listRef, int index, void *data, int size);
```
The data insertion method is more convenient to use as it saves the steps of creating nodes and setting data (even for the head of the linked list, the creation can be omitted and completed internally by this method), and it can flexibly insert specified data into specified positions.
```c
static void test_insert(void)
{
sList *list = NULL;
for (int i = 0; i < 5; i++)
{
if (!sList_insert(&list, -1, &i, sizeof(i))) goto FAIL;
}
sList_forEach(list, n)
{
printf("data %d\r\n", sList_ref(n, int));
}
FAIL:
sList_delete(list);
}
```
**Results**:
```
data 0
data 1
data 2
data 3
data 4
```
The `sList_forEach` in the example is for traversing the linked list, and its specific usage will be introduced later. When the passed-in sList reference is NULL, the method will create a node and generate the head of the list for the first time. Passing in a negative `index` means inserting at the tail. The predefined `sList_front` and `sList_back` macro definitions can be used to represent the head and tail respectively.
#### sList Erasing Data
```c
int sList_erase(sList **listRef, int index, sList **outPrev);
```
This method is the counterpart of the `sList_insert` method. It erases the data at the specified position (removes the node from the linked list). Meanwhile, for more flexible use, it also supports obtaining the previous node of the erased one (which can make consecutive erasing more convenient and efficient).
```c
static void test_erase(void)
{
sList *list = NULL;
for (int i = 0; i < 5; i++)
{
if (!sList_insert(&list, -1, &i, sizeof(i))) goto FAIL;
}
sList_erase(&list, 0, NULL);
sList_forEach(list, n)
{
printf("data %d\r\n", sList_ref(n, int));
}
FAIL:
sList_delete(list);
}
```
**Results**:
```
data 1
data 2
data 3
data 4
```
Compared with the previous insertion example, the head of the list is erased here.
#### sList Pushing and Popping
```c
int sList_pushFront(sList **listRef, void *data, int size);
int sList_pushBack(sList **listRef, void *data, int size);
int sList_popFront(sList **listRef);
int sList_popBack(sList **listRef);
```
These are respectively the methods for inserting at the head, inserting at the tail, deleting from the head, and deleting from the tail. In fact, they are encapsulations based on the `sList_insert` and `sList_erase` methods for common usage scenarios, making them easier to use.
```c
static void test_pop(void)
{
sList *list = NULL;
for (int i = 0; i < 5; i++)
{
if (!sList_pushFront(&list, &i, sizeof(i))) goto FAIL;
}
for (int i = 0; i < 5; i++)
{
if (!sList_pushBack(&list, &i, sizeof(i))) goto FAIL;
}
sList_popBack(&list);
sList_popBack(&list);
sList_popFront(&list);
sList_forEach(list, n)
{
printf("data %d\r\n", sList_ref(n, int));
}
FAIL:
sList_delete(list);
}
```
**Results**:
```
data 3
data 2
data 1
data 0
data 0
data 1
data 2
```
#### sList Appending
```c
int sList_append(sList *list, sList **append);
```
This method can concatenate two linked lists into one. The `append` linked list will become invalid after the concatenation is successful.
**Note**: The `append` should be the head of the list. Although it can still be concatenated successfully even if it's not the head, it still belongs to the original linked list, and some unexpected situations may occur during operations.
```c
static void test_append(void)
{
sList *list = NULL, *ap = NULL;
for (int i = 0; i < 10; i++)
{
if (!sList_pushBack(&list, &i, sizeof(i))) goto FAIL;
if (!sList_pushBack(&ap, &i, sizeof(i))) goto FAIL;
}
if (!sList_append(list, &ap)) goto FAIL;
printPoint(ap);
sList_forEach(list, n)
{
printf("data %d\r\n", sList_ref(n, int));
}
FAIL:
sList_delete(list);
sList_delete(ap);
}
```
**Results**:
```
data 0
data 1
data 2
data 3
data 4
data 5
data 6
data 7
data 8
data 9
data 0
data 1
data 2
data 3
data 4
data 5
data 6
data 7
data 8
data 9
```
#### sList Linking Nodes
```c
sList *sList_attach(sList **listRef, int index, sList *attach);
```
This method links a node (or a linked list) to an existing linked list, and the specific position to link can be specified by the `index`. This method is very flexible and directly operates on the linked list structure. **Generally, this method is not commonly used**, and instead, the encapsulated methods like `sList_insert` are usually used. This method can be combined with other methods to be flexibly re-encapsulated into other methods.
```c
static void test_attach(void)
{
sList *list = NULL, *a = NULL;
for (int i = 0; i < 5; i++)
{
if (!sList_pushBack(&list, &i, sizeof(i))) goto FAIL;
}
for (int i = 0; i < 3; i++)
{
if (!sList_pushBack(&a, &i, sizeof(i))) goto FAIL;
}
sList_attach(&list, -1, a);
sList_forEach(list, n)
{
printf("data %d\r\n", sList_ref(n, int));
}
FAIL:
sList_delete(list);
}
```
**Results**:
```
data 0
data 1
data 2
data 3
data 4
data 0
data 1
data 2
```
#### sList Detaching Nodes
```c
sList *sList_detach(sList **listRef, int index, int count, sList **outPrev);
```
This method is the counterpart of the `sList_attach` method. It can detach several nodes (a sub-linked list) from the linked list. The specific position and the number of nodes to detach can be specified by the `index` and `count` respectively. This method is very flexible and directly operates on the linked list structure. **Generally, this method is not commonly used**, and instead, the encapsulated methods like `sList_erase` are usually used. This method can be combined with other methods to be flexibly re-encapsulated into other methods.
```c
static void test_detach(void)
{
sList *list = NULL, *node;
for (int i = 0; i < 10; i++)
{
if (!sList_insert(&list, -1, &i, sizeof(i))) goto FAIL;
}
node = sList_detach(&list, 3, -1, NULL);
if (!node)
{
printf("sList_detach fail\r\n");
}
sList_forEach(node, n)
{
printf("node data %d\r\n", sList_ref(n, int));
}
sList_delete(node);
sList_forEach(list, n)
{
printf("data %d\r\n", sList_ref(n, int));
}
FAIL:
sList_delete(list);
}
```
**Results**:
```
node data 3
node data 4
node data 5
node data 6
node data 7
node data 8
node data 9
data 0
data 1
data 2
```
#### sList Copying
```c
sList *sList_copy(sList *list, int begin, int end);
```
This method will make a deep copy of a new linked list according to the specified interval of the source linked list.
```c
static void test_copy(void)
{
sList *list = NULL, *copy = NULL;
for (int i = 0; i < 10; i++)
{
if (!sList_pushBack(&list, &i, sizeof(i))) goto FAIL;
}
copy = sList_copy(list, 2, -1);
if (!copy)
{
printf("sList_copy fail\r\n");
}
sList_forEach(copy, n)
{
printf("data %d\r\n", sList_ref(n, int));
}
FAIL:
sList_delete(list);
sList_delete(copy);
}
```
**Results**:
```
data 2
data 3
data 4
data 5
data 6
data 7
data 8
data 9
```
#### sList Reversing an Interval
```c
int sList_reverse(sList *list, int begin, int end);
```
This method will reverse the specified interval of the source linked list.
```c
static void test_reverse(void)
{
sList *list = NULL;
for (int i = 0; i < 10; i++)
{
if (!sList_pushBack(&list, &i, sizeof(i))) goto FAIL;
}
if (!sList_reverse(list, sList_front, sList_back))
{
printf("sList_reverse fail\r\n");
}
sList_forEach(list, n)
{
printf("data %d\r\n", sList_ref(n, int));
}
FAIL:
sList_delete(list);
}
```
**Results**:
```
data 9
data 8
data 7
data 6
data 5
data 4
data 3
data 2
data 1
data 0
```
#### sList Getting a Specified Node
```c
sList *sList_to(sList *list, int index);
```
This method can obtain the node with a specified offset from the current position of the head node.
```c
static void test_to(void)
{
sList *list = NULL, *node;
for (int i = 0; i < 10; i++)
{
if (!sList_pushBack(&list, &i, sizeof(i))) goto FAIL;
}
node = sList_to(list, 6);
if (!node)
{
printf("sList_to fail\r\n");
goto FAIL;
}
printf("data %d\r\n", sList_ref(node, int));
FAIL:
sList_delete(list);
}
```
**Results**:
```
data 6
```
#### sList Size
```c
int sList_size(sList *list);
```
This method is used to obtain the number of data elements in the linked list.
```c
static void test_size(void)
{
sList *list = NULL;
for (int i = 0; i < 10; i++)
{
if (!sList_pushBack(&list, &i, sizeof(i))) goto FAIL;
}
printf("size %d\r\n", sList_size(list));
printf("size %d\r\n", sList_size(sList_to(list, 3)));
FAIL:
sList_delete(list);
}
```
**Results**:
```
size 10
size 7
```
#### sList Traversing
```c
#define sList_forEach(list, node)
```
This method is for traversing the linked list. Specific examples can be referred to in the above usage examples.
#### sList Node Data Reference
```c
#define sList_ref(node, type)
```
This method is similar to the reference in C++. In fact, it operates on pointers (but hides them), making reading and writing more convenient. However, it should be noted that data operations should not exceed the bounds. For example, if a node originally stores `char`-type data (and only 1 byte of space is allocated), using it as `int`-type data would cause an out-of-bounds situation. Specific examples can be referred to in the above usage examples.