面试数据结构篇—单链表常考点汇总

单链表是最基本的数据结构,由于其简单的构造以及相关操作代码的简短,特别受面试官的青睐,面试官可以通过在短短的15分钟内让你写出单链表的操作,而对你的代码能力进行判断。所以掌握单链表是重中之重,对常考的知识点必须熟记于心,能够快速的写出来,并且bug-free。


单链表的定义

常见的定义方式如下:

 // Definition for singly-linked list.
 struct ListNode {
     int val;
     ListNode *next;
     ListNode(int x) : val(x), next(NULL) {}
};
从上述代码中可以看出,单链表包含数据以及指向下一个节点的指针,形象化的表示如下图1所示:

               面试数据结构篇—单链表常考点汇总_第1张图片
                                    图1: 单链表图(感谢第七城市提供)

单链表不一定有头结点,但是一定会有一个头指针head。


单链表常见面试题

面试题目录:

1:就地逆转单链表

2:检测单链表是否有环

3:判断两个单链表是否有交点,如果有交点,求交点

4:在O(1)时间内删除链表内的某一结点

5:如果单链表有环,求环的长度以及入环点

(一)就地逆转单链表

  经典做法:设定三个指针,一个是pre(指向前一个结点),一个是current(指向当前结点),一个next(指向下一个结点),然后三个指针同时往右移,并且同时修改指针指向的位置

//reverse the single-list in place
//@author: zhang haibo
//@time: 2013-12-5
ListNode* Reverse_Single_List(ListNode* head)
{
	 //check the head is or not NULL
	 if(head == NULL)
	 	   return head;
	 //the head of the reverse list
	 ListNode* reverseHead = NULL;
	 //current listnode
	 ListNode* current = head;
	 //the previous listnode of current listnode
	 ListNode* pre = NULL;
	 while(current != NULL)
	 {
	 	   ListNode* next = current->next;
	 	   if(next == NULL)
	 	   	   reverseHead = current;
	 	   current->next = pre;
	 	   pre = current;
	 	   current = next;
	 }
	 
	 return reverseHead;
}

(二)检测单链表是否有环

经典做法:设定两个指针,一个快指针,一个慢指针,快指针一次走两步,慢指针一次走一步,如果两个指针相遇,说明肯定存在环,如果没有环,则扫描到链表尾节点就退出了。

//check the singly-list whether or not has cycle
//@author: zhang haibo
//@time: 2013-12-5
bool Is_Exist_Cycle(ListNode* head)
{
	 ListNode* slow = head;
	 ListNode* fast = head;
	 while(fast != NULL && fast->next != NULL)
	 {
	 	   slow = slow->next;
	 	   fast = fast->next->next;
	 	   if(slow == fast)
	 	   	   return true;
	 }
	 
	 return false;
}

(三)判断两个单链表是否有交点,如果有交点,求交点

经典做法:判断两个链表的尾节点是否相同,如果相同则必存在交点,如果不相同,则不存在交点。具体的做法是,指向两个链表的指针p1和p2分别走到末尾,并且求出两个链表的长度了L1和L2,判断p1和p2是否相同,不相同则没有交点,直接返回即可,如果相同,则存在交点,设定p1和p2指向头结点,长链表先走abs(L1-L2)步,然后两个链表共同走即可。

//check two lists have intersection or not.
//@author: zhang haibo
//@time: 2013-12-5
bool Is_Exist_Intersection(ListNode* list1, ListNode* list2, ListNode* &result)
{
	 if(list1 == NULL || list2 == NULL)
	    return false;
	 ListNode* p1 = list1;
	 ListNode* p2 = list2;
	 int length_of_list1 = 1;
	 int length_of_list2 = 1;
	 while(p1->next != NULL)
	 {
	 	   p1 = p1->next;
	 	   ++length_of_list1;
	 }
	 while(p2->next != NULL)
	 {
	 	   p2 = p2->next;
	 	   ++length_of_list2;
	 }
	 
	 //not have the intersection
	 if(p1 != p2)
	 	   return false;
	 
	 //have the intersection
	 p1 = list1, p2 = list2;
	 if(length_of_list1 < length_of_list2)
	 {
	 		 p1 = list2;
	 		 p2 = list1;
	 }
	 	
	 //p1 goes forward dis steps
	 int dis = abs(length_of_list1 - length_of_list2);
	 while(dis--)
	 	   p1 = p1->next;
	 //p1 and p2 goes forward	in the same time
	 while(p1 != p2 )
	 {
	     p1 = p1->next;
	     p2 = p2->next;
	 }
	 
	 //set the result
	 result = p1;
	 
	 return true;
}

(四)在O(1)时间内删除链表内的某一结点

1)如果此节点是尾节点,则必须从头进行扫描到尾部节点前一个节点,进行删除,耗费N-1时间。

2)如果此节点是内部节点,则删除此节点的下一个节点,并且交换两个节点的数据即可,耗费1时间。

总体而言,假设链表的长度为N,总共的时间复杂度为(1/N)*(N-1)+(N-1/N)*1 = 1

//delete one node in the list
//@author: zhang haibo
//@time: 2013-12-5
ListNode* Delete_Node(ListNode* head, ListNode* deletedNode)
{
    if(head == NULL || deletedNode == NULL)
	   return head;
    //if deletedNode is the head of the list
    if(head == deletedNode)
    {
	   head = head->next;
	   return head;
    }
    //not the tail	   
    if(deletedNode->next != NULL)
    {
   	   ListNode* next = deletedNode->next;
   	   deletedNode->val = next->val;
   	   deletedNode->next = next->next;
   	   next = NULL;
    }
    else//the tail
    {
   	   ListNode* current = head;
   	   while(current->next != deleteNode)
   	       current = current->next;
   	   current->next = NULL;
    }
    return head;
}

(五)如果单链表有环,求环的长度以及入环点

 带环链表有如下几点性质,这里不再证明,请找相关资料查看:

1:快指针(每次走两步)和慢指针(每次走一步)肯定会在第一圈相遇

2:相遇点到入环点 和  链表头指针到入环点 的距离是相同的。

//find the entrance point and 
// calculate the length of cycle
//@author: zhang haibo
//@time:  2013-12-5
ListNode* Find_Loop_Port(ListNode* head, int& length)
{
	  length = 0;
	  if(head == NULL)
	  	  return NULL;
	  
	  ListNode* slow = head;
	  ListNode* fast = head;
	  while(fast != NULL && fast->next != NULL)
	  {
	  	  fast = fast->next->next;
	  	  slow = slow->next;
	  	  ++length;
	  }
	  
	  //no cycle
	  if(fast == NULL || fast->next == NULL)
	  {
	  	  length = 0;
	  	  return NULL;
	  }
	  
	  //set slow point to the start head
	  slow = head;
	  while(slow != fast)
	  {
	  	  slow = slow->next;
	  	  fast = fast->next;
	  	  ++length;
	  }
	  
	  return slow;
}


你可能感兴趣的:(数据结构,互联网,面试,单链表)