1、从链表的末尾添加节点
2、删除链表节点
3、链表中倒数第K个节点
4、反转链表
5、从尾到头打印链表
6、合并两个排序的链表
7、两个链表的第一个公共节点
8、判断两个链表是否有环相关问题
struct ListNode
{
int m_data;
ListNode *m_pNext;
};
一、从链表的末尾添加节点:
ListNode *AddToTail(ListNode**pHead, int data)
{
//创建新节点将数据保存下来
ListNode *pNew = new ListNode();
pNew->m_data = data;
pNew->m_pNext = NULL;
//头节点为空,则指向新节点,组成有一个节点的链表
if (*pHead == NULL)
{
*pHead = pNew;
}
else
{
//链表有部分数据的的话,定义指向头节点的指针偏移到链表的尾部
ListNode *pNode = *pHead;
while (pNode->m_pNext != NULL)
{
pNode = pNode->m_pNext;
}
//在链表的尾部连接上新的节点
pNode->m_pNext = pNew;
}
return *pHead; //返回整条链表
}
二、删除链表节点:
ListNode *RemoveNode(ListNode **pHead, int data)
{
if (*pHead == NULL || pHead == NULL)
return NULL;
ListNode *pBeDelNode = NULL;
if ((*pHead)->m_data == data)
{
pBeDelNode = *pHead;
*pHead = (*pHead)->m_pNext;
}
else
{
ListNode *pNode = *pHead;
while (pNode->m_pNext != NULL && pNode->m_pNext->m_data != data)
{
pNode = pNode->m_pNext;
}
if (pNode->m_pNext != NULL && pNode->m_pNext->m_data == data)
{
pBeDelNode = pNode->m_pNext;
pNode->m_pNext = pNode->m_pNext->m_pNext;
}
}
if (pBeDelNode->m_pNext != NULL)
{
delete pBeDelNode;
pBeDelNode = NULL;
}
}
三、找链表中倒数第K个节点
//为了能够只遍历一次就能找到倒数第k个节点,可以定义两个指针:
//(1)第一个指针从链表的头指针开始遍历向前走k - 1,第二个指针保持不动;
//(2)从第k步开始,第二个指针也开始从链表的头指针开始遍历;
//(3)由于两个指针的距离保持在k - 1,当第一个(走在前面的)指针到达链表的尾结点时,第二个指针(走在后面的)指针正好是倒数第k个结点。
ListNode *Find_K_Node(ListNode *pHead, int k)
{
if (pHead == NULL || k <= 0)
return NULL;
ListNode *pAhead = pHead;
ListNode *pBhend = pHead;
int i = 0;
for (int i = 0; i < (k - 1); i++)
{
if (pAhead->m_pNext == NULL)
return NULL;
pAhead = pAhead->m_pNext;
}
while (pAhead->m_pNext != NULL)
{
pAhead = pAhead->m_pNext;
pBhend = pBhend->m_pNext;
}
return pBhend;
}
四、反转链表
//思路 这个博主讲的很清晰,这里不再复述,链接:https://www.cnblogs.com/GODYCA/archive/2012/12/27/2835185.html
1、迭代方法:
ListNode* ReverseNode(ListNode *pHead)
{
if (pHead == NULL)
return NULL ;
if (pHead->m_data == NULL)
return NULL ;
ListNode *pCurrNode = pHead;
ListNode *RetNode = NULL;
while (pCurrNode != NULL)
{
ListNode *pTemNode = pCurrNode->m_pNext; //指向当前节点的下一节点
pCurrNode->m_pNext = RetNode; //当前节点指向前一个节点
RetNode = pCurrNode; //前一节点指向当前节点
pCurrNode = pTemNode; //当前节点指向下一节点
}
return RetNode;
}
2、递归方法
ListNode ReverseNode2(ListNode pNode)
{
ListNode *pPerNode = pNode;
if (pNode->m_pNext == NULL)
return pNode;
else
{
ReverseNode2(pNode->m_pNext);
pNode->m_pNext->m_pNext = pNode;
if (pNode == pPerNode)
pPerNode->m_pNext = NULL;
}
}
五、从尾到头打印链表
//思路:利用栈的特性,先进先出,后进后出。从头到尾部遍历链表保存到栈中,再从栈顶开始输出值
#include
void PrintListNode(ListNode pNode)
{
std::stack<ListNode>Node;
ListNode*pTemNode = pNode;
while (pTemNode != NULL)
{
Node.push(pTemNode);
pTemNode = pTemNode->m_pNext;
}
while (!Node.empty())
{
pTemNode = Node.top();
cout << pTemNode->m_data << endl;
Node.pop();
}
}
六、合并两个排序的链表
//该算法与将两个有序的数组合并是同一个思想
ListNode *MergeNode(ListNode pNodeA, ListNodepNodeB)
{
if (pNodeA == NULL || pNodeB == NULL)
return NULL;
ListNode *NewNode = new ListNode();
ListNode *RetNode = NewNode;
while (pNodeA != NULL && pNodeB != NULL)
{
if (pNodeA->m_data < pNodeB->m_data)
{
NewNode = pNodeA;
pNodeA = pNodeA->m_pNext;
}
else
{
NewNode = pNodeB;
pNodeB = pNodeB->m_pNext;
}
NewNode = NewNode->m_pNext;
}
//其中一个还有剩余字节的链表接在新链表的后面就可以了
if (pNodeA != NULL)
NewNode->m_pNext = pNodeA;
if (pNodeB != NULL)
NewNode->m_pNext = pNodeB;
return NewNode;
}
七、两个链表的第一个公共节点
1、借助栈的特性,从尾部到头开始比较节点是否相同,相同则把栈顶弹出,接着比较下一节点直到找到最后一个公共节点。
2、不借助外部空间法:先分别遍历两个链表的长度, 找出长的链表,并计算长表链表比短的链表长是多少,然后将长链表走两个链表长度的差,然后再一起向后遍历找到相同的点。
int GetNodeLen(ListNode *pNode)
{
int len = 0;
ListNode *pTemNode = pNode;
while (pTemNode!= NULL)
{
pTemNode = pTemNode->m_pNext;
len++;
}
return len;
}
ListNode *FindFirstCommonNode(ListNode *pNodeA, ListNode *pNodeB)
{
int lenA = GetNodeLen(pNodeA);
int lenB = GetNodeLen(pNodeB);
int diff = lenA - lenB;
ListNode *NodeLong = NULL;
ListNode *NodeShort = NULL;
if (diff > 0)
{
NodeLong = pNodeA;
NodeShort = pNodeB;
}
else
{
diff = lenB - lenA;
NodeLong = pNodeB;
NodeShort = pNodeA;
}
for (int i = 0; i < diff; i++)
NodeLong = NodeLong->m_pNext;
while (NodeLong != NULL && NodeShort != NULL && NodeLong->m_data != NodeShort->m_data)
{
NodeLong = NodeLong->m_pNext;
NodeShort = NodeShort->m_pNext;
}
ListNode *commentNode = NodeLong;
//ListNode *commentNode = NodeShort; //或
return commentNode;
}
八、判断链表是否有环相关问题
1、判断是否又环
bool FindLoopNode(ListNode *pNode)
{
if (pNode == NULL)
return NULL;
ListNode *pFast, *pSlow;
pFast = pSlow = pNode;
while (pSlow != NULL && pFast->m_pNext != NULL)
{
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext->m_pNext;
if (pSlow == pSlow)
return true;
}
return false;
}
2、找到环的入口点 ,详细思路请见链接:https://www.cnblogs.com/dancingrain/p/3405197.html
ListNode* getLoopNode(ListNode *pNode)
{
if (pNode == NULL)
return NULL;
ListNode *pFast, *pSlow;
pFast = pSlow = pNode;
while (pSlow != NULL && pFast->m_pNext != NULL)
{
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext->m_pNext;
if (pSlow == pSlow)
break;
}
if (pSlow == NULL || pFast == NULL)
return NULL;
pSlow = pNode;
while (pSlow != pFast)
{
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext;
}
return pSlow;
}