- 闭环的入口 方法一
- 判断链表是否有环
- 思想:可以设置快慢指针,快指针一次走两步,慢指针一次走一步,如果快指针追上了走的慢的指针,那么链表有环;
- 如果走到了链表尾部都没有追上,说明链表无环;
- 如果有环,返回入口节点
- 思想:返回的节点一定在环内,如果计算出环中节点的个数count,快指针比慢指针多走count步,那么两个指针相遇时,
- 就是环的入口节点。
- 步骤:
- 第一步:慢指针走一步,快指针走两步,计算单链是否有环?
- 第二步:如果没有环,则输出为空;如果有环,则计算环的个数n;
- 第三步:前指针向后移动n位, 再查找前指针与后指针是否相等,若相等,则位入口节点,反之。
- 闭环的入口 方法二
- a、第一步,找环中相汇点。分别用fast,slow指向链表头部,slow每次走一步,fast每次走二步,
- 直到fast==slow找到在环中的相汇点。
- b、第二步,找环的入口。接上步,当fast==slow时,fast所经过节点数为2x,slow所经过节点数为x,
- 设环中有n个节点,fast比slow多走r圈有2x=rn+x; x=rn;(r为圈数,n为一圈的结点数)
- 可以看出slow实际走了多个环的步数,再让fast指向链表头部,slow位置不变。
- 假设链表开头到环接口的距离是y,那么x-y表示slow指针走过的除链表开头y在环中走过的距离,
- 那么slow再走y步,此时fast结点与slow结点相遇,fast == slow ,x-y+y=x = rn,即此时slow指向环的入口。
- closedLoopList.h
#include <iostream>
struct ListNode {
int data;
struct ListNode * next;
ListNode(int x) : data(x), next(nullptr) {}
};
//基类链表
class BaseList {
public:
virtual ~BaseList() = default;
virtual ListNode *CreateClosedList() = 0;
virtual ListNode *ClosedLoopList(ListNode *pHead) = 0;
virtual int counterClosedLoopList(ListNode *pHead) = 0;
virtual void ShowClosedLoopList(ListNode *pHead) const = 0;
};
//实现基类的链表
class CompleteList : public BaseList {
public:
virtual ~CompleteList() = default;
ListNode *CreateClosedList() override;
ListNode *ClosedLoopList(ListNode *pHead) override;
int counterClosedLoopList(ListNode *pHead) override;
void ShowClosedLoopList(ListNode *pHead) const override;
};
class BaseClosedLoopList {
public:
virtual ~BaseClosedLoopList() = default;
virtual ListNode *EntryClosedLoopList(ListNode *pHead) = 0;
};
class CompleteClosedLoopListFirst : public BaseClosedLoopList {
public:
virtual ~CompleteClosedLoopListFirst() = default;
ListNode *EntryClosedLoopList(ListNode *pHead) override;
};
class CompleteClosedLoopListSecond : public BaseClosedLoopList {
public:
virtual ~CompleteClosedLoopListSecond() = default;
ListNode *EntryClosedLoopList(ListNode *pHead) override;
};
// 反转链表的模板
template <typename listtemplate="">
class CompleteClosedLoopListTemp {
public:
~CompleteClosedLoopListTemp() {}
ListNode *EntryClosedLoopList(ListNode *pHead) {
listTemplate.EntryClosedLoopList(pHead);
}
private:
ListTemplate listTemplate;
};</typename>
* closedLoopList.cpp ```c++ #include "closedLoopList.h" #include <vector> // 尾结点插入法创建链表 ListNode * CompleteList::CreateClosedList() { int num = 1; //unique_ptr<ListNode> pHead = make_unique<ListNode> (num); ListNode *pHead = new ListNode(num); ListNode *p = pHead; //尾结点插入法 for(int i = 2; i < 10; i++) { ListNode *q = new ListNode(i); p->next = q; //p节点插入listNode节点 p = p->next; // 向后移位 } p->next = pHead; return pHead; } /* * 是否为循环链表? * 思路:选2个节点,分别为慢节点和快节点,慢节点走一步,而快节点走两步,如果快节点能够追上慢节点,则此链表是闭环链表; * 如果快节点不能追上慢节点,则此链表是开环链表。 */ ListNode *CompleteList::ClosedLoopList(ListNode *pHead) { if (pHead == nullptr) { return nullptr; } ListNode * pSlowNode = pHead->next; if (pSlowNode == nullptr) { return nullptr; } ListNode * pFastNode = pSlowNode->next; while (pSlowNode != nullptr && pFastNode != nullptr) { if (pSlowNode == pFastNode) { return pFastNode; } pSlowNode = pSlowNode->next; pFastNode = pFastNode->next; if (pFastNode->next != nullptr) { pFastNode = pFastNode->next; } } return nullptr; } /* * 环链表的个数 * 思想:头节点与下一个节点进行比较,若不相等,则个数自加,且向下移位;若相等,则输出环链表的个数。 * 步骤: * 第一步:会面节点指向头节点,且链表个数为1; * 步骤二: 当头节点的下一个节点不等于会面节点,则个数自加且头节点向下移位; * 第三步:输出链表的个数 */ int CompleteList::counterClosedLoopList(ListNode *pHead) { if (pHead == nullptr) { return 0; } ListNode *pMeetNode = pHead; int count = 1; while (pHead->next != pMeetNode) { count++; pHead = pHead->next; } return count; } void CompleteList::ShowClosedLoopList(ListNode *pListNode) const { ListNode *pHeadNode = pListNode; for (int i = 0; i < 10; i++) { std::cout<<" "<<pHeadNode->data; pHeadNode = pHeadNode->next; } std::cout << std::endl; return; } /* * 闭环的入口 方法一 * 1. 判断链表是否有环 * 思想:可以设置快慢指针,快指针一次走两步,慢指针一次走一步,如果快指针追上了走的慢的指针,那么链表有环; * 如果走到了链表尾部都没有追上,说明链表无环; * 2. 如果有环,返回入口节点 * 思想:返回的节点一定在环内,如果计算出环中节点的个数count,快指针比慢指针多走count步,那么两个指针相遇时, * 就是环的入口节点。 * 步骤: * 第一步:慢指针走一步,快指针走两步,计算单链是否有环? * 第二步:如果没有环,则输出为空;如果有环,则计算环的个数n; * 第三步:前指针向后移动n位, 再查找前指针与后指针是否相等,若相等,则位入口节点,反之。 */ ListNode *CompleteClosedLoopListFirst::EntryClosedLoopList(ListNode *pHead) { if (pHead == nullptr || pHead->next == nullptr) { return nullptr; } CompleteList completeList; ListNode *pMeetNode = completeList.ClosedLoopList(pHead); if (pMeetNode == nullptr) { std::cout<<"the closed pHeadNode Node is null"<<std::endl; return nullptr; } else { std::cout<<"the closed pHeadNode Node is "<<pMeetNode->data<<std::endl; } int nums = completeList.counterClosedLoopList(pMeetNode); if (nums == 0) { std::cout<<"the nums of closed pHeadNode is zero"<<std::endl; return nullptr; } else { std::cout<<"the nums of closed pHeadNode is "<<nums<<std::endl; } ListNode *pFastNode = pHead; ListNode *pSlowNode = pHead; for (int i = 0; i < nums; i++) { pFastNode = pFastNode->next; } while (pFastNode != pSlowNode) { pFastNode = pFastNode->next; pSlowNode = pSlowNode->next; } return pFastNode; } /* * 闭环的入口 方法二 * a、第一步,找环中相汇点。分别用fast,slow指向链表头部,slow每次走一步,fast每次走二步, * 直到fast==slow找到在环中的相汇点。 * b、第二步,找环的入口。接上步,当fast==slow时,fast所经过节点数为2x,slow所经过节点数为x, * 设环中有n个节点,fast比slow多走r圈有2x=rn+x; x=rn;(r为圈数,n为一圈的结点数) * 可以看出slow实际走了多个环的步数,再让fast指向链表头部,slow位置不变。 * 假设链表开头到环接口的距离是y,那么x-y表示slow指针走过的除链表开头y在环中走过的距离, * 那么slow再走y步,此时fast结点与slow结点相遇,fast == slow ,x-y+y=x = rn,即此时slow指向环的入口。 */ ListNode *CompleteClosedLoopListSecond::EntryClosedLoopList(ListNode *pHead) { if (pHead == nullptr || pHead->next == nullptr) { return nullptr; } /* ListNode *pSlowNode = pHead; ListNode *pFastNode = pHead; while (pSlowNode != nullptr && pFastNode->next != nullptr) { pSlowNode = pSlowNode->next; pFastNode = pFastNode->next->next; if (pSlowNode == pFastNode) { pFastNode = pHead; while (pSlowNode != pFastNode) { pSlowNode = pSlowNode->next; pFastNode = pFastNode->next; } return pFastNode; } } */ ListNode *pSlowNode = pHead->next; ListNode *pFastNode = pSlowNode->next; while (pSlowNode != nullptr && pFastNode != nullptr) { pSlowNode = pSlowNode->next; pFastNode = pFastNode->next->next; // 当快指针 与 慢指针相遇时 if (pSlowNode == pFastNode) { pFastNode = pHead; // 当快指针 与 慢指针相遇时 while (pSlowNode != pFastNode) { pSlowNode = pSlowNode->next; pFastNode = pFastNode->next; } return pFastNode; } } return nullptr; } int main() { CompleteList completeList; std::vector<ListNode *> pCompleteNode; for(int i = 0; i < 4; i++) { ListNode *completeNodeTemp = completeList.CreateClosedList(); pCompleteNode.push_back(completeNodeTemp); } std::cout<<"CreateList1: "<<std::endl; completeList.ShowClosedLoopList(pCompleteNode[0]); completeList.ShowClosedLoopList(pCompleteNode[1]); CompleteClosedLoopListTemp<CompleteClosedLoopListFirst> completeClosedLoopListFirst; ListNode *pEntryNode1 = completeClosedLoopListFirst.EntryClosedLoopList(pCompleteNode[0]); if (pEntryNode1 == nullptr) { std::cout<<"the first entry node of closed pHeadNode is null"<<std::endl; } else { std::cout<<"the first entry node of closed pHeadNode is "<<pEntryNode1->data<<std::endl; } int num1 = 2; ListNode *pNewNode1 = new ListNode(num1); pNewNode1->next = nullptr; ListNode *pEntryNode1_2 = completeClosedLoopListFirst.EntryClosedLoopList(pNewNode1); if (pEntryNode1_2 == nullptr) { std::cout<<"the first entry node of closed pHeadNode is null"<<std::endl; } else { std::cout<<"the first entry node of closed pHeadNode is "<<pEntryNode1_2->data<<std::endl; } CompleteClosedLoopListTemp<CompleteClosedLoopListSecond> completeClosedLoopListSecond; ListNode *pEntryNode2 = completeClosedLoopListSecond.EntryClosedLoopList(pCompleteNode[1]); if (pEntryNode2 == nullptr) { std::cout<<"the second entry node of closed pHeadNode is null"<<std::endl; } else { std::cout<<"the second entry node of closed pHeadNode is "<<pEntryNode2->data<<std::endl; } int num2 = 3; ListNode *pNewNode2 = new ListNode(num2); pNewNode2->next = nullptr; ListNode *pEntryNode2_2 = completeClosedLoopListSecond.EntryClosedLoopList(pNewNode2); if (pEntryNode2_2 == nullptr) { std::cout<<"the second entry node of closed pHeadNode is null"<<std::endl; } else { std::cout<<"the second entry node of closed pHeadNode is "<<pEntryNode1_2->data<<std::endl; } return 1; }