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. The linked list node is defined as follows:
Struct listnode
{
Int m_nkey;
Listnode * m_pnext;
};
Analysis: to get the last K nodes, it is natural to go to the end of the linked list first, and then backtrack K steps from the end. However, the input is a one-way linked list. Only the pointer from the past to the next is not the pointer from the back to the next. Therefore, we need to open up our ideas.
Since the linked list cannot be traversed from the End Node, we should return the idea to the header node. Assuming that the entire linked list has n nodes, the last K nodes are the n-k-1 nodes starting from the first node (counting from 0 ). If we can get the number n of nodes in the linked list, we only need to go back from the node to the n-k-1 step. How do I get the number of knots n? This is not difficult. You only need to start the traversal chain table from the beginning. Each time you go through a node, you can add one to the counter.
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. However, if the number of nodes in the input linked list is large, it is possible that the entire linked list cannot be read from the hard disk into the physical memory at one time, traversing twice means that a node needs to be read twice from the hard disk to the physical memory. It is time-consuming to read data from the hard disk to the memory. Can we reduce the number of linked list traversal times to 1? If possible, it will effectively improve the time efficiency of code execution.
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 K-1 step, the second pointer also starts 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.
Reference code for IDEA 1:
//////////////////////////////////////// ///////////////////////////////
// Find the kth node from the tail of a list
// Input: plisthead-the head of list
// K-the distance to the tail
// Output: the kth node from the tail of a list
//////////////////////////////////////// ///////////////////////////////
Listnode * findkthtotail_solution1 (listnode * plisthead, unsigned int K)
{
If (plisthead = NULL)
Return NULL;
// Count the nodes number in the list
Listnode * pcur = plisthead;
Unsigned int nnum = 0;
While (pcur-> m_pnext! = NULL)
{
Pcur = pcur-> m_pnext;
Nnum ++;
}
// If the number of nodes in the list is less than K
// Do nothing
If (nnum <K)
Return NULL;
// The Kth node from the tail of a list
// Is the (n-k) Th node from the head
Pcur = plisthead;
For (unsigned int I = 0; I <nnum-K; ++ I)
Pcur = pcur-> m_pnext;
Return pcur;
}
Reference code for idea 2:
//////////////////////////////////////// ///////////////////////////////
// Find the kth node from the tail of a list
// Input: plisthead-the head of list
// K-the distance to the tail
// Output: the kth node from the tail of a list
//////////////////////////////////////// ///////////////////////////////
Listnode * findkthtotail_solution2 (listnode * plisthead, unsigned int K)
{
If (plisthead = NULL)
Return NULL;
Listnode * pahead = plisthead;
Listnode * pbehind = NULL;
For (unsigned int I = 0; I <K; ++ I)
{
If (pahead-> m_pnext! = NULL)
Pahead = pahead-> m_pnext;
Else
{
// If the number of nodes in the list is less than K,
// Do nothing
Return NULL;
}
}
Pbehind = plisthead;
// The distance between pahead and pbehind is K
// When pahead arrives at the tail, P
// Behind is at the kth node from the tail
While (pahead-> m_pnext! = NULL)
{
Pahead = pahead-> m_pnext;
Pbehind = pbehind-> m_pnext;
}
Return pbehind;
}
Discussion: the code for this question has a lot of pointer operations. In software development, incorrect pointer operations are the root cause of most problems. Therefore, every company wants programmers to have good habits in operating pointers, such as judging whether a pointer is null before using pointers. These are the details of programming, but if these details are not well grasped, it is very likely to lose hands with your favorite company.
In addition, the Code corresponding to these two ideas contains loops. A common problem with code containing loops is the judgment of the loop end condition. Should I use less than or equal? Should I use K or K-1? Because the question requires counting from 0, and our habit of thinking is counting from 1, we must first think about these boundary conditions before writing code, in addition, after writing the code, run the code once with the boundary value, the boundary value minus 1, and the boundary value plus 1 (write the code on paper and you can only run it in your mind ).
Extension: similar to this question, you can also enter a one-way linked list. If the number of knots in the linked list is an odd number, the intermediate node is output. If the number of knots in the linked list is an even number, one before the two nodes is output. If you are interested, analyze and write your own code.