SListNode* reserve(SListNode*head)
{
//只有一个节点 或 链表为空
if (head == NULL || head->next == NULL)
return head;
SListNode* pre = NULL;
SListNode* cur = head;
SListNode* after=NULL;
//修改指针的指向即可
while (cur)
{
after = cur->next;
cur->next = pre;
pre = cur;
cur = after;
}
return pre;
}
SListNode* middlenode1(SListNode*head)
{
//奇数节点返回中间
//偶数返回中间的第二个节点
if (head == NULL || head->next == NULL)
return head;
SListNode*slow = head;
SListNode*fast = head;
while (fast)
{
if (fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
}
}
return slow;
}
分析:
起始 slow fast 位置,fast 每次走两步,slow每次走一步:
则:此时刚好奇数个节点,fast 达到最后一个节点时,slow 刚好停在中间节点的位置:
若有偶数个节点时:
此时,fast 到达 NULL 位置时,slow 刚好停在中间第二个节点位置:
SListNode* middlenode2(SListNode* head)
{
//奇数节点返回中间
//偶数返回中间的第一个节点
if (head == NULL || head->next == NULL)
return head;
SListNode*slow = head;
SListNode*fast = head;
SListNode* pre = NULL;
while (fast)
{
if (fast->next != NULL)
{
pre = slow;
slow = slow->next;
fast = fast->next->next;
}
}
if (fast)
return slow; //奇数个节点
else
return pre; //偶数个节点
}
分析:
起始位置的节点,pre 用来标记 slow 的前一个节点:
此时 ,fast !=NULL 时,slow 刚好是中间节点(即有奇数个节点时):
若有偶数个节点:
此时,pre 记录了 slow 的前一个节点位置,即偶数个节点的中间第一个节点位置:
SListNode* samenode(SListNode* list1, SListNode* list2)
{
if (list1 == NULL || list2 == NULL)
return NULL;
SListNode* cur1 = list1;
SListNode* cur2 = list2;
int count1 = 1, count2 = 1;
while (cur1->next != NULL)
{
count1++;
cur1 = cur1->next;
}
while (cur2->next != NULL)
{
count2++;
cur2 = cur2->next;
}
if (cur1 != cur2)
return NULL; //不相交
//相交
int gap = count1 - count2;
cur1 = list1; cur2 = list2;
if (gap > 0) {
while (gap--)
cur1 = cur1->next;
}
else {
while (gap++)
cur2 = cur2->next;
}
while (cur1 != cur2) {
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
分析:
单链表除了头节点和尾节点以外,其余节点有且仅有一个直接前驱节点和一个直接后继节点,因此两条相交链表相交的可能性有以下可能:
首先,找到两条链表的表尾节点,判断两个表尾节点是否为同一个节点,若是则两个链表相交,否则不交;
其次,判断两条链表长度是否相等,若相等则定义两个节点分别从两个链表头节点开始比对,找到第一个相同节点(不只是值相等)即为第一个交点,若不相等,则需要让较长的链表先走链表长度差值步,然后在统一向后比对寻找相同节点。
bool hasCycle(SListNode* head)
{
if (head == NULL || head->next == NULL)
return false;
SListNode* cur1 = head;
SListNode* cur2 = head;
while (cur2 && cur2->next) {
cur2 = cur2->next->next; //快指针每次走两步
cur1 = cur1->next; //满指针每次走一步
if (cur1 == cur2)
return true;
}
return false;
}
分析:
定义快慢指针,快指针每次走两步,慢指针每次走一步
SListNode* detectCycle(SListNode* head)
{
SListNode* fast = head;
SListNode* slow = head;
int cycle = 0;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) { //相遇点
cycle = 1;
break;
}
}
if (!cycle)
return NULL; //不带环
//带环,求入口点
SListNode* pH = head;
SListNode* pM = fast;
while (pH != pM) {
pH = pH->next;
pM = pM->next;
}
return pM;
}
分析:
首先需要分析链表中是否带环,其次寻找环的入口点:
假设环外长度为 L,环中从入口位置到相遇点距离为 X,环长度为 r
又因为 fast 与 slow 分别为快慢指针,fast 每次走两步,slow 每次走一步,因此 fast 走过的距离应为 slow 的两倍,故有如下关系:
(n 为自然常数,假设找到相遇点之前 fast 绕环行走了 nr 步,即转了 n 圈)
L+X+nr = 2*(L+X) ---------》 化简有:
nr=L+X ---------------> L= nr - X
说明定义一个 pH指针从链表头节点开始,一个指针 pM 从相遇点开始,每次分别前进一步,最终两个节点会在环的入口点相遇(因为走过的距离 L==nr - X 相等)
ps:博文内容为个人原创,有问题欢迎留言讨论呀~~