链表小结

本章主要内容如下:

* 带头结点的链表反转

* 不带头结点的链表反转

* 链表有环

1、  带头结点的链表反转

思路:遍历每个节点,将其插入到头结点跟第一个节点之间,使其成为新的第一节点,其他的相应后移,即可实现。复杂度O(n)

#include<stdio.h>
#include<stdlib.h>
struct ListNode
{
	int data;
	struct ListNode *next;
};

void Reverse(ListNode *pHead)
{
	ListNode *pCurrent = pHead->next;
	ListNode *pNext = NULL;
	pHead->next = NULL;

	while(pCurrent)
	{
		pNext = pCurrent->next;

		pCurrent->next = pHead->next;
		pHead->next = pCurrent;

		pCurrent = pNext;
	}

}

int main()
{

	ListNode *pList = (ListNode*)malloc(sizeof(ListNode));
	ListNode *pCurrent = pList;
	pCurrent->data = 0xffffffff;

	for(int i=0; i<10; i++)
	{
		ListNode *q =(ListNode*)malloc(sizeof(ListNode));
		q->data = i;
		pCurrent->next = q;
		pCurrent = q;

		printf("%d, ", pCurrent->data);
	}
	printf("\n");
	pCurrent->next = NULL;

	Reverse(pList);

	pCurrent = pList->next;
	while(pCurrent)
	{
		printf("%d, ", pCurrent->data);

		ListNode *p = pCurrent;
		pCurrent = pCurrent->next;

		free(p);
	} 

	free(pList);

	return 0;
}


2、  不带头结点的链表反转

#include<stdio.h>
#include<stdlib.h>
struct ListNode
{
	int data;
	struct ListNode *next;
};

void Reverse(ListNode *&pHead)
{

	ListNode *pCurrent = pHead;
	ListNode *pPrev = NULL;
	ListNode *pNext = NULL;

	while (pCurrent)
	{
		pNext = pCurrent->next;

		pCurrent->next = pPrev;

		pPrev = pCurrent;
		pCurrent = pNext;
	}

	pHead = pPrev;

}



int main()
{

	ListNode *pList = (ListNode*)malloc(sizeof(ListNode));
	ListNode *pCurrent = pList;
	pCurrent->data = 0;

	for(int i=1; i<10; i++)
	{
		ListNode *q =(ListNode*)malloc(sizeof(ListNode));
		q->data = i;
		pCurrent->next = q;
		pCurrent = q;
	}
	pCurrent->next = NULL;
    
	Reverse(pList);

	pCurrent = pList;
	while(pCurrent)
	{
		printf("%d, ", pCurrent->data);

		ListNode *p = pCurrent;
		pCurrent = pCurrent->next;

		free(p);
	} 

	return 0;
}


3、  链表有环

3.1如何判断有环?

方法:快慢指针,采用2个指针不同步数(步数小的每次1步,步数大的每次2步),步数大的如果能够与步数小的相遇则必然存在环。

bool hasCircle(ListNode *pHead)
{
	ListNode *slow = pHead;
	ListNode *fast = pHead;

	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;

		if (slow == fast)
			break;
	}

	return !(fast==NULL || fast->next==NULL);
}

3.2 如何查找环的的入口节点



假设,当二者此一次相遇时,其走过的路程关系是2*(a+b)=a+(b+c)*n+b, 其中n为快指针在环内转的圈数,则a=(b+c)*n-b.

这样,一个指针从头开始,另一个指针从相遇点开始,步长为1进行移动,二者的相遇点即是环的入口点

ListNode *findCircleIn(ListNode *pHead)
{
	ListNode *slow = pHead;
	ListNode *fast = pHead;

	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;

		if (slow == fast)
			break;
	}

	  if (fast == NULL || fast->next == NULL)        
		  return NULL;     

	  slow = pHead;     
	  while (slow != fast)     
	  {          
		  slow = slow->next;          
		  fast = fast->next;     
	  }     

	  return slow; 
}

3.3 计算环的长度

找到环的入口节点后,从入口节点遍历,再次回到入口节点,即可计算出环的长度

int findCircleIn(ListNode *pHead)
{
	ListNode *slow = pHead;
	ListNode *fast = pHead;

	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;

		if (slow == fast)
			break;
	}

	if (fast == NULL || fast->next == NULL)        
	  return 0;     

	slow = pHead;     
	while (slow != fast)     
	{          
	  slow = slow->next;          
	  fast = fast->next;     
	}     

	ListNode *p = slow->next;
	int length = 1;
	while (p != slow)
	{
	  length++;
	  p = p->next;
	}

	return length; 
}

4、两个单链表是否相交

http://blog.163.com/bbluesnow@126/blog/static/27784545201251051156817/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值