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

原创 2013年12月05日 17:44:28

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


单链表的定义

常见的定义方式如下:

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


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

链表经典算法题实现

本文包含链表的以下内容:   1、单链表的创建和遍历   2、求单链表中节点的个数   3、查找单链表中的倒数第k个结点(剑指offer,题15)   4、查找单链表中的中间结点   5、合...

LeetCode 25. Reverse Nodes in k-Group(反转链表)

原题网址:https://leetcode.com/problems/reverse-nodes-in-k-group/ Given a linked list, reverse the node...
  • jmspan
  • jmspan
  • 2016年05月20日 10:35
  • 342

linux 同步机制 死锁

说出你所知道的各类linux系统的各类同步机制(重点),什么是死锁?如何避免死锁(每个技术面试官必问)Linux 内核的同步机制,第 1 部分 原子操作,不会被任何事务给打断,通常用于资源计数,引用计...

Linux ipcs 命令和ipcrm命令详解

ipcs 命令   用途 : linux/uinx上提供关于一些进程间通信方式的信息,包括共享内存,消息队列,信号,报告进程间通信设施状态。    语法       ipcs [ -m] [ -...

面试题—数据结构之单链表详述(基本篇)

单链表的结构是数据结构中最简单的,它的每一个节点只有一个指向后一个节点的指针。 单链表节点的定义: [cpp] view plaincopyprint? typedef ...

面试题—数据结构之单链表详述(基本篇2)

下面也是关于单链表的操作问题,实现单链表的逆置,关于这个问题,最容易想到的方法是遍历一遍链表,利用一个辅助指针,存储遍历过程中当前指针指向下一个元素,然后将当前节点元素的指针反转,利用已经存在存储的指...

面试题—数据结构之单链表详述(基本篇3)

单链表的正向排序,就是插入数据时就按从小到大排序。代码有注释很容易理解的://单链表的正向排序 node *InsertSort(void) { int data = 0; struct node...

笔试面试常考数据结构-单链表常用操作编程实现

单链表是笔试以及面试手写代码中常考的数据结构之一。下面实现了单链表的常见操作:创建单链表、删除节点、打印单链表(包括正向打印以及逆向打印)、反转单链表、找出单链表的倒数第K个节点、合并两个有序单链表等...

程序员面试宝典之数据结构基础-----③单链表的插入

单链表的插入,注意分三种情况,插入到头部前,插入到尾部后,其他。 仍然是细节决定成败。。。 #include #include #include using namespace ...

java数据结构—单链表的实现原理

再次学习数据额结构,看到前面的单链表,感觉里面的思路很不错,自己动手写代码尝试一下,果然一动手就发现自己并没有完全理解。这里主要记录我花了很长时间才理解的地方,不去考虑增删改查,我觉得这些功能在很多地...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:面试数据结构篇—单链表常考点汇总
举报原因:
原因补充:

(最多只允许输入30个字)