# π Write in front

catalogue

π Write in front

π₯ Logical structure

π₯ Storage structure: single linked list

β 1. Create a node · SLN

β 2. Output single linked list (traverse single linked list) · SListPrint

β 3. Dynamically apply for a node · BuySListNode

ππ» How to distinguish between passing a secondary pointer or a primary pointer

β 4. SListPushBack

β 5. Single chain meter insertion · SListPushFront

β 6. Single linked list lookup · slitfind

β 7. Insert (slightly troublesome) · slitinsertfront before specifying the pos position

β 8. Insert SListInsertAfter after specifying the pos position

β 9. SListPopBack

β 10. Header deletion · SListPopBack

π Topic 1

β 11. Delete SListEraseAfter the specified position

β 12. Delete SListEraseFront before the specified position

π Exercise 2. Removing linked list elements

π Conventional method

π Sentinel method

π Exercise 3. Reverse linked list

π Idea 1: directly use three pointers to flip

π Idea 2: head insertion method

π: Before understanding the single chain list of this lesson, let me review the sequence list of last lesson

Defects of sequence table:

1. Dynamic capacity increase with linear consumption
2. With a certain degree of space waste
3. Insert and delete data to be moved

π: The linked list improves these defects of the sequence list

1. Space on demand
2. Inserting and deleting data does not need to move the data, just modify the pointer
3. There is no need to use storage units with continuous addresses - the logical structure and physical structure are inconsistent

π: So in what order should we understand a data structure?

50: Analyze from its logical structure -- > physical structure (storage structure) - > operations performed

π: Boy, I didn't expect that the previous experience of the sequence table made you mature so much at once! The analysis is very comprehensive!

π: Then let's analyze them one by one

# π₯ Logical structure

The logical structure of a single linked list is a linear list, that is, it is a linear structure in logic, that is, a straight line

50: So what does it have to do with the storage structure?

π: As the saying goes, the definition of operation is for the logical structure, and the implementation of operation is for the storage structure

50: How profound! What operation definition and operation implementation??

π: Let's take an example to explain the logical one-to-one relationship:
·Title: arrange a string of six English letters in alphabetical order (c d e a b f)

π: The operation definition is simply: how do you plan to sort these six English letters in your mind? In general, there are only the following four methods:

Β

Β

Β

Obviously, the best choice of arrangement that meets our requirements is linear structure

β¨β¨β¨ I am the dividing line β¨β¨β¨

# π₯ Storage structure: single linked list

Concept: it refers to storing data elements in a linear table through a group of arbitrary storage units. In order to establish the linear relationship between data elements, each linked list node needs to store not only the information of the element itself, but also a pointer to its successor

The node structure of single linked list is shown in the following figure:

Data field: a field that stores data element information

Pointer field: a field that stores the position of a direct successor element

β

Single linked list is to connect the data elements of linear table in logical order by relying on the pointer field of each node

Because it is very simple to use the linked list of the leading node, the more difficult one-way linked list without the leading node is selected as the operation case.

β¨β¨β¨ I am the dividing line β¨β¨β¨

The head pointer is the storage location of the first node in the linked list. The access of the whole linked list starts from the pointer. In fact, each subsequent node is the location pointed by the previous subsequent pointer; the last node points to "NULL" (usually represented by NULL or "^")

The data field of the head node can not store any information, and the pointer field of the head node points to the pointer of the first node

β¨β¨β¨ I am the dividing line β¨β¨β¨

Β

β¨β¨β¨ I am the dividing line β¨β¨β¨

The following is a single linked list of non leading nodes!!! Because if you master the non leading nodes, you can kill the leading nodes casually

# β 1. Create a node · SLN

```typedef int SLDataType;
typedef struct SListNode
{
SLDataType data;//Data field, storing data
struct SListNode* next;//Pointer to the next node
//The type pointed to by the pointer is struct SListNode
}SLN;//Replace this structure with SLN```

Suppose p is a pointer to the ith element of the linear table

```node a(i){

p->data The value of is the node a(i)A data element of

p->next The value of is a pointer, node a(i)The successor node of, pointing to the second node i+1 Two elements, i.e. nodes a(i+1)

}
```

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 2. Output single linked list (traverse single linked list) · SListPrint

Because the elements of a single linked list are discretely distributed in the storage space, a specific node in the table cannot be found directly. When outputting a single linked list, you need to traverse from the header and print out in turn

```void SListPrint(SLN* plist)//Output single linked list
{//The essence is to traverse the single linked list
SLN* cur = plist;//Assign header pointer to cur
while (cur)//Only cur is true will it traverse downward
{
printf("%d->", cur->data);//Output data field
cur = cur->next;//cur points to the next node
}
printf("NULL\n");//The last node points to NULL
}```

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 3. Dynamically apply for a node · BuySListNode

Because subsequent insertion operations need to create a new node, writing a function module can facilitate subsequent calls.

```SLN* BuySListNode(SLDataType x)//Create a new node with data field x
{
SLN* node = (SLN*)malloc(sizeof(SLN));//Apply for a node space of SLN type
node->data = x;
node->next = NULL;
return node; //The return type is a pointer to the SLN structure type
//This pointer points to the new node created
}```

β¨β¨β¨ I am the dividing line β¨β¨β¨

# ππ» How to distinguish between passing a secondary pointer or a primary pointer

1. If you want to change the value of the incoming pointer itself ----- > you need to pass in the secondary pointer

```Change arguments int Value of variable————>pass int*

void swap(int* x, int* y);

int main()
{
int a = 1;
int b = 2;
swap(&a, &b);
}

Relative, change int* Value of variable————>pass int**

void swap(int** x, int** y);

int main()
{
int* a;
int* b;
swap(&a, &b);
}```

2. For headless single linked list. As long as the first node will change (that is, the value of the incoming pointer will change), the secondary pointer needs to be passed

Note: the single linked list of the leading node does not need to pass the secondary pointer, because the leading node pointed to by the incoming pointer will not change

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 4. SListPushBack

Because we write the single linked list without head node, we need to consider the case of NULL pointer. When the original linked list has no data elements, the head pointer points to NULL. We need to change the value of the head pointer. Therefore, we need to use the secondary pointer to receive the head pointer address to change the value of the head pointer

```void SListPushBack(SLN** pplist, SLDataType x)
{
SLN* newnode = BuySListNode(x);//Use the create node function and use newnode to receive
if (*pplist == NULL)
{
*pplist = newnode;//Change the header pointer value to the new node address
}
else
{
SLN* tail = *pplist;//Assign the header pointer to tail
while (tail->next != NULL)
{
tail = tail->next;//Traversal tail finding
}
tail->next = newnode;//The original tail node points to the new node
}
}```

Commissioning:

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 5. Single chain meter insertion · SListPushFront

Because the single linked list of headless nodes we write is header insertion, the value of the header pointer must be changed once for each node inserted. Therefore, the secondary pointer should be used to receive the address of the header pointer, and then change the value of the header pointer

```void SListPushFront(SLN** pplist, SLDataType x)
{
SLN* newnode = BuySListNode(x);//Dynamically apply for a new node
newnode->next = *pplist;//The new node refers to the position pointed to the head node
*pplist = newnode;//Point the head node to the new node
}```

Commissioning:

β

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 6. Single linked list lookup · slitfind

Find the position pos of the specified element in the linked list

```SLN* SListFind(SLN* plist, SLDataType x)//Function returns a pointer to the location of the node to be found
{
SLN* cur = plist;
while (cur)//Only if the linked list is not empty can the search process be carried out
{
if (cur->data == x)
{
return cur;//Returns a pointer to this node when found
}
cur = cur->next;//Traverse backward one by one
}
return NULL;

}```

Find debug

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 7. Insert (slightly troublesome) · slitinsertfront before specifying the pos position

```void SListInsertFront(SLN* pos,SLDataType x)
{
assert(pos);//Assert to prevent pos from being a null pointer
SLN* newnode = BuySListNode(x);//Dynamically apply for a node
newnode->next = pos->next;//Point the new node to the back node of pos
pos->next = newnode;//Point pos to new node
int tmp = pos->data;//Use temporary variables to exchange the data of pos and newnode nodes
pos->data = newnode->data;
newnode->data = tmp;
}```

debugging

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 8. Insert SListInsertAfter after specifying the pos position

It can be seen that the final results of step 7 and step 8 are the same, but it is more convenient to insert after pos

```void SListInsertAfter(SLN* pos, SLDataType x)
{
SLN* newnode = BuySListNode(x);//Dynamically apply for a node
newnode->next = pos->next;//The new node points to the node that the pos points to
pos->next = newnode;//pos points to the new node
}```

debugging

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 9. SListPopBack

Three cases considered in tail deletion

1. The header pointer is null ----- > return directly

2. After there is only one node - > free, set the header pointer to null (change the value of the header pointer - > use the secondary pointer to receive)

3. There are many nodes - > Free lose the last node and set the next of the penultimate node to NULL

```void SListPopBack(SLN** pplist)
{
if (*pplist == NULL)
return;//The header pointer is null and returns directly
else if ((*pplist)->next == NULL)
{
free(*pplist);//Put the first node free
*pplist = NULL;//Set the value of the header pointer to null
}
else
{
SLN* tail = *pplist;
SLN* prev = NULL;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);//free tailed node
tail = NULL;//Set the value of the tail pointer to null
prev->next = NULL;//Set the next of the penultimate node to NULL
}
}```

Commissioning:

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 10. Header deletion · SListPopBack

As can be seen from the figure below, only two situations need to be considered for header deletion:

1. The header pointer is null ----- > return directly

2. Change the value of the header pointer to the next of the first node (that is, change the value of the header pointer, and use the secondary pointer to receive the header pointer address)

```void SListPopFront(SLN** pplist)
{
if (*pplist == NULL)
return;
else
{
SLN* cur = (*pplist)->next;//Declare a temporary variable pointing to the successor of the first node
free(*pplist);//free drop the first node
*pplist = cur;//The header pointer points to the node pointed to by the temporary variable
}
}```

Commissioning:

β¨β¨β¨ I am the dividing line β¨β¨β¨

# π Topic 1

Insert a value x in front of a node in a headless single linked list. How to insert it (don't tell you the header pointer!)

Solution: insert backward and exchange the two values

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 11. Delete SListEraseAfter the specified position

```void SListEraseAfter(SLN* pos)
{
assert(pos);//Assert that if pos is empty, it will not be executed downward
if (pos->next == NULL)
{
return;//pos is the last node, delete air
}
else
{
SLN* next = pos->next;//Give the address of the node after pos to next
pos->next = next->next;
free(next); //free drops the node pointed to by next
next = NULL;//It is a good habit to leave next blank
}
}```

debugging

β¨β¨β¨ I am the dividing line β¨β¨β¨

# β 12. Delete SListEraseFront before the specified position

```void SListEraseFront(SLN** pplist,SLN* pos)
{
assert(pos);
assert(*pplist);
if (*pplist == pos)
return;//pos is in the first node and cannot be deleted before
SLN* cur = *pplist;
SLN* prev = NULL;
if (cur->next == pos)//The deleted position is the first node, and the value of the header pointer needs to be changed
{
*pplist = pos;
free(cur);
cur = NULL;
}
else//In other cases, double pointers are used for connection and free
{
while (cur->next != pos)
{
prev = cur;
cur = cur->next;
}
prev->next = pos;
free(cur);
cur = NULL;
}
}```

debugging

β¨β¨β¨ I am the dividing line β¨β¨β¨

# π Exercise 2. Removing linked list elements

β

Train of thought analysis:

## π Conventional method

```struct ListNode* removeElements(struct ListNode* head, int val){
//Why not use secondary pointers? Didn't the value of the header pointer here change?
//A return value struct ListNode * is used, so the value of the head node changed inside the function can also be obtained outside the function
struct ListNode* prev =NULL ;
while(cur)
{
if(cur->val==val)
{
struct ListNode* next=cur->next;
{
free(cur);
cur=next;
}
else
{
prev->next=next;
free(cur);
cur=next;
}
}

else
{
prev=cur;//When prev is not NULL, the first element must not be val
cur=cur->next;
}
}
}```

Note: why not use secondary pointers? Isn't the value of the head node here changed?
A return value struct ListNode * is used, so the value of the head node changed inside the function can also be obtained outside the function

## π Sentinel method

If we add a sentinel position, we don't need to discuss it according to whether the first element is val

(whether the first element is val) ------- > the essence is the null pointer problem of prev

```struct ListNode* reverseList(struct ListNode* head){
while(cur)
{
struct ListNode* next=cur->next;
cur=next;
}
}```

β¨β¨β¨ I am the dividing line β¨β¨β¨

# π Exercise 3. Reverse linked list

β

## π Idea 1: directly use three pointers to flip

```1->2->3->4->NULL
Through 3 pointers n1\n2\n3 Flip

n1  n2 n3
NULL  1->2->3->4->NULL

n1  n2 n3
NULL<-1  2->3->4->NULL

n1  n2 n3
NULL<-1<-2  3->4->NULL

n1  n2 n3
NULL<-1<-2<-3  4->NULL

n1  n2 n3
NULL<-1<-2<-3<-4  NULL```
```struct ListNode* reverseList(struct ListNode* head){
while(n2)
{
n2->next=n1;//Flip

n1=n2;//iteration
n2=n3;
if(n3==NULL)//Prevent null pointer
break;
n3=n3->next;
}
return n1;
}```

β

## π Idea 2: head insertion method

Note that the header does not create a new node here

```cur next
1 ->2 ->3 ->4->NULL

Each time, take the node in the original linked list and insert it into the new node
Two pointers are required, one for header insertion and one for identifying the next node

1->NULL

-----step2-----

cur next
1->2 ->3->4->NULL

2->1->NULL
```
```struct ListNode* reverseList(struct ListNode* head){