Some topics of data structure, linked list

Posted by (RL)Ian on Tue, 21 Sep 2021 04:12:36 +0200

Copyright, reprint, please indicate the source, thank you!
Original link: https://blog.csdn.net/luckyxiaoqiang/article/details/7393134

The known linked list nodes are declared as follows:
struct ListNode
{
int m_nKey;
ListNode * m_pNext;
};

1. Find the number of nodes in the single linked list

//Find the number of nodes in the single linked list
int numberNode(ListNode* node)
{
	if (node=nullptr)
	{
		return;
	}
	int num = 0;
	while (node!=nullptr)
	{
		num++;
		node = node->m_pNext;
	}
	return num;
}

2. Reverse the single linked list

//Single linked list inversion
ListNode*FlipList(ListNode*node)
{
if (node==nullptr)//Determine whether it is an empty linked list
	{
		return;
	}
	ListNode*phead = nullptr;
	while (node!=nullptr)
	{//Take the original chain header node
		ListNode*p = node;
		//The original chain header pointer points to the next node
		node = node->m_pNext;
		//The pointer field of the current node is null
		p->m_pNext = nullptr;
		//Judge whether it is the first node
		if (nullptr==phead)
		{
			phead = p;
		}
		else
		{
			p->m_pNext = phead;
			phead = p;
		}
	}
	return phead;
}

3. Find the penultimate node in the single linked list (K > 0)

The main idea is to use two pointers. First, let the front pointer go to the k-th node in the positive direction, so that the distance difference between the front and rear pointers is k-1. Then, the front and rear pointers go forward together. When the front pointer goes to the last node, the node referred to by the rear pointer is the penultimate node.

//Find the penultimate node in the single linked list
ListNode* findLastNode(ListNode*node, int k)
{
	if (0 == k || nullptr == node)//Empty judgment processing
	{
		return nullptr;
	}
	ListNode*first = node;
	ListNode*second = node;
	for (int i = 0; i < k-1; i++)
	{
		second = second->m_pNext;
		if (second==nullptr)//If second is empty, the node location to be found is outside the linked list
		{
			return nullptr;
		}
	}
	while (second->m_pNext!=nullptr)
	{
		first = first->m_pNext;
		second = second->m_pNext;
	}
	return first;//The previous pointer refers to the node to be found
}

4. Find the intermediate node of the single linked list

This question can be applied to similar ideas in the previous question. It also sets two pointers, but here, the two pointers move forward at the same time. The front pointer moves two steps at a time and the rear pointer moves one step at a time. When the front pointer moves to the last node, the node referred to by the rear pointer is the intermediate node, that is, the (n/2+1) node. Note that the linked list is empty and the number of nodes in the linked list is 1 and 2. Time complexity O (n). Reference codes are as follows:

// Get the middle node of the single linked list. If the length of the linked list is n (n > 0), the n/2+1 node is returned
ListNode * GetMiddleNode(ListNode * pHead)
{
	if(pHead == NULL || pHead->m_pNext == NULL) // If the linked list is empty or has only one node, return the header pointer
		return pHead;
 
	ListNode * pAhead = pHead;
	ListNode * pBehind = pHead;
	while(pAhead->m_pNext != NULL) // The front pointer takes two steps at a time until it points to the last node, and the rear pointer takes one step at a time
	{
		pAhead = pAhead->m_pNext;
		pBehind = pBehind->m_pNext;
		if(pAhead->m_pNext != NULL)
			pAhead = pAhead->m_pNext;
	}
	return pBehind; // The node referred to by the following pointer is the intermediate node
}

5. Print the single linked list from end to end

For this reverse order problem, we should think of stack, last in, first out. Therefore, this problem either uses the stack itself or allows the system to use the stack, that is, recursion. Note that the linked list is empty. The time complexity is O (n). Reference codes are as follows:
Use the stack yourself:

// Print the linked list from end to end, using the stack
void RPrintList(ListNode * pHead)
{
	std::stack<ListNode *> s;
	ListNode * pNode = pHead;
	while(pNode != NULL)
	{
		s.push(pNode);
		pNode = pNode->m_pNext;
	}
	while(!s.empty())
	{
		pNode = s.top();
		printf("%d\t", pNode->m_nKey);
		s.pop();
	}
}

Use recursive functions:

// Print the linked list from end to end, using recursion
void RPrintList(ListNode * pHead)
{
	if(pHead == NULL)
	{
		return;
	}
	else
	{
		RPrintList(pHead->m_pNext);
		printf("%d\t", pHead->m_nKey);
	}
}

6. It is known that the two single linked lists pHead1 and pHead2 are ordered respectively, and they are still ordered when combined into a linked list

This is similar to merge sort. Pay special attention to the case when both linked lists are empty and one of them is empty. Only O (1) space is required. The time complexity is O (max(len1, len2)). Reference codes are as follows:

// Merge two ordered linked lists
ListNode * MergeSortedList(ListNode * pHead1, ListNode * pHead2)
{
	if(pHead1 == NULL)
		return pHead2;
	if(pHead2 == NULL)
		return pHead1;
	ListNode * pHeadMerged = NULL;
	if(pHead1->m_nKey < pHead2->m_nKey)
	{
		pHeadMerged = pHead1;
		pHeadMerged->m_pNext = NULL;
		pHead1 = pHead1->m_pNext;
	}
	else
	{
		pHeadMerged = pHead2;
		pHeadMerged->m_pNext = NULL;
		pHead2 = pHead2->m_pNext;
	}
	ListNode * pTemp = pHeadMerged;
	while(pHead1 != NULL && pHead2 != NULL)
	{
		if(pHead1->m_nKey < pHead2->m_nKey)
		{
			pTemp->m_pNext = pHead1;
			pHead1 = pHead1->m_pNext;
			pTemp = pTemp->m_pNext;
			pTemp->m_pNext = NULL;
		}
		else
		{
			pTemp->m_pNext = pHead2;
			pHead2 = pHead2->m_pNext;
			pTemp = pTemp->m_pNext;
			pTemp->m_pNext = NULL;
		}
	}
	if(pHead1 != NULL)
		pTemp->m_pNext = pHead1;
	else if(pHead2 != NULL)
		pTemp->m_pNext = pHead2;
	return pHeadMerged;
}

There are also the following recursive solutions:

ListNode * MergeSortedList(ListNode * pHead1, ListNode * pHead2)
{
	if(pHead1 == NULL)
		return pHead2;
	if(pHead2 == NULL)
		return pHead1;
	ListNode * pHeadMerged = NULL;
	if(pHead1->m_nKey < pHead2->m_nKey)
	{
		pHeadMerged = pHead1;
		pHeadMerged->m_pNext = MergeSortedList(pHead1->m_pNext, pHead2);
	}
	else
	{
		pHeadMerged = pHead2;
		pHeadMerged->m_pNext = MergeSortedList(pHead1, pHead2->m_pNext);
	}
	return pHeadMerged;
}

7. Judge whether there is a ring in a single linked list

Two pointers are also used here. If there are links in a linked list, that is, traversing with a pointer will never end. Therefore, we can use two pointers to traverse. One pointer takes two steps at a time and one pointer takes one step at a time. If there is a ring, the two pointers will certainly meet in the ring. The time complexity is O (n). Reference codes are as follows:

bool HasCircle(ListNode * pHead)
{
	ListNode * pFast = pHead; // The fast pointer advances two steps at a time
	ListNode * pSlow = pHead; // The slow pointer advances one step at a time
	while(pFast != NULL && pFast->m_pNext != NULL)
	{
		pFast = pFast->m_pNext->m_pNext;
		pSlow = pSlow->m_pNext;
		if(pSlow == pFast) // Encounter, existence ring
			return true;
	}
	return false;
}

8. Judge whether two single linked lists intersect

If two linked lists intersect at a node, all nodes after the intersecting node are common to the two linked lists. In other words, if two linked lists intersect, the last node must be common. First traverse the first linked list, remember the last node, and then traverse the second linked list. When reaching the last node, compare it with the last node of the first linked list. If it is the same, it will intersect, otherwise it will not intersect. The time complexity is O(len1+len2), because only one additional pointer is needed to save the last node address, and the space complexity is O(1). Reference codes are as follows:

bool IsIntersected(ListNode * pHead1, ListNode * pHead2)
{
        if(pHead1 == NULL || pHead2 == NULL)
                return false;
 
	ListNode * pTail1 = pHead1;
	while(pTail1->m_pNext != NULL)
		pTail1 = pTail1->m_pNext;
 
	ListNode * pTail2 = pHead2;
	while(pTail2->m_pNext != NULL)
		pTail2 = pTail2->m_pNext;
	return pTail1 == pTail2;
}

9. Find the first node where two single linked lists intersect

Traverse the first linked list, calculate the length len1, and save the address of the last node.
Traverse the second linked list, calculate the length len2, and check whether the last node is the same as the last node of the first linked list. If not, it will not intersect and end.
Both linked lists start from the first node. Assuming len1 is greater than len2, the first linked list will traverse len1-len2 nodes. At this time, the distance between the current node of the two linked lists and the first intersection node will be equal, and then traverse backward together to know that the addresses of the two nodes are the same.
Time complexity, O(len1+len2). Reference codes are as follows:

ListNode* GetFirstCommonNode(ListNode * pHead1, ListNode * pHead2)
{
	if(pHead1 == NULL || pHead2 == NULL)
		return NULL;
 
	int len1 = 1;
	ListNode * pTail1 = pHead1;
	while(pTail1->m_pNext != NULL)
	{
		pTail1 = pTail1->m_pNext;
		len1++;
	}
 
	int len2 = 1;
	ListNode * pTail2 = pHead2;
	while(pTail2->m_pNext != NULL)
	{
		pTail2 = pTail2->m_pNext;
		len2++;
	}
 
	if(pTail1 != pTail2) // Disjoint returns NULL directly
		return NULL;
 
	ListNode * pNode1 = pHead1;
	ListNode * pNode2 = pHead2;
        // First align the current node of the two linked lists to make the distance from the tail node equal
	if(len1 > len2)
	{
		int k = len1 - len2;
		while(k--)
			pNode1 = pNode1->m_pNext;
	}
	else
	{
		int k = len2 - len1;
		while(k--)
			pNode2 = pNode2->m_pNext;
	}
	while(pNode1 != pNode2)
	{
		pNode1 = pNode1->m_pNext;
		pNode2 = pNode2->m_pNext;
	}
        return pNode1;
}

10. It is known that there is a ring in a single linked list. Find the first node in the ring

First, judge whether there is a ring. If there is no ring, it ends. Break at a node in the ring (of course, the original linked list cannot be destroyed at the end of the function), so as to form two intersecting single linked lists. Finding the first node in the ring will be transformed into the first node to find the intersection of two single linked lists. Reference codes are as follows:

ListNode* GetFirstNodeInCircle(ListNode * pHead)
{
	if(pHead == NULL || pHead->m_pNext == NULL)
		return NULL;
 
	ListNode * pFast = pHead;
	ListNode * pSlow = pHead;
	while(pFast != NULL && pFast->m_pNext != NULL)
	{
		pSlow = pSlow->m_pNext;
		pFast = pFast->m_pNext->m_pNext;
		if(pSlow == pFast)
			break;
	}
	if(pFast == NULL || pFast->m_pNext == NULL)
		return NULL;
 
	// Taking this node in the ring as the hypothetical tail node, it becomes the intersection problem of two single linked lists
	ListNode * pAssumedTail = pSlow; 
	ListNode * pHead1 = pHead;
	ListNode * pHead2 = pAssumedTail->m_pNext;
 
	ListNode * pNode1, * pNode2;
	int len1 = 1;
	ListNode * pNode1 = pHead1;
	while(pNode1 != pAssumedTail)
	{
		pNode1 = pNode1->m_pNext;
		len1++;
	}
	
	int len2 = 1;
	ListNode * pNode2 = pHead2;
	while(pNode2 != pAssumedTail)
	{
		pNode2 = pNode2->m_pNext;
		len2++;
	}
 
	pNode1 = pHead1;
	pNode2 = pHead2;
	// First align the current node of the two linked lists to make the distance from the tail node equal
	if(len1 > len2)
	{
		int k = len1 - len2;
		while(k--)
			pNode1 = pNode1->m_pNext;
	}
	else
	{
		int k = len2 - len1;
		while(k--)
			pNode2 = pNode2->m_pNext;
	}
	while(pNode1 != pNode2)
	{
		pNode1 = pNode1->m_pNext;
		pNode2 = pNode2->m_pNext;
	}
    return pNode1;
}

11. Give a single chain header pointer pHead and a node pointer pToBeDeleted, O(1) time complexity delete node pToBeDeleted

For deleting a node, our common idea is to make the previous node of the node point to the next node of the node. In this case, we need to traverse to find the previous node of the node, and the time complexity is O(n). For the linked list, the structure of each node in the linked list is the same, so we can copy the data of the next node of the node to the node, and then delete the next node. Pay attention to the last node. At this time, you can only use common methods to find the previous node first, but the overall average time complexity is O(1). Reference codes are as follows:

void Delete(ListNode * pHead, ListNode * pToBeDeleted)
{
	if(pToBeDeleted == NULL)
		return;
	if(pToBeDeleted->m_pNext != NULL)
	{
		pToBeDeleted->m_nKey = pToBeDeleted->m_pNext->m_nKey; // Copy the data of the next node to this node, and then delete the next node
		ListNode * temp = pToBeDeleted->m_pNext;
		pToBeDeleted->m_pNext = pToBeDeleted->m_pNext->m_pNext;
		delete temp;
	}
	else // The last node is to be deleted
	{
		if(pHead == pToBeDeleted) // There is only one node in the linked list
		{
			pHead = NULL;
			delete pToBeDeleted;
		}
		else
		{
			ListNode * pNode = pHead;
			while(pNode->m_pNext != pToBeDeleted) // The penultimate node was found
				pNode = pNode->m_pNext;
			pNode->m_pNext = NULL;
			delete pToBeDeleted;
		}	
	}
}

Topics: linked list