Reverse linked list
Three pointers:
Problem solving ideas:
-
First analyze the special case. When the linked list is empty or there is only one node, directly return to head
-
When there are more than one node in the linked list, we first consider whether we can reverse the pointer in turn, so as to reverse the linked list, as shown in the following figure:
Then, to reverse the pointer, you can first define two pointers n1 and n2
n2->next=n1;
But there is a problem here. When n2 points to n1, the address of the second node is lost. Therefore, it is necessary to define an additional pointer n3 to save the address of the second node
-
When the first node points to NULL, n1, n2 and n3 move one node backward to make the second node point to the first node
Here, the movement of the three pointers is completed by iteration, which is divided into three steps:
- n1=n2
- n2=n3
- n3=n3->next
-
Repeat the third step until n2 points to NULL, the cycle ends and the reverse linked list is completed
It should be noted here that since the inversion is performed now and the iteration is in progress, when n3 points to NULL, the loop will not end until an iteration is performed
Complete code
struct ListNode* reverseList(struct ListNode* head){ if(head==NULL||head->next==NULL) return head; struct ListNode* n1=NULL,*n2=head,*n3=head->next; while(n2) { n2->next=n1; n1=n2; n2=n3; if(n3) n3=n3->next; } return n1; }
Head insertion method:
Problem solving ideas:
-
In addition to reversing from the original linked list, you can also open up a new linked list with the pointer newhead pointing to the header Head insertion , insert the nodes of the original linked list into the new linked list in turn
struct ListNode* newhead = NULL;
-
First define two pointers cur and next. Cur is used to take the node from the old linked list and insert it into the new linked list. Next is the same as saving the next node, so as to prevent cur from finding the old linked list again after moving the node to the new linked list
-
When cur==NULL, the linked list is reversed. The specific process is as follows:
Complete code
struct ListNode* reverseList(struct ListNode* head){ struct ListNode* newhead = NULL; //Open up a new linked list struct ListNode* cur = head; //cur is used to take the knot from the old linked list and insert it into the new linked list while(cur) //When cur is not NULL, the loop continues { struct ListNode* next=cur->next; //It is used to save the next node of cur mobile node cur->next=newhead; //Insert the header into the new linked list newhead=cur; //newNode points to the new header node in the new linked list cur=next; //cur returns to the old linked list and continues to move the next node } return newhead; }
Intermediate node of linked list
Solution: speed pointer
- According to the meaning of the topic, after traversing the linked list, you need to return to the intermediate node
- Then whether two pointers can be defined. When the fast pointer traverses, the slow pointer just points to the middle node of the linked list
- It is not difficult to find that as long as the fast pointer takes one more step each time than the slow pointer, at the end, the slow pointer can point to the middle node of the linked list
Complete code
struct ListNode* slow=head; struct ListNode* fast=head; //The start positions of the fast and slow pointers point to the head node //When fast==NULL (the number of nodes is odd), fast - > next = = null (the number of nodes is even), the cycle ends and intermediate nodes are found while(fast&&fast->next) { slow = slow->next; fast = fast->next->next; //The slow pointer takes one step and the fast pointer takes two steps } return slow;
The penultimate node in the lin k ed list
Title: enter a linked list and output the penultimate node in the linked list. In order to meet the habit of most people, this question starts from 1, that is, the tail node of the linked list is the penultimate node. For example, a linked list has 6 nodes. Starting from the beginning, their values are 1, 2, 3, 4, 5 and 6. The penultimate node of the linked list is the node with the value of 4.
Problem solving ideas:
- Like the previous question, this question also requires to return a node in the linked list. Therefore, it can also be solved by using fast and slow pointers
- Define the fast and slow pointer, but the difference here is that the starting position of the fast pointer points to NULL, the slow pointer points to the head node, the fast pointer takes k steps in advance, and then the fast and slow pointer moves forward at the same time, so the fast pointer will always lead the slow pointer by k nodes. After the fast pointer traverses the linked list, the node pointed to by the slow pointer is the penultimate node in the linked list.
struct ListNode*fast=NULL; //The fast pointer points to NULL struct ListNode*slow=pHead; //The slow pointer points to the head node while(k--) //Go k steps first { if(fast) fast=fast->next; else return NULL; } while(fast) //The fast and slow pointers move at the same time { fast=fast->next; slow=slow->next; } return slow;
Merge two ordered linked lists
-
First, consider the special case. If all the linked lists are empty, return one of them. If one of them is empty, return another non empty linked list
if(list1==NULL) { return list2; } if(list2==NULL) { return list1; }
-
In addition to the first special case, other cases can malloc a head node with a sentinel position, and compare the node sizes of list1 and list2 in turn. The small node has priority to be tail inserted into the new linked list. To carry out tail insertion, it is necessary to define a pointer to the tail node of the new linked list and record the address of the tail node
Node*head=NULL,*tail=NULL; head=tail=(Node*)malloc(sizeof(Node)); //Take the small tail insert while(list1&&list2) { if(list1->val<list2->val) { tail->next=list1; list1=list1->next; } else { tail->next=list2; list2=list2->next; } tail=tail->next; }
-
When does it end? When one of the linked lists is empty, insert the whole tail of the rest of the other linked list after the new linked list
if(list1) tail->next=list1; else tail->next=list2;
The overall process is as follows:
Complete code
typedef struct ListNode Node; struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { if(list1==NULL) //Judgment of special circumstances { return list2; } if(list2==NULL) { return list1; } Node*head=NULL,*tail=NULL; //The head node with sentinel position does not store valid data head=tail=(Node*)malloc(sizeof(Node)); //Take the small tail insert while(list1&&list2) //Both linked lists are not empty { if(list1->val<list2->val) { tail->next=list1; list1=list1->next; } else { tail->next=list2; list2=list2->next; } tail=tail->next; } if(list1) tail->next=list1; else tail->next=list2; Node *realHead; realHead=head->next; //The real head node is the next node of the sentry position return realHead; }
Linked list segmentation
Idea:
Since the linked list cannot be reordered on the basis of the original linked list, since the topic requires that the larger than X be moved to node X and the smaller than X be moved to node x, we can open up two linked lists, one to store the smaller than x node (smallhead) and the other to store the larger than x node (bighead), and then connect the two linked lists.
- Traverse the original linked list, insert the end of the node smaller than x into smallhead and the head larger than x into bighead, and finally get the following two linked lists.
- It should be noted here that since the head node of the developed linked list is a sentinel node and does not store data, when two linked lists are linked, the last node of the sentinel bit head node of the large linked list should be linked with the tail node of the small linked list, and the tail node of the large linked list should be empty, so as to get the separated linked list.
smalltail->next=bigHead->next; bigtail->next=NULL;
Complete code
typedef struct ListNode Node; struct ListNode* partition(struct ListNode* head, int x){ Node *smallHead,*smalltail,*bigHead,*bigtail; smallHead=smalltail=(Node*)malloc(sizeof(Node)); bigHead=bigtail=(Node*)malloc(sizeof(Node)); smallHead->next=smalltail->next=NULL; bigHead->next=bigtail->next=NULL; while(head) { if(head->val<x) { smalltail->next=head; smalltail=smalltail->next; } else { bigtail->next=head; bigtail=bigtail->next; } head=head->next; } smalltail->next=bigHead->next; bigtail->next=NULL; return smallHead->next; }
Palindrome linked list
Idea:
-
To judge whether the linked list is a palindrome linked list, we can disconnect from the intermediate node and compare each node one by one. How to find the intermediate node can still use the fast and slow pointer method. Each step of the slow pointer, the fast pointer takes two steps. When the fast pointer reaches the end, the slow pointer points to the intermediate node, but we don't want to disconnect after the intermediate node, But to disconnect the previous node of the intermediate node, we also need a pointer to keep the previous node of the slow pointer.
-
However, because the linked list cannot be traversed in reverse, the second linked list must be reversed. The inversion method is the same as the second method of the above linked list inversion problem, which will not be repeated here.
Complete code
typedef struct ListNode Node; bool isPalindrome(struct ListNode* head){ Node *fast = head; Node *slow = head; Node *prev = NULL; if(head->next == NULL) return true; while(fast && fast->next) { prev = slow; // Keep the previous node of slow slow = slow->next; //Come on, take two steps fast = fast->next->next; //Come on, take two steps } prev->next = NULL;//Disconnect from prev node //Linked list inversion Node *newhead = NULL; Node *cur = slow; while(cur) { Node *next =cur->next; cur->next = newhead; newhead = cur; cur = next; } //Compare the two linked lists while(head) { if(head->val == newhead->val) { head = head->next; newhead = newhead->next; } else return false; } return true; } e *newhead = NULL; Node *cur = slow; while(cur) { Node *next =cur->next; cur->next = newhead; newhead = cur; cur = next; } //Compare the two linked lists while(head) { if(head->val == newhead->val) { head = head->next; newhead = newhead->next; } else return false; } return true; }