数据结构(C语言)2.线性表——单链表

本文介绍了单链表的基本操作,包括创建、删除、查找等,并详细解释了如何解决链表中的常见问题,如寻找中间节点、判断回文结构、查找相交节点等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.单链表的实现

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLTDateType;

typedef struct SListNode
{
	SLTDateType data;
	struct SlistNode* next;
}SLTNode;

SLTNode* BuyListNode(SLTDateType x);  //开辟新节点
void SListPrint(SLTNode* phead);      //打印
void SListPushBack(SLTNode** pphead, SLTDateType x); //尾插
void SListPushFront(SLTNode** pphead, SLTDateType x);  //头插
void SListPopBack(SLTNode** pphead); //尾删
void SListPopfront(SLTNode** pphead); //头删
SLTNode* SListFind(SLTNode* phead, SLTDateType x); //查询&修改
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);//在pos位置之前去插入一个节点
void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDateType x);//在pos位置后面去插入一个节点
void SListErase(SLTNode** pphead, SLTNode* pos); // 在pos指定位置删除数据
void SListEraseAfter(SLTNode* pos); // 在pos指定位置后面删除数据
void SListDestroy(SLTNode** pphead);//销毁

​​​​​​​

#include "SList.h"

//开辟新节点
SLTNode* BuyListNode(SLTDateType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

//打印
void SListPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//尾插
void SListPushBack(SLTNode** pphead, SLTDateType x)
{
	//动态开辟新节点的内存
	SLTNode* newnode = BuyListNode(x);
	
	//如果头节点为空指针,直接将新节点赋值
	//如果phead为一级指针,对phead的赋值是形参赋值,对实参plist不影响,plist仍为空,导致后面代码无法实现
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}

	//找尾
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}

}

//头插
void SListPushFront(SLTNode** pphead, SLTDateType x)
{
	SLTNode* newnode = BuyListNode(x);

	newnode->next = *pphead;
	*pphead = newnode;
}

//尾删
void SListPopBack(SLTNode** pphead)
{
	////温柔方式
	//if (*pphead == NULL)
	//{
	//	return;
	//}

	//粗暴方式
	assert(*pphead != NULL);

	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}

	else
	{
		// 方法一
		SLTNode* tail = *pphead;
		SLTNode* prev = NULL;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;

		prev->next = NULL;

		//方法二
		/*SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail);
		tail->next = NULL;*/
	}
}

//头删
void SListPopfront(SLTNode** pphead)
{
	assert(*pphead != NULL);
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

//查找
SLTNode* SListFind(SLTNode* phead, SLTDateType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}

//在pos位置之前去位置插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	SLTNode* newnode = BuyListNode(x);
	SLTNode* posPrev = *pphead;
	if (*pphead == pos)//头插
	{
		newnode->next = *pphead;
		*pphead = newnode;
	}
	else
	{
		//找到pos的前一个位置
		while (posPrev->next != pos)
		{
			posPrev = posPrev->next;
		}
		posPrev->next = newnode;
		newnode->next = pos;
	}
}

//在pos位置后面去插入一个节点,更适合单链表,也更简单
void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	SLTNode* newnode = BuyListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

//在pos指定位置删除数据
void SListErase(SLTNode** pphead, SLTNode* pos)
{
	SLTNode* cur = *pphead;

	if (*pphead == pos)//头删
	{
		*pphead = pos->next;
		free(pos);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

// 在pos指定位置后面删除数据
void SListEraseAfter(SLTNode* pos)
{
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
	next = NULL;
}

//销毁
void SListDestroy(SLTNode** pphead) 
{
	SLTNode* cur = *pphead;
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}
#include"SList.h"

void TestSList1()
{
	SLTNode* plist = NULL; //链表为空
	SListPushBack(&plist, 1);//尾插
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 4);

	SListPrint(plist);

	SListPushFront(&plist, 1);//头插
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);

	SListPrint(plist);
}

void TestSList2()
{
	SLTNode* plist = NULL; //链表为空
	
	SListPushFront(&plist, 1);//头插
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);

	SListPrint(plist);

	SListPopBack(&plist);//尾删
	SListPrint(plist);
}

void TestSList3()
{
	SLTNode* plist = NULL; //链表为空

	SListPushFront(&plist, 1);//头插
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);

	SListPrint(plist);

	SListPopfront(&plist);//头删
	SListPrint(plist);

	SListPopfront(&plist);
	SListPrint(plist);

	SListPopfront(&plist);
	SListPrint(plist);

	SListPopfront(&plist);
	SListPrint(plist);
}

void TestSList4()
{
	SLTNode* plist = NULL; //链表为空

	SListPushFront(&plist, 1);//头插
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 4);

	SListPrint(plist);

	//找
	SLTNode* pos = SListFind(plist, 2);
	int i = 0;
	while (pos)
	{
		printf("第%d个pos节点:%p->%d\n", ++i, pos, pos->data);
		pos = SListFind(pos->next, 2);

	}

	//修改 3->30
	pos = SListFind(plist, 3);
	if (pos)
	{
		pos->data = 30;
	}

	SListPrint(plist);
}

void TestSList5()
{
	SLTNode* plist = NULL; //链表为空

	SListPushFront(&plist, 1);//头插
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 4);

	SListPrint(plist);

	SLTNode* pos = SListFind(plist, 3);
	if (pos)
	{
		SListInsert(&plist, pos, 30);//在3的前面插入30
	}

	SListPrint(plist);
}

int main()
{
	//TestSList1();
	//TestSList2();
	//TestSList3();
	//TestSList4();
	TestSList5();

	return 0;
}

2.移除链表中某些元素,并返回新的头节点

#include <stdio.h>
#include <stdlib.h>

struct ListNode
{
	int data;
	struct ListNode* next;
};

struct ListNode* removeElements(struct ListNode* head,int val)
{
	struct ListNode* prev=NULL;
	struct ListNode* cur=head;
	while(cur)
	{
		if(cur->data==val)
		{
			if(cur==head)
			{
				head=cur->next;
				free(cur);
				cur=head;
			}
			else
			{
				//删除 
			    prev->next=cur->next;
			    free(cur);
			    cur=prev->next;
			}
		}
		else
		{
			//往后走
			prev=cur;
			cur=cur->next; 
		}
	}
	return head;
}

int main()
{
	//快速创建链表,方便调试 
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=7;
	n2->data=7;
	n3->data=7;
	n4->data=7;
	
	n1->next=n2;
	n2->next=n3;
	n3->next=n4;
	n4->next=NULL;
	
	struct ListNode* head=removeElements(n1,7);
	printf("%p",head);
	
	return 0;
}

3.翻转链表

#include<stdio.h>
#include<stdlib.h>

struct ListNode
{
	int data;
	struct ListNode* next;
};

//方法一 
struct ListNode* reverseList(struct ListNode* head)
{
	if(head==NULL)
	{
		return NULL;
	}
	else
	{
	
	    struct ListNode* n1=NULL;
	    struct ListNode* n2=head;
	    struct ListNode* n3=head->next;
	
	    while(n2!=NULL)
	    {
		    //翻转 
		    n2->next=n1;
		
		    //迭代往后走 
		    n1=n2;
		    n2=n3;
		    if(n3!=NULL)
		    {
			    n3=n3->next;
		    }
	    }
	    return n1;
	}
 } 
// 


////方法二
//struct ListNode* reverseList(struct ListNode* head)
//{
//	struct ListNode* cur=head;
//	struct ListNode* newHead=NULL;
//	
//	while(cur)
//	{
//		struct ListNode* next=cur->next;
//		//头插
//		cur->next=newHead;
//		newHead=cur;
//		
//		//迭代
//		cur=next; 
//	}
//	return newHead;
//}
 

int main()
{
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=1;
	n2->data=2;
	n3->data=3;
	n4->data=4;
	
	n1->next=n2;
	n2->next=n3;
	n3->next=n4;
	n4->next=NULL;
	
	//翻转前 
	struct ListNode* cur=n1;
	while(cur)
	{
		printf("%d->",cur->data);
		cur=cur->next;
	}
	printf("NULL\n");
	
	//翻转后 
	cur=reverseList(n1);
	while(cur)
	{
		printf("%d->",cur->data);
		cur=cur->next;
	}
	printf("NULL\n");
	
	return 0;
} 

4.找到非空链表的中间节点,若有两个返回第二个

#include<stdio.h>
#include<stdlib.h>

struct ListNode
{
	int data;
	struct ListNode* next;
};

struct ListNode* middleNode(struct ListNode* head)
{
	struct ListNode* slow=head; //fast速度是slow的两倍,fast走到末尾,slow刚好走到中间 
	struct ListNode* fast=head;
	
	while(fast&&fast->next)    // 1 2 3 4 5(fast)
	                           // 1(fast1) 2 3(fast2) 4 5(fast3) 6 NULL(fast4)
	{
		slow=slow->next;
		fast=fast->next->next;
	}
	return slow;
}

int main()
{
	//快速创建链表,方便调试
	
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=1;
	n2->data=2;
	n3->data=3;
	n4->data=4;
	
	n1->next=n2;
	n2->next=n3;
	n3->next=n4;
	n4->next=NULL;
	
	printf("%d\n",middleNode(n1)->data);
	
	return 0;
} 

5.找到链表中倒数第K个节点

#include<stdio.h>
#include<stdlib.h>

struct ListNode
{
	int data;
	struct ListNode* next;
};

//1.fast先走K步
//2.slow和fast再一起走,fast==NULL时,slow就是倒数第K个 
struct ListNode* FindKthToTail(struct ListNode* head,int k)
{
	struct ListNode* fast=head;
	struct ListNode* slow=head;
	int i=k;
	while(i--) //k步 
	{
		//K大于链表长度 
		if(fast==NULL)
		{
			return NULL;
		}
		fast=fast->next;
	}
	while(fast)
	{
		slow=slow->next;
		fast=fast->next;
	}
	return slow;
}

int main()
{
	//快速创建链表,方便调试
	
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=1;
	n2->data=2;
	n3->data=3;
	n4->data=4;
	
	n1->next=n2;
	n2->next=n3;
	n3->next=n4;
	n4->next=NULL;
	
	printf("%d\n",FindKthToTail(n1,3)->data);
	
	return 0;
} 

6.合并两个升序链表得到新的升序链表

#include <stdio.h>
#include <stdlib.h>

//思路:依此比较链表中的节点,每次取小的节点,尾插到新的链表 

struct ListNode
{
	int data;
	struct ListNode* next;
};

struct ListNode* mergeTwoLists(struct ListNode* l1,struct ListNode* l2)
{
	//如果其中一个为空,返回另一个 
	if(l1==NULL)
	{
		return l2;
	}
	
	if(l2==NULL)
	{
		return l1;
	}
	
	struct ListNode* head=NULL;
	struct ListNode* tail=NULL;
	
	//设置哨兵位
	//多一个哨兵位的头节点,这个节点不存储有效数据 
	head=tail=(struct ListNode*)malloc(sizeof(struct ListNode)); 
	
	
	while(l1&&l2)
	{
		if(l1->data<l2->data)
		{
//			if(head==NULL)
//			{
//				head=tail=l1;
//			}
			//else
			{
				tail->next=l1;
				tail=tail->next;
			}
			l1=l1->next;
		}
		else
		{
//			if(head==NULL)
//			{
//				head=tail=l2;
//			}
			//else
			{
				tail->next=l2;
				tail=tail->next;
			}
			l2=l2->next;
		}
	}
	if(l1)//若L1没结束 
	{
		tail->next=l1;
	}
	if(l2)
	{
		tail->next=l2;
	}
	//return head;
	struct ListNode* list=head->next;
	free(head);
	return list; 
} 

int main()
{
	//快速创建链表,方便调试
	
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=1;
	n2->data=2;
	n4->data=4;
	
	n1->next=n2;
	n2->next=n4;
	n4->next=NULL;
	
	
	struct ListNode* m1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* m2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* m3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* m4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	m1->data=1;
	m2->data=3;
	m4->data=4;
	
	m1->next=m2;
	m2->next=m4;
	m4->next=NULL;
	
	struct ListNode* cur=NULL;
	cur=mergeTwoLists(n1,m1);
	while(cur)
	{
		printf("%d->",cur->data);
		cur=cur->next;
	}
	printf("NULL\n");
	return 0;
}

7.分割链表

#include<stdio.h>
#include<stdlib.h>

//给定数值X,将小于X的节点排在其他节点之前,且不能改变原来的数据顺序 

struct ListNode
{
	int data;
	struct ListNode* next;
};

ListNode* Partition(ListNode* pHead,int x)
{
	struct ListNode* lessHead=NULL;
	struct ListNode* lessTail=NULL;
	//开一个哨兵位头节点,方便尾插 
	lessHead=lessTail=(struct ListNode*)malloc(sizeof(struct ListNode));
	lessTail->next=NULL;
	
	struct ListNode* greaterHead=NULL;
	struct ListNode* greaterTail=NULL;
	//开一个哨兵位头节点,方便尾插 
	greaterHead=greaterTail=(struct ListNode*)malloc(sizeof(struct ListNode));
	greaterTail->next=NULL;
	
	struct ListNode* cur=pHead;
	while(cur)
	{
		if(cur->data<x)
		{
			lessTail->next=cur;
			lessTail=cur;
		}
		else
		{
			greaterTail->next=cur;
			greaterTail=cur;
		}
		cur=cur->next;
	}
	lessTail->next=greaterHead->next;
	greaterTail->next=NULL;//否则可能是环形 
	
	struct ListNode* list=lessHead->next;
	//free(lessHead);
	//free(greaterHead);
	
	return list;
}

int main() 
{
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=2;
	n2->data=3;
	n3->data=1;
	n4->data=4;
	
	n1->next=n2;
	n2->next=n3;
	n3->next=n4;
	n4->next=NULL;
	
	struct ListNode* cur=NULL;
	cur=Partition(n1,3);
	while(cur)
	{
		printf("%d->",cur->data);
		cur=cur->next;
	}
	printf("NULL\n");
	return 0;
}

8.判断链表是否是回文结构

#include<stdio.h>
#include<stdlib.h>

struct ListNode
{
	int data;
	struct ListNode* next;
};

//翻转 
struct ListNode* reverseList(struct ListNode* head)
{
	struct ListNode* cur=head;
	struct ListNode* newHead=NULL;
	
	while(cur)
	{
		struct ListNode* next=cur->next;
		//头插
		cur->next=newHead;
		newHead=cur;
		
		//迭代
		cur=next; 
	}
	return newHead;
}

//找到中间节点 
struct ListNode* middleNode(struct ListNode* head)
{
	struct ListNode* slow=head; //fast速度是slow的两倍,fast走到末尾,slow刚好走到中间 
	struct ListNode* fast=head;
	
	while(fast&&fast->next)    // 1 2 3 4 5(fast)
	                           // 1(fast1) 2 3(fast2) 4 5(fast3) 6 NULL(fast4)
	{
		slow=slow->next;
		fast=fast->next->next;
	}
	return slow;
}

bool PalindromeList(ListNode* A)
{
	struct ListNode* mid=middleNode(A);
	struct ListNode* rHead=reverseList(mid);
	struct ListNode* curA=A;
	struct ListNode* curR=rHead;
	
	while(curA&&curR)
	{
		if(curA->data!=curR->data)
		{
			return false;
		}
		else
		{
			curA=curA->next;
			curR=curR->next;
		}
	}
	return true;
 } 

int main()
{
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=2;
	n2->data=3;
	n3->data=3;
	n4->data=2;
	
	n1->next=n2;
	n2->next=n3;
	n3->next=n4;
	n4->next=NULL;
	
	bool PalindromeList(n1);
	
	return 0;
 } 

9.找到两个链表相交节点

#include <stdio.h>
#include <stdlib.h>

struct ListNode
{
	int data;
	struct ListNode* next;
}; 


//尾节点相同就是相交,否则就是不相交
//求交点: 长的链表先走(长度差)步,再同时走,第一个相同就是交点
// 1 2 3
//      7 8
//   4 5
struct ListNode* getIntersectionNode(struct ListNode* headA,struct ListNode* headB)
{
	struct ListNode* tailA=headA;
	struct ListNode* tailB=headB;
	int lenA=1;
	int lenB=1;
	while(tailA->next)
	{
		++lenA;
		tailA=tailA->next;
	} 
	while(tailB->next)
	{
		++lenB;
		tailB=tailB->next;
	} 
	
	//不相交 
	if(tailA!=tailB)
	{
		return NULL;
	}
	//求差
	//abs求绝对值 
	int gap=abs(lenA-lenB);
	//长的链表先走(长度差)步,再同时走找交点 
	struct ListNode* longList=headA;
	struct ListNode* shortList=headB;
	if(lenA<lenB)
	{
		shortList=headA;
		longList=headB;
	}
	while(gap--)
	{
		longList=longList->next;
	}
	while(longList!=shortList)
	{
		longList=longList->next;
		shortList=shortList->next;
	}
	return longList;
} 

int main()
{
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=1;
	n2->data=2;
	n3->data=3;
	n4->data=4;
	
	n1->next=n2;
	n2->next=n3;
	n3->next=n4;
	n4->next=NULL;
	
	struct ListNode* m1=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	m1->data=5;
	
	m1->next=n3;

	
	printf("%d\n",getIntersectionNode(n1,m1)->data);

	
	return 0;
}

10.判断链表中是否有环

#include <stdio.h>
#include <stdlib.h>

struct ListNode
{
	int data;
	struct ListNode* next;
}; 


//快慢指针
//slow和fast指向链表的开始
//slow一次走一步
//fast一次走两步
//不带环,fast会指向空
//带环,fast会追上slow,再次相遇 
bool hasCycle(struct ListNode* head)
{
	struct ListNode* fast=head;
	struct ListNode* slow=head;
	while(fast&&fast->next)
	{
		fast=fast->next->next;
		slow=slow->next;
		if(fast==slow)
		{
			return true;
		}
	}
	return false;
} 

int main()
{
	struct ListNode* n1=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n2=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n3=(struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* n4=(struct ListNode*)malloc(sizeof(struct ListNode));
	
	n1->data=1;
	n2->data=2;
	n3->data=3;
	n4->data=4;
	
	n1->next=n2;
	n2->next=n3;
	n3->next=n4;
	n4->next=NULL;
	
	hasCycle(n1);
	
	return 0;
}

11.单链表带环问题,延申问题

单链表带环问题

解法思路:快慢指针,slow和fast同时指向链表头部

          Slow每次走一步

          Fast每次走两步

          有环,Slow和fast会在环中相遇

          无环,则fast或fast->next指向空

延伸问题:

  1. 为什么Slow每次走一步,Fast每次走两步的情况,它们一定会在环中相遇?会不会在环中错过,永远遇不上?请证明。

结论:带环一定会相遇

分析证明:

       第一步:slow和fast,fast一定先进环,此时slow走了入环前距离的一半。

       第二步:随着slow进环,fast已经在环中走了一段路程,路程大小与环的大小有关

              假设slow进环的时候,slow与fast的距离是N

(fast追slow的距离)

  Slow每次向前走一步,fast向前走两步,每追一次,fast和slow的距离变化为N-1,N-2,……,1,0

  每追一次,fast和slow的距离-1,它们之间的距离减到0的时候就是相遇的点。

  1. 为什么slow走一步,fast一定要走两步,可不可以走n步(n>=2)?请证明。

结论:fast一次走n步(n>=2),不一定相遇

分析证明:

       假设:slow走一步,fast走三步,slow进环的时候,slow与fast的距离是N(fast追slow的距离)

            它们之间的距离变化:N,N-2,N-4,N-6,……

               如果N是偶数就能追上

               如果N是奇数,这次追不上,此时它们之间的距离变为C-1(C为环长,fast追slow的距离)

                如果C-1是奇数,就永远追不上,追到后面还是相距C-1

                如果C-1是偶数,就能追上

       slow走一步,fast走N步,证明类似。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值