判断链表是否有环以及查找环的入口点——淘宝笔试归来

      淘宝的技术笔试题量不大,但是时间也很短(一个小时),基础题的难度还可以,后面的算法编程题就有点难度了,除非是之前做过类似的题目,否则在考场上用极其有限的时间很难做出来。下面和大家分享一道淘宝的编程题。

 

题目:①判断一个单向链表是否有环,如果有环则找到环的入口节点。

          ②判断两个单向链表是否相交,如果相交则找到交点节点。

算法思想:①用两个指针p1,p2同时指向链表的头部,p1一次移动一步,p2一次移动两步,如果最终p1和p2重合则说明链表有环,如果p2走到空指针(链表的结尾)则说明链表无环。如果最终p1和p2重合,使p2重新指向链表的头结点,然后p1和p2同时一次移动一步,当p1和p2再次重合时该节点指针就是环的入口节点指针。

                ②有了第一问的算法基础,应该不难理解第二问。首先将其中一个链表list1首尾相接,变成一个有环链表,如果另一个链表list2和list1相交的话,list2也将成为一个有环链表,并且环的入口节点就是两个链表的交叉节点。如果两个链表不相交,则list2依然是一个无环链表。

      下面是我用C++实现的程序代码,已经在visual C++6.0上运行通过了,程序中有详细的代码注释,这两个小问题在一个main函数中实现。程序代码中的不足之处还请大家多提宝贵意见。

 

TaobaoTest.cpp

 #include <iostream> using namespace std; /*节点的类定义*/ class Node { public: int data; Node * next; Node(int data) { this->data=data; } }; /*链表的类定义*/ class List { public: Node * head;//头结点指针 Node * tail;//尾结点指针 /*用一个整形数组作为参数的构造函数*/ List(int array[],int length) { head=new Node(array[0]); Node * temp=head; int i; for(i=1;i<length;i++) { temp->next=new Node(array[i]); temp=temp->next; } temp->next=NULL; tail=temp; } /*查找指定位置的节点,并返回指向该节点的指针*/ Node * FindNode(int index) { Node * temp=head; while(--index) temp=temp->next; return temp; } }; /*判断链表是否有环,如果有环则返回环的首结点指针,否则返回NULL值*/ Node * FindCircle(List list) { Node * p1,* p2; p1=list.head; p2=list.head; /*判断链表是否有环,当p1=p2时说明链表有环,程序跳出循环。如果p2一直走到链表尽头则说明没有环。*/ do { if(p2->next!=NULL&&p2->next->next!=NULL) { p2=p2->next->next; p1=p1->next; } else return NULL; } while(p1!=p2); /*求出环的起点节点,并将其返回*/ p2=list.head; while(p1!=p2) { p2=p2->next; p1=p1->next; } return p1; } /*判断两个链表是否交叉,如果交叉返回交叉节点,否则返回NULL。*/ Node * FindCross(List list1,List list2) { list1.tail->next=list1.head;//将list1变成有环链表 Node * p1,* p2; p1=list2.head; p2=list2.head; /*判断链表是否有环,当p1=p2时说明链表有环,程序跳出循环。如果p2一直走到链表尽头则说明没有环。*/ do { if(p2->next!=NULL&&p2->next->next!=NULL) { p2=p2->next->next; p1=p1->next; } else return NULL; } while(p1!=p2); /*求出环的起点节点,并将其返回*/ p2=list2.head; while(p1!=p2) { p2=p2->next; p1=p1->next; } return p1; } int main() { /*构造一个有环链表,并查找环的起始节点*/ int array[8]={1,2,3,4,5,6,7,8}; List list(array,sizeof(array1)/sizeof(int));//构造一个链表 list.tail->next=list.FindNode(5);//将该链表构造成一个有环链表 Node * temp=FindCircle(list);//查找环的起始节点 if(temp==NULL) cout<<"No cirle exists in the list."<<endl; else cout<<"There is a circle in the list , and the value of the join_point is "<<temp->data<<endl; /*构造两个链表,然后使这两个链表交叉。最后查找交叉节点。*/ int array1[8]={1,2,3,4,5,6,7,8}; int array2[5]={9,10,11,12,13}; List list1(array1,sizeof(array1)/sizeof(int));//构造链表list1 List list2(array2,sizeof(array2)/sizeof(int));//构造链表list2 list2.tail->next=list.FindNode(3);//使这两个链表交叉 temp=FindCross(list,list2);//查找这两个链表的交叉节点 if(temp==NULL) cout<<"These two lists dose not cross."<<endl; else cout<<"These two lists cross with each other , and the value of the corss_point is "<<temp->data<<endl; return 0; } 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(JOIN,编程,算法,list,null,p2p)