链表相关练习题

#include<iostream>
#include<stack>
#include<assert.h>
using namespace std;

typedef struct Node
{
	Node* _pNext;
	int _data;
}*PNode;


//初始化链表
void InitList(PNode* pHead)
{
	assert(pHead);
	*pHead = NULL;
}


//查找单链表的中间节点,只能遍历一次链表
//设置一个快指针和一个慢指针,当快指针到最后一个节点的时候
//慢指针的位置正好的中间节点
PNode FindMidNode(PNode pHead)
{
	PNode pSlow = pHead;
	PNode pFast = pHead;
	while (pFast && pFast->_pNext)
	{
		pSlow = pSlow->_pNext;
		pFast = pFast->_pNext->_pNext;
	}
	return pSlow;
}


//查找链表的倒数第k个节点,只能遍历一次链表
//定义一个快指针和一个慢指针,让快指针比慢指针先走k个节点,然后一起走
//快指针走到最后一个节点的时候慢指针的位置就是倒数第k个节点
PNode FindLastKNode(PNode pHead, size_t k)
{
	if (NULL == pHead || 0 == k)
		return NULL;

	PNode pFront = NULL;
	PNode pBack = NULL;

	while (--k)
	{
		if (NULL == pFront)
			return NULL;

		pFront = pFront->_pNext;
	}
	while (pFront)
	{
		pFront = pFront->_pNext;
		pBack = pBack->_pNext;
	}
	return pBack;
}

//删除链表的倒数第k个节点,只能遍历一次链表
void DeleteLastKNode(PNode* pHead, size_t k)
{
	assert(pHead);
	if (NULL == *pHead || 0 == k)
		return ;
	//找到第k个节点
	if (NULL == pHead || 0 == k)
		return ;

	PNode pFront = NULL;
	PNode pBack = NULL;

	while (k--)
	{
		if (NULL == pFront)
			return ;

		pFront = pFront->_pNext;
	}
	PNode pPreBack = NULL;
	while (pFront)
	{
		pFront = pFront->_pNext;
		pPreBack = pBack;
		pBack = pBack->_pNext;
	}

	//删除
	if (pBack == *pHead)
	{
		*pHead = (*pHead)->_pNext;
		delete pBack;
	}
	else
	{
		pPreBack->_pNext = pBack->_pNext;
		delete pBack;
	}

}

//判断单链表是否带环
//定义一个快指针一个慢指针,如果链表带环,快指针可以在一圈内追上慢指针
bool HasCircle(PNode pHead)
{
	PNode pFast = pHead;
	PNode pSlow = pHead;

	while (pFast&&pSlow->_pNext)
	{
		if (pFast == pSlow)
			return true;

		pFast = pFast->_pNext->_pNext;
		pSlow = pSlow->_pNext;
	} 
}


//求环的长度
//定义一个相遇节点,然后让链表往后走,定义一个计数++
//链表指针到达相遇节点的时候,count的数量就是节点数
int GetCircleLen(PNode pMeetNode)
{
	if (NULL == pMeetNode)
		return 0;

	int count = 1;
	PNode pCur = pMeetNode;
	while (pCur->_pNext != pMeetNode)
	{
		count++;
		pCur = pCur->_pNext;
	}
	return count;
}

//找环的入口节点
//思路参考公式
	PNode GetEnterNode(PNode pHead, PNode pMeetNode)
	{
		if (NULL == pHead || NULL == pMeetNode)
			return NULL;

		PNode pH = pHead;
		PNode pM = pMeetNode;

		while (pH != pM)
		{
			pH = pH->_pNext;
			pM = pM->_pNext;
		}
		return pM;
	}


//判断链表是否相交
	bool IsListCross(PNode pHead1, PNode pHead2)
	{
		if (NULL == pHead1 || NULL == pHead2)
			return false;

		PNode pLastNode1 = pHead1;
		while (pLastNode1->_pNext)
			pLastNode1 = pLastNode1->_pNext;

		PNode pLastNode2 = pHead2;
		while (pLastNode2->_pNext)
			pLastNode2 = pLastNode2->_pNext;

		if (pLastNode2 == pLastNode2)
			return true;

		return false;
	}


//求环的长度
	int Size(PNode pHead)
	{
		int count = 0;
		PNode pCur = pHead;
		while (pCur)
		{
			count++;
			pCur = pCur->_pNext;
		}
		return count;
	}

//求两个环的相交节点
	PNode GetCrossNode(PNode pHead1, PNode pHead2)
	{
		if (!IsListCross(pHead1, pHead2))
			return NULL;

		int len1 = Size(pHead1);
		int len2 = Size(pHead2);
		int gap = len1 - len2;

		PNode pCur1 = pHead1;
		PNode pCur2 = pHead2;
		//head1长
		if (gap >= 0)
		{
			while (gap--)
				pCur1 = pCur1->_pNext;
		}
		//head2长
		else
		{
			while (gap++)
				pCur2 = pCur2->_pNext;
		}
		while (pCur1 != pCur2)
		{
			pCur1 = pCur1->_pNext;
			pCur2 = pCur2->_pNext;
		}
		return pCur1;
	}


//逆序打印链表1 -> 2 -> 3 -> 4 -> NULL
//法一:递归,分情况:1.链表存在 2.链表不存在
/*void PrintListFromTail2Head(PNode pHead)
{
	if (pHead)
	{
		PrintListFromTail2Head(pHead->_pNext);
		cout << pHead->_data << "" << endl;
	}
	else
}*/

//法二:循环。栈:后进先出
void PrintListFromTail2Head(PNode pHead)
{
	if (NULL == pHead)
		return;

	stack<Node*> s;
	PNode pCur = pHead;
	while (pCur)
	{
		s.push(pCur);
		pCur = pCur->_pNext;
	}
	while (!s.empty())
	{
		pCur = s.top();
		cout << pCur << "";
		s.pop();
	}
}



//删除一个无头单链表的非尾结点(不能遍历链表)
//1->2->3->NULL  替换
void Delete(PNode pos,PNode pdel)
{
	assert(pos);
	pos->_data = pdel->_data;
	pos->_pNext = pdel->_pNext;
	delete pdel;
}




//在无头单链表的一个非头结点前插入一个结点(不能遍历链表)
void InsertNode(PNode pos)
{
	assert(pos);
	 PNode pNewNode = new Node;
	 pNewNode->_pNext = pos->_pNext;
	 pos->_pNext = pNewNode;
}


//头插
void PushFront(PNode pHead)
{
	PNode pNewNode = new Node;
	pNewNode->_pNext = pHead;
	pHead = pNewNode;
}


//返回最后一个结点
PNode Back(PNode pHead)
{
	if (NULL == pHead)
		return NULL;

	PNode pCur = pHead;
	while (pCur->_pNext)
		pCur = pCur->_pNext;

	return pCur;
}


//单链表实现约瑟夫环 1->2->3->4->5->6->NULL
PNode JosephCircle(PNode& pHead, int M)
{
	//把单链表构成环
	Back(pHead)->_pNext = pHead;
	Node* pCur = pHead;
	while (pCur->_pNext == pCur)
	{
		//1.报数
		while (--M)
			pCur = pCur->_pNext;
		//2.删除(替换法)
		PNode pDel = pCur->_pNext;
		pCur->_data = pDel->_data;
		pCur->_pNext = pDel->_pNext;
		delete pDel;
	}
	//解环
	pCur->_pNext = NULL;
	pHead = pCur;
	return pCur;
}




//逆置/反转单链表 1->2->3->4->NULL,三个指针
//法一:替换法
/*
PNode ReserverList(PNode& pHead)
{
	if (pHead == NULL || NULL == pHead->_pNext)
		return pHead;

	PNode pCur = pHead;
	PNode pCurPre = NULL;
	PNode pCurNext = pCur->_pNext;
	while (pCurNext)
	{
		pCur->_pNext = pCurPre;
		pCurPre = pCur;
		pCur = pCurNext;
		pCurNext = pCur->_pNext;
	}
	pCur->_pNext = NULL;
	pHead = pCur;
}
*/




//法二:构建一个新链表,让原来的链表头插进来
PNode ReserverList(PNode& pHead)
{
	PNode pNewNode = NULL;
	PNode pCur = pHead;
	PNode pCurNext = NULL;
	while (pCur)
	{
		pCurNext = pCur->_pNext;
		pCur->_pNext = pNewNode;
		pNewNode = pCur;
		pCur = pCurNext;
	}
	return pNewNode;
}




//冒泡排序
void BubbleSort(PNode pHead)
{
	if (pHead == NULL || NULL == pHead->_pNext)
		return;
	PNode pCur =NULL ;
	PNode pCurNext = NULL;
	PNode pTail = NULL;
	bool isChange = false;
	while (pHead != pTail)
	{
		while (pCurNext != pTail)
		{
			if (pCur->_data > pCurNext->_data)
			{
				swap(pCur->_data, pCurNext->_data);
				isChange = true;
			}
		} 
		pCur = pCurNext;
		pCurNext = pCur->_pNext;
	}
	pTail = pCur;
	if (!isChange)
		return;
}



//合并有序链表,合并后依然有序
PNode MergeList(PNode pHead1, PNode pHead2)
{
	//法一:
	if (pHead1 == NULL)
		return pHead2;
	if (pHead2 == NULL)
		return pHead1;
   //法二:
	/*
	if (NULL == pHead1 || NULL == pHead2)
		return (NULL == pHead1) ? pHead2 : pHead1;
		*/
	PNode pL1 = pHead1;
	PNode pL2 = pHead2;
	PNode pNewHead = NULL;
	PNode pTail = NULL;
	if (pL1->_data <= pL2->_data)
	{
		pNewHead = pL1;
		pTail = pNewHead;
		pL1 = pL1->_pNext;
	}
	while (pL1 && pL2)
	{
		if (pL1->_data <= pL2->_data)
		{
			pTail->_pNext = pL1;
			pL1 = pL1->_pNext;
		}
		else
		{
			pTail->_pNext = pL2;
			pL2 = pL2->_pNext;
		}
		pTail = pTail->_pNext;
	}
	if (pL1)
		pTail->_pNext = pL1;
	if (pL2)
		pTail->_pNext = pL2;
}




//递归逆向销毁链表
void Destroy(PNode& pHead)
{
	if (pHead)
	{
		Destroy(pHead->_pNext);
		delete pHead;
	}
}




//递归逆向查找元素是否存在
bool Find(PNode pHead, int data)
{
	if (pHead->_pNext)
	{
		while (pHead->_data == data)
		{
			pHead = pHead->_pNext;
		}
		return;
	}
}




int main()
{
	PNode pHead = NULL;
	InitList(&pHead);
	return 0;
}

链表作为数据结构中的重要部分,是算法训练中必不可少的练习内容。以下是一些经典的链表算法练习题及对应的解答思路和代码示例。 ### 反转链表 反转链表是一个基础问题,其核心在于调整链表中节点的指向。通过使用三个指针分别记录当前节点、前一个节点和后一个节点,可以实现链表的逐个反转。 ```c struct ListNode* reverseList(struct ListNode* head) { struct ListNode *prev = NULL; struct ListNode *current = head; while (current != NULL) { struct ListNode *nextTemp = current->next; current->next = prev; prev = current; current = nextTemp; } return prev; } ``` ### 判断链表是否有环 此问题可以通过快慢指针的方法解决。定义两个指针,一个每次移动一个节点(慢指针),另一个每次移动两个节点(快指针)。如果链表中存在环,则两个指针最终会相遇;否则,快指针将遇到空节点[^2]。 ```c bool hasCycle(struct ListNode *head) { struct ListNode *slow = head; struct ListNode *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) { return true; } } return false; } ``` ### 分割链表 分割链表的问题要求将链表按照特定值分成两部分,一部分小于该值,另一部分大于或等于该值。解决这个问题的一种方法是创建两个带头节点的链表,分别用于存储小于和大于等于目标值的节点,最后将两个链表合并[^3]。 ```c struct ListNode* partition(struct ListNode* head, int x) { struct ListNode lessHead, greaterHead; struct ListNode *lessTail = &lessHead; struct ListNode *greaterTail = &greaterHead; while (head) { if (head->val < x) { lessTail->next = head; lessTail = lessTail->next; } else { greaterTail->next = head; greaterTail = greaterTail->next; } head = head->next; } greaterTail->next = NULL; lessTail->next = greaterHead.next; return lessHead.next; } ``` ### 删除链表中的重复元素 删除链表中的重复元素需要遍历链表,并检查当前节点与下一个节点的值是否相同。如果相同,则跳过下一个节点;如果不相同,则继续遍历。 ```c struct ListNode* deleteDuplicates(struct ListNode* head) { struct ListNode *current = head; while (current && current->next) { if (current->val == current->next->val) { struct ListNode *temp = current->next; current->next = temp->next; free(temp); } else { current = current->next; } } return head; } ``` ### 合并两个有序链表 合并两个有序链表的目标是将它们合并成一个新的有序链表。可以通过比较两个链表的节点值,依次选择较小的节点插入到新链表中。 ```c struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) { struct ListNode dummy; struct ListNode *tail = &dummy; while (l1 && l2) { if (l1->val < l2->val) { tail->next = l1; l1 = l1->next; } else { tail->next = l2; l2 = l2->next; } tail = tail->next; } tail->next = l1 ? l1 : l2; return dummy.next; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值