方法一:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct node_t
{
struct node_t *next;
int data;
}node_t;
node_t * Getlink(node_t *head, int *group, int count)
{
int cout = count;
int *pgroup = group;
node_t *new_node = NULL;
node_t *ptr = NULL;
assert(group);
for( ; cout > 0; cout--)
{
new_node = (node_t *)malloc(sizeof(node_t));
new_node->next = NULL;
new_node->data = *pgroup++;
if(NULL == head)
{
head = new_node;
ptr = head;
}
else
{
ptr->next = new_node;
ptr = new_node;
}
}
ptr = NULL;
pgroup = NULL;
return head;
}
node_t * Getcirclelink(node_t *head, int *group, int count)
{
int cout = count;
int *pgroup = group;
node_t *new_node = NULL;
node_t *ptr = NULL;
assert(group);
for( ; cout > 0; cout--)
{
new_node = (node_t *)malloc(sizeof(node_t));
new_node->next = NULL;
new_node->data = *pgroup++;
if(NULL == head)
{
head = new_node;
ptr = head;
}
else
{
ptr->next = new_node;
ptr = new_node;
}
}
ptr->next = head->next;
ptr = NULL;
pgroup = NULL;
return head;
}
void Printlink(node_t *head)
{
while(1)
{
if(NULL != head)
{
printf("%d\n",head->data);
head = head->next;
}
else
{
break;
}
sleep(1);
}
}
void Checklist(node_t *head)
{
node_t *runfast = NULL;
node_t *runslow = NULL;
assert(head);
//快指针
runfast = head;
//慢指针
runslow = head;
while(1)
{
if(NULL != runfast->next)
{
runfast = runfast->next->next;
}
else
{
runfast = runfast->next;
}
runslow = runslow->next;
if(NULL == runfast)
{
runslow = NULL;
printf("this link is no circle!\n");
break;
}
if((runfast == runslow) && (NULL != runfast))
{
printf("fast point catch slow point data is %d, %d\n",runfast->data,runslow->data);
printf("this link have a circle!\n");
runslow = NULL;
runfast = NULL;
break;
}
}
}
int main(void)
{
int ret = 0;
int groupf[] = {1,2,3,4,5,6,7};
int groups[] = {1,2,3,4,5,6,7,8,9};
node_t *fhead = NULL;
node_t *shead = NULL;
//获取一个无环链表
fhead = Getlink(fhead, groupf, 7);
//获取一个有环链表
shead = Getcirclelink(shead, groups, 9);
//判断两条链表有没有环
Checklist(fhead);
Checklist(shead);
//打印两条链表
Printlink(fhead);
Printlink(shead);
return 0;
}
方法二:
问题:
微软亚院之编程判断俩个链表是否相交
给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。
问题扩展:
2.如果需要求出俩个链表相交的第一个节点列?
答案:
参考文章:http://blog.csdn.net/lihappy999/article/details/7330175
- //20121127
- #include <iostream>
- using namespace std;
- typedef struct node
- {
- int num;
- node* next;
- }node;
- void generateList(const bool circleTrue,node *&head1,node *&head2);
- //产生链表,两个链表相交,circleTrue 为true表示产生环,false为不带环
- //产生的链表结构肯定是相同的
- bool judgeCircle(node* const head);//判断是否存在环,true存在,false不存在
- node* crossNode(const bool circleTrue,node *head1,node *head2);
- int main()
- {
- node* head1;
- node* head2;
- generateList(true,head1,head2);//相交,且有环
- bool b=judgeCircle(head1);
- node* p=crossNode(b,head1,head2);
- cout<<"cross node:"<<p->num<<endl;
- return 0;
- }
- void generateList(const bool circleTrue,node *&head1,node *&head2)
- {
- //每个链表都具有10个节点
- node *pre1=NULL;
- node *p=new node;
- head1=p;
- p->num=rand();
- p->next=NULL;
- pre1=p;
- node *pre2=NULL;
- p=new node;
- head2=p;
- p->num=rand();
- p->next=NULL;
- pre2=p;
- //假设从第3个节点开始相交
- int crossID=3;
- //假设环的开始节点为5
- int circleStart=5;
- node *cs1=NULL;
- node *cs2=NULL;
- for (int i=0;i<10;++i)
- {
- //第一条链表的节点
- p=new node;
- pre1->next=p;
- p->num=rand();
- p->next=NULL;
- pre1=p;
- if (i==circleStart)
- {
- cs1=p;
- }
- if (i==crossID)
- {
- cs2=p;
- }
- }
- if (circleTrue)
- {
- pre1->next=cs1;
- }
- for (int i=0;i<5;++i)
- {
- p=new node;
- pre2->next=p;
- p->num=rand();
- p->next=NULL;
- pre2=p;
- }
- pre2->next=cs2;
- }
- bool judgeCircle(node* const head)
- {
- //两个指针,一个每次走一步,一个每次走两步,当前一个指针赶上后一个指针时,就说明存在环
- node* p1=head;
- node* p2=head;
- while ((p1->next!=NULL)&&(p2->next!=NULL))
- {
- p1=p1->next;
- p2=p2->next->next;
- if (p1==p2)
- {
- break;
- }
- }
- if (p2->next==NULL)
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- node* crossNode(const bool circleTrue,node *head1,node *head2)
- {
- if (!circleTrue)
- {
- //不存在环
- int num1=1;
- int num2=1;
- node* p1=head1;
- node* p2=head2;
- while (head1->next!=NULL)
- {
- num1++;
- head1=head1->next;
- }
- while (head2->next!=NULL)
- {
- num2++;
- head2=head2->next;
- }
- int preNum=num1>=num2?num1-num2:num2-num1;//对齐处理
- if (num1>=num2)
- {
- for (int i=0;i<preNum;i++)
- {
- p1=p1->next;
- }
- }
- else
- {
- for (int i=0;i<preNum;i++)
- {
- p2=p2->next;
- }
- }
- while (p1!=p2)
- {
- p1=p1->next;
- p2=p2->next;
- }
- return p1;
- }
- else
- {
- //存在环
- //分两种情况,入环口相同和入环口不同
- node* p1=head1;
- node* p2=head1;
- p1=p1->next;
- p2=p2->next->next;
- while (p1!=p2)
- {
- p1=p1->next;
- p2=p2->next->next;
- }
- //相遇点p2
- p1=head1;
- node* entraNode;
- while (p1!=p2)
- {
- p1=p1->next;
- entraNode=p2;
- p2=p2->next;
- }
- //相遇点p1的前一点pre即为环的入口点
- p1=head1;
- p2=head2;
- int num1=0;
- while (p1->next!=entraNode)
- {
- num1++;
- p1=p1->next;
- }
- int num2=0;
- while (p2->next!=entraNode)
- {
- num2++;
- p2=p2->next;
- }
- p1=head1;
- p2=head2;
- int preNum=num1>=num2?num1-num2:num2-num1;//对齐处理
- if (num1>=num2)
- {
- for (int i=0;i<preNum;i++)
- {
- p1=p1->next;
- }
- }
- else
- {
- for (int i=0;i<preNum;i++)
- {
- p2=p2->next;
- }
- }
- while (p1!=p2)
- {
- p1=p1->next;
- p2=p2->next;
- }
- return p1;
- }
- }
学习的时候要注意真正理解其中的原理~
假设该链表在环出现之前有L个结点,环中有C个结点。
再假设慢指针初始化时指向的位置为a、快指针初始化时指向的位置为b,
如果二者在t次移动后相遇,也就是说:(a+t-L) mod C == (b+2*t-L) mod C
稍微变形一下就可以看出,t==a-b(mod C)这个模线性方程一定有解
所以无论a、b的起始位置如何,二者总是会相遇的。
这种方法之所以能够判断链表中是否有环,是要使快、慢指针在环里转圈的时候总会碰面。
所以快慢指针的步长选择很重要,起始位置倒是无关紧要的事情。
方法三:
要求: 算法中使用的内存数量是一个常数, 即不能因为链表长度的增减使用的内存也增减.
下面是本人的一个实现:
struct list{
int data;
struct list *next;
};
int has_circle(struct list *head)
{
struct list *cur1 = head;
int pos1 = 0;
while(cur1){
struct list *cur2 = head;
int pos2 = 0;
pos1 ++;
while(cur2){
pos2 ++;
if(cur2 == cur1){
if(pos1 == pos2)
break;
else
return 1; //has circle
}
cur2 = cur2->;next;
}
cur1 = cur1->;next;
}
return 0;
}