Single linked list story

πŸŒ• Write in front

catalogue

πŸŒ• Write in front

πŸ”₯ Logical structure

πŸ”₯ Storage structure: single linked list

πŸ”₯ Header pointer and header node  

🍊 Head pointer

🍊 Head node  

🍊 Similarities and differences between head pointer and head node

πŸ”₯ Lead and no lead nodes

🍊 No lead node

🍊 Leading node  

βœ… 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

Linked 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 ✨✨✨

πŸ”₯ Header pointer and header node  

🍊 Head pointer

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 "^")

🍊 Head node  

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

🍊 Similarities and differences between head pointer and head node

✨✨✨ I am the dividing line ✨✨✨

πŸ”₯ Lead and no lead nodes

🍊 No lead node

Β 

🍊 Leading node  

✨✨✨ 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

203. Remove 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* cur = head;
    struct ListNode* prev =NULL ;
    while(cur)
    {
        if(cur->val==val)
        {
            struct ListNode* next=cur->next;
            if(prev==NULL)//cur is the head
            {
                free(cur);
                head=next;
                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;
        }
    }
    return head;
}

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){
    struct ListNode* cur=head , *newHead=NULL;
    while(cur)
    {
        struct ListNode* next=cur->next;
        cur->next=newHead;
        newHead=cur;
        cur=next;
    }
    return newHead;
}

✨✨✨ I am the dividing line ✨✨✨

πŸ“„ Exercise 3. Reverse linked list

206. 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){
    if(head==NULL||head->next==NULL)//Empty table, or when there is only one node
        return head;
    struct ListNode* n1=NULL, *n2=head, *n3=head->next;
    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

newHead==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

cur->newHead
 1->NULL
cur=newhead

-----step2-----

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

 cur->newHead->NULL
   2->1->NULL
cur=newHead
struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* cur=head , *newHead=NULL;
    while(cur)
    {
        struct ListNode* next=cur->next;
        cur->next=newHead;
        newHead=cur;
        cur=next;
    }
    return newHead;
}

Tags: Algorithm data structure Singly Linked List

Posted on Mon, 29 Nov 2021 09:30:04 -0500 by Mad Mick