Linked List:
1. check whether there are any leading nodes.
2. Create a single-chain table: Create a table in sequence (tail insertion method) and create a table in reverse order (header insertion method ). To insert or delete a single-chain table, you need to find the front node.
3. Compared with a one-way linked list, a one-way linked list has a forward pointer. When deleting a node, a one-way linked list needs to traverse the table.
Insert and delete a two-way cyclic linked list:
1. insert SS-> next = p-> next; P-> next = s; s-> prior = P; s-> next-> prior = s; 2. insert SS-> prior = p-> prior; P-> prior = s; s-> next = P; s-> prior-> next = s; 3. after p is deleted, follow Ss = p-> next; P-> next = s-> next; P-> next-> prior = P; 4. delete PP-> prior-> next = p-> next; P-> next-> prior = p-> prior;
1. Determine whether two linked lists are intersecting: (assume that both linked lists have no rings)
Method:
1. Determine whether each node of the first linked list is in the second linked list.
2. Connect the second linked list to the end of the first linked list to check whether the linked list has a ring and if it has a ring
3. If the two linked lists have a public node, all the nodes after the public node will overlap, and their last node will inevitably overlap.
Traverse the first linked list first, remember the last node, and then traverse the second linked list to get a comparison between the last node and the last node of the first linked list.
How can we determine that a single-chain table has loops?
Set two pointers (fast and slow). The initial values all point to the header. Slow moves one step forward each time, and fast moves two steps forward each time. If the linked list has a ring, fast must first enter the ring, when slow enters the ring, the two pointers must meet each other. (Of course, if the first line to the end of fast is null, It is a loop-free linked list) The program is as follows:
bool IsExitsLoop(ListNode *head){ ListNode *slow = head, *fast = head; while ( fast && fast->next ) { slow = slow->next; fast = fast->next->next; if ( slow == fast ) break; } return !(fast == NULL || fast->next == NULL);}
Find the entry point of the ring
When fast encounters slow, slow certainly does not traverse the linked list, and fast already loops n circles (1 <= N) in the ring ). Assume that slow takes the s step, then fast takes 2 s step (the number of fast steps is equal to the number of S plus N turns on the ring), set the ring length to R, then:
2 S = S + nR
S = nR
The distance between the ring entry point and the encounter point is X, and the distance from the start point to the ring entry point is A, then:
A + x = s
A + x = nR
A = nR-x
The distance from the head of the linked list to the entry point of the ring is equal to n-cycle Inner Ring minus the distance from the inner point of the ring to the encounter point. Now, a pointer P1 is traversed from the start point of the linked list and P2 is traversed from the encounter point, the step sizes of P1 and P2 are both 1. When P1 moves from a, it reaches the entry point of the ring. Since P2 begins to move from the encounter point, P2 moves the NR step back to the encounter point, and then moves the X step back to the entrance point of the ring, that is, the distance (NR-x) is moved. When P1 moves a to the entry point of the ring for the first time, P2 also arrives at the entry point. The program is described as follows:
ListNode* FindLoopPort(ListNode *head){ ListNode *slow = head, *fast = head; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) break; } if(fast == NULL || fast->next == NULL) return NULL; slow = head; while(slow != fast) { slow = slow->next; fast = fast->next; } return slow;}
Extension 1: If the linked list may have a ring, how can we determine whether two linked lists are intersecting?
Ideas:
1. First, judge whether a belt or no ring exists.
2. If none of them contain loops, determine whether the end node is equal.
3. If both nodes contain loops, judge the node on which the two pointers meet in a linked list. If the nodes are not in another linked list, the nodes are intersecting. If the nodes are not in a linked list, the nodes are not intersecting.
// 1. first, judge whether there is a ring with no ring. // check whether there is a ring and return bool. If there is a ring, return the node in the ring. // train of thought: Use two pointers. one pointer step is 1, A pointer step is 2 to determine whether the linked list has a circle bool iscircle (node * head, node * & circlenode, node * & lastnode) {node * fast = head-> next; node * slow = head; while (fast! = Slow & Fast & slow) {If (fast-> next! = NULL) Fast = fast-> next; If (fast-> next = NULL) lastnode = fast; If (slow-> next = NULL) lastnode = slow; fast = fast-> next; slow = slow-> next;} If (fast = slow & Fast & slow) {circlenode = fast; return true ;} else return false ;}
If none of the nodes are connected, the system determines whether the tail node is equal. If both nodes are connected, the node where the two pointers meet in a linked list is not on the other linked list. The following code comprehensively solves this problem:
// Determine whether the linked list is intersecting when the belt ring does not have a ring. // 2. if none of them contain loops, determine whether the end node is equal. // 3. if both nodes contain loops, judge the node where the two pointers meet on a linked list, and the node is not on the other linked list. Bool detect (node * head1, node * head2) {node * circlenode1; node * worker; node * lastnode1; node * lastnode2; bool iscircle1 = iscircle (head1, circlenode1, lastnode1 ); bool iscircle2 = iscircle (head2, circlenode2, lastnode2); // If (iscircle1! = Iscircle2) return false; // both nodes have no loops and determine whether the last node is equal to else if (! Iscircle1 &&! Iscircle2) {return lastnode1 = lastnode2;} // both have loops, determine whether the node in the ring can reach the node else {node * temp = circlenode1-> next; while (temp! = Circlenode1) {If (temp = circlenode2) return true; temp = temp-> next;} return false ;}
Extension 2: Find the first node of the intersection of two linked lists
Idea: if the two tail nodes are the same, they overlap; otherwise, the two linked lists do not have public nodes.
In the above thinking, when we traverse two linked lists to the End Node sequentially, we cannot guarantee that the two linked lists reach the end node at the same time, because the two linked lists are not necessarily of the same length. However, if one linked list has more than one node long than the other, we first traverse more than one node on the long linked list, and then synchronize the traversal, at this time, we can ensure that the last node is reached at the same time. Since the two linked lists start from the first public node to the End Node of the linked list, this part is overlapped. Therefore, they must also reach the first public node at the same time. Therefore, in traversal, the first same node is the first public node.
In this way, we first need to traverse the two linked lists to obtain their lengths and find the difference between the two lengths. After traversing the long linked list several times, traverse the two linked lists synchronously until the same node is found or until the linked list ends. At this point, if the length of the first linked list is m and the length of the second linked list is N, the time complexity of this method is O (m + n ).
ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2){ // Get the length of two lists unsigned int nLength1 = ListLength(pHead1); unsigned int nLength2 = ListLength(pHead2); int nLengthDif = nLength1 - nLength2; // Get the longer list ListNode *pListHeadLong = pHead1; ListNode *pListHeadShort = pHead2; if(nLength2 > nLength1) { pListHeadLong = pHead2; pListHeadShort = pHead1; nLengthDif = nLength2 - nLength1; } // Move on the longer list for(int i = 0; i < nLengthDif; ++ i) pListHeadLong = pListHeadLong->m_pNext; // Move on both lists while((pListHeadLong != NULL) && (pListHeadShort != NULL) && (pListHeadLong != pListHeadShort)) { pListHeadLong = pListHeadLong->m_pNext; pListHeadShort = pListHeadShort->m_pNext; } // Get the first common node in two lists ListNode *pFisrtCommonNode = NULL; if(pListHeadLong == pListHeadShort) pFisrtCommonNode = pListHeadLong; return pFisrtCommonNode;}unsigned int ListLength(ListNode* pHead){ unsigned int nLength = 0; ListNode* pNode = pHead; while(pNode != NULL) { ++ nLength; pNode = pNode->m_pNext; } return nLength;}
Ii. Question: Given the head pointer and a node pointer of the linked list, delete the node at O (1) time.
Analysis: we need to start from the first node to find the node to be deleted because we need to get the first node of the node to be deleted. In another way, we can get its next node from a given node. In this case, the next node is actually deleted. Because we have obtained the first node of the actually deleted node, it can be fully implemented. Of course, before deleting a node, We need to copy the data of the next node of the given node to the given node. At this time, the time complexity is O (1 ).
void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted){ if(!pListHead || !pToBeDeleted) return; // if pToBeDeleted is not the last node in the list if(pToBeDeleted->m_pNext != NULL) { // copy data from the node next to pToBeDeleted ListNode* pNext = pToBeDeleted->m_pNext; pToBeDeleted->m_nKey = pNext->m_nKey; pToBeDeleted->m_pNext = pNext->m_pNext; // delete the node next to the pToBeDeleted delete pNext; pNext = NULL; } // if pToBeDeleted is the last node in the list else { // get the node prior to pToBeDeleted ListNode* pNode = pListHead; while(pNode->m_pNext != pToBeDeleted) { pNode = pNode->m_pNext; } // deleted pToBeDeleted pNode->m_pNext = NULL; delete pToBeDeleted; pToBeDeleted = NULL; }}
It is worth noting that in order to make the Code look concise, the above Code is based on two assumptions: (1) the given node is indeed in the linked list; (2) the given node to be deleted is not the head node of the linked list. The first assumption does not affect the robustness of the Code. As for the second assumption, the Code may be faulty when there is only one knot in the entire list. But this assumption is not too much, because in some linked list implementations, a virtual linked list header is created, and it is not an actual linked list node. In this way, the node to be deleted cannot be the head node of the linked list.
Extension: A single-chain table without a header pointer. A pointer points to a node in the middle of the single-chain table (not the first or the last one) and deletes the node.
Deleting a node requires its precursor node, but this question cannot be obtained. Therefore, the value of the node next to the node will be deleted and then deleted.
void DeleteRandomNode(node* pCurrent){ assert(pCurrent != NULL) node* pNext = pCurrent->next; if(pNext != NULL) { pCurrent->next = pNext->next; pCurrent->data = pNext->data; delete pNext; }}
3. Deleting the most intermediate element of a single linked list requires the shortest time
void DeleteMiddleNode(ListNode *head){ if(head == NULL) return; else if(head->next == NULL) { delete head; return; } else { ListNode *low = head; ListNode *fast = head->next; while(fast != NULL && fast->next != NULL) { fast = fast->next->next; if(fast == NULL) break; low = low->next; } ListNode *temp = low->next; low->next = low->next->next; delete temp; }}
3. Search for the last K nodes
Question: enter a one-way linked list and output the k-th node in the list. The last 0th nodes of the linked list are the tail pointer of the linked list.
Solution 1: assuming that the entire linked list has n nodes, then the last K nodes are the first n-k-1 nodes starting from the first node (counting from 0 ).
The time complexity of this approach is O (n), but it needs to be two times in a traversal chain table. The number of nodes in the linked list is N for the first time, and the number of n-k-1 nodes starting from the first node is K for the second time. If the number of knots in the linked list is small, this is a good method.
ListNode* FindKthToTail(ListNode* head, int k){ if(head == NULL) return NULL; ListNode *p = head; unsigned int n = 0; while(p->next != NULL) { p = p->next; n ++; } if(n < k) return NULL; p = head; for(int i = 0; i < n-k; ++i) p = p->next; return p;}
Solution 2: If we maintain two pointers over time, the first pointer traverses from the head pointer of the linked list, and the second pointer remains unchanged before the K-1 step; at the beginning of the K-1 step, the second pointer also begins to traverse from the head pointer of the linked list. Since the distance between the two pointers is kept in the K-1, when the first (walking in front) pointer reaches the end point of the linked list, the second pointer (walking behind) the pointer is exactly the last K node.
In this way, you only need to traverse a table once. For a long linked list, you only need to import each node from the hard disk to the memory once. Therefore, the time efficiency of this method is higher than that of the previous method.
ListNode *FindMToLastElement(ListNode *head, int m) { ListNode *p1, *p2; p1 = head; for(int i = 0; i < m; ++i) { if(p1->next) p1 = p1->next; else return NULL; } p2 = head; while(p1->next) { p1 = p1->next; p2 = p2->next; } return p2;}
4. From the end to the first time
Question: Enter the head node of a linked list and output the value of each node from the end to the end.
1. Reverse the linked list and output from start to end
Void reverselist (listnode * head) {listnode * P = head-> next; // head of the original linked list> next = NULL; // new table (empty table) while (P! = NULL) {listnode * q = p-> next; // save the next node q p-> next = head-> next; head-> next = P; P = Q ;}}
2. From the beginning to the end, each time a node passes through, the node is put into a stack. After traversing the entire chain table, the node value is output from the top of the stack. At this time, the order of the output nodes has been reversed. This method requires the maintenance of an additional stack, which is difficult to implement.
3. Since we think of stack to implement this function, recursion is essentially a stack structure. So naturally, we thought of implementing it with recursion. To output the linked list in turn, each time we access a node, we first recursively output the node next to it, and then output the node itself, so that the output result of the linked list is reversed.
void PrintListReversely(ListNode* head){ if(head != NULL) { // Print the next node first if (head->next != NULL) { PrintListReversely(head->next); } // Print this node printf("%d", head->data); }}
5. Sort the linked list
Typedef listnode * List; // sort the elements in a single-chain table by insertion. Void insertionsort (List & L) {list H = L-> next; // The original linked list l-> next = NULL; // The New empty table list s = NULL, P = NULL; while (h) {// remove the node S = H from the original linked list; H = H-> next; // find the insert position P = l in the new table; while (p-> next & P-> next-> data <= s-> data) P = p-> next; // insert S-> next = p-> next; P-> next = s;} after P. // sort the elements in a single-chain table by choice. Void selectionsort (List & L) {list p = L; List q = NULL, S = NULL, M = NULL; while (p-> next) {// select the smallest (from p-> next to the end of the table) q = P; // The precursor q s of the smallest element = P; while (S-> next) {If (S-> next-> data <q-> next-> data) q = s; S = s-> next;} M = Q-> next; // locate the minimum M // The minimum element m inserts at the end of the ordered sequence (after P) if (Q! = P) {q-> next = m-> next; // minimum M m-> next = p-> next; // after P is inserted, p-> next = m;} p = p-> next; // L-> next to P is an ordered sequence }}