【数据结构】面试之链表问题集锦(上)

本文首发于我的公众号码农之屋(id: Spider1818),专注于干货分享,包含但不限于Java编程、网络技术、Linux内核及实操、容器技术等。欢迎大家关注,二维码文末可以扫。

导读:链表问题在面试过程中是非常重要也是非常基础的一环,主要就是考查面试者的编程功底,接下来将对常见的面试题进行归纳总结。


1、在O(1)时间删除链表节点

题目描述:给定链表的头指针和一个节点指针,在O(1)时间删除该节点。

分析:本题与《编程之美》上的「从无头单链表中删除节点」类似。主要思想都是「狸猫换太子」,即用下一个节点数据覆盖要删除的节点,然后删除下一个节点(如果节点是尾节点时,该方法就行不通了)。

代码如下:

 void deleteRandomNode(Node *cur)
 {
     assert(cur != NULL);
     assert(cur->next != NULL);
     Node* pNext = cur->next;
     cur->data = pNext->data;
     cur->next = pNext->next;
     delete pNext;
 }

 

2. 单链表的转置

题目描述:输入一个单向链表,输出逆序反转后的链表。

分析:链表的转置是一个很常见、很基础的数据结构题了,非递归的算法很简单,用三个临时指针pre、head、next 在链表上循环一遍即可。

代码如下:

Node* reverseByLoop(Node *head)
 {
     if(head == NULL ||  head->next == NULL)
         return head;
     Node *pre = NULL;
     Node *next = NULL;
     while(head != NULL)
     {
         next = head->next;
 
         head->next = pre;
         pre = head;
         head = next;
     }
     return pre;
 }

 

3. 求链表倒数第k个节点

题目描述:输入一个单向链表,输出该链表中倒数第k个节点,链表的倒数第0个节点为链表的尾指针。

分析:设置两个指针p1、p2,首先p1和p2都指向head,然后p2向前走k步,这样p1和p2之间就间隔k个节点,最后p1和p2同时向前移动,直至p2走到链表末尾。

代码如下:

 Node* theKthNode(Node *head,int k)
{
     if(k < 0) returnNULL;
 
     Node *slow,*fast;
     slow = fast = head;
     int i = k;
      for(;i>0 && fast!=NULL;i--)
     {
         fast = fast->next;
     }
 
     if(i > 0)    returnNULL; 
 
     while(fast != NULL)
     {
         slow = slow->next;
         fast = fast->next;
     }
 
     return slow;
 }

 

​​​​​4. 求链表的中间节点

 

题目描述:求链表的中间节点,如果链表的长度为偶数,返回中间两个节点的任意一个,若为奇数,则返回中间节点。

分析:此题的解决思路和第3题「求链表的倒数第k个节点」很相似。可以先求链表的长度,然后计算出中间节点所在链表顺序的位置。但是如果要求只能扫描一遍链表,如何解决呢?最高效的解法和第3题一样,通过两个指针来完成。用两个指针从链表头节点开始,一个指针每次向后移动两步,一个每次移动一步,直到快指针移到到尾节点,那么慢指针即是所求。

代码如下:

 Node* theMiddleNode(Node *head)
 {
     if(head == NULL)
         returnNULL;
     Node *slow,*fast;
     slow = fast = head;
     while(fast != NULL &&  fast->next != NULL)
     {
         fast = fast->next->next;
         slow = slow->next;
     }
     return slow;
 }

 

5. 判断单链表是否存在环

题目描述:输入一个单向链表,判断链表是否有环。

分析:通过两个指针,分别从链表的头节点出发,一个每次向后移动一步,另一个移动两步,两个指针移动速度不一样,如果存在环,那么两个指针一定会在环里相遇。

代码如下:

 bool hasCircle(Node *head,Node *&circleNode)
 {
     Node *slow,*fast;
     slow = fast = head;
     while(fast != NULL &&  fast->next != NULL)
     {
         fast = fast->next->next;
         slow = slow->next;
         if(fast == slow)
         {
             circleNode = fast;
             return true;
         }
     }
 
     return false;
 }

 

我的公众号「码农之屋」(id: Spider1818) ,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎大家关注。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值