C++关于链表操作

本文介绍了链表的基本操作,包括如何从链表末尾添加节点、删除指定节点、找到倒数第K个节点、反转整个链表、从尾到头打印链表元素,以及合并两个已排序的链表。此外,还讨论了如何判断链表中是否存在环并找到环的入口节点。这些操作都是通过迭代和递归方法实现的,适用于链表数据结构的常见问题解决。
摘要由CSDN通过智能技术生成

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值