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<stack>
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, ListNode*pNodeB)
{
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;
}