zoukankan      html  css  js  c++  java
  • 链表有关的常见面试题

    1.单链表逆序

    实现1:

    遍历:

       1: /*
       2:  * 遍历链表, 将每个结点的next置为其前驱
       3:  * 遍历过程中需要额外的指针来记录结点的前驱和后继 
       4:  */
       5: LinkList ReverseList(LinkList L)
       6: {
       7:     if (!L || !L->next) {
       8:         return L;
       9:     }
      10:  
      11:     Node *pre, *cur, *next;
      12:  
      13:     pre = next = NULL;
      14:     cur = L->next;
      15:     while (cur) {
      16:         next = cur->next;
      17:         cur->next = pre;
      18:         pre = cur;
      19:         cur = next;
      20:     }
      21:     L->next = pre;
      22:  
      23:     return L;
      24: }

    实现2:

    递归:

       1: /* 
       2:  * 采用递归,每次递归返回子链表反转后的头指针 
       3:  */
       4: Node * ReverseList(Node *node)
       5: {
       6:     if (!node || !node->next) {
       7:         return node;
       8:     }
       9:  
      10:     Node *next = node->next;
      11:     Node *head = ReverseList(next);
      12:     next->next = node;
      13:     node->next = NULL;
      14:  
      15:     return head;
      16: }

    2.合并有序链表

    实现1:

    遍历, 遍历两个链表,每次将较小的结点插入到合并后的新链表。

       1: Node *Merge(Node *head1, Node *head2)
       2: {
       3:     /* 如果一个链表为空, 则直接返回另一个 */
       4:     if (!head1) {
       5:         return head2;
       6:     }
       7:     if (!head2) {
       8:         return head1;
       9:     }
      10:     
      11:     /* head为合并后的头指针, p1 p2分别用来遍历两个链表 */
      12:     Node *head, *p1, *p2;
      13:     head = p1 = p2 = NULL;
      14:     if (head1->data < head2->data) {
      15:         head = head1;
      16:         p1 = head1->next;
      17:         p2 = head2;
      18:     } else {
      19:         head = head2;
      20:         p2 = head2->next;
      21:         p1 = head1;
      22:     }
      23:     
      24:     /* cur为合并后链表的当前结点, 从p1和p2从选出较小的作为其后继 */
      25:     Node *cur = head;
      26:     while (!p1 && !p2) {
      27:         if (p1->data <= p2->data) {
      28:             cur->next = p1;
      29:             cur = p1;
      30:             p1 = p1->next;
      31:         } else {
      32:             cur->next= p2;
      33:             cur = p2;
      34:             p2 = p2->next;
      35:         }
      36:     }
      37:     
      38:     /* 遍历完一个链表后,将另一链表剩余结点插入到新链表中 */
      39:     if (!p1) {
      40:         cur->next= p1;
      41:     } else {
      42:         cur->next= p2;
      43:     }
      44:     
      45:     return head;    
      46: }

    实现2:

    递归,每次递归返回合并后新链表的头结点。

       1: Node *MergeRecursive(Node *head1, Node *head2)
       2: {
       3:     if (!head1 || !head2) {
       4:         return head1 ? head1 : head2;
       5:     }
       6:     
       7:     Node *head;
       8:     if (head1->data < head2->data) {
       9:         head = head1;
      10:         head->next = MergeRecursive(head1->next, head2);        
      11:     } else {
      12:         head = head2;
      13:         head->next = MergeRecursive(head1, head2->next);
      14:     } 
      15:     
      16:     return head;
      17: }

    3.判断两个无环单链表是否交叉,如果是则返回交点

    实现1:

    判断是否交叉:因为无环单链表只可能是Y型交叉,所以遍历两个链表至最后一个结点,判断最后一个结点是否相等即可。

       1: bool IsCross(Node *head1, Node *head2)
       2: {
       3:     if (!head1 || !head2) {
       4:         return false;
       5:     }
       6:     
       7:     Node *p1 = head1;
       8:     Node *p2 = head2;    
       9:     while (p1->next) {
      10:         p1 = p1->next;
      11:     }
      12:     while (p2->next) {
      13:         p2 = p2->next;
      14:     }
      15:     
      16:     return (p1 == p2);
      17: }

    找出交点:遍历两个链表,记录长度分别为L1和L2,先让长的链表向后移动abs(L1-L2),然后在逐个比较结点,第一个相等的结点即为交点。

       1: Node *FindCross(Node *head1, Node *head2)
       2: {
       3:     if (!head1 || !head2) {
       4:         return NULL;
       5:     }
       6:     
       7:     /* 求出两个链表的长度 */
       8:     Node *p1, *p2;
       9:     p1 = head1;
      10:     p2 = head2;
      11:     int len1, len2, len;
      12:     len1 = len2 = 0;    
      13:     while (p1) {
      14:         len1++;
      15:         p1 = p1->next;
      16:     } 
      17:     while (p2) {
      18:         len2++;
      19:         p2 = p2->next;
      20:     }
      21:     
      22:     /* 将长链表先移动len个结点 */
      23:     int i;
      24:     len = abs(len1 - len2);
      25:     p1 = head1;
      26:     p2 = head2;
      27:     if (len1 > len2) {
      28:         for (i = 0; i < len; ++i) {
      29:             p1 = p1->next;
      30:         }
      31:     } else {
      32:         for (i = 0; i < len; ++i) {
      33:             p2 = p2->next;
      34:         }
      35:     }
      36:     
      37:     /* 遍历 找到第一个相等的结点即为交点 */    
      38:     while (!p1) {
      39:         p1 = p1->next;
      40:         p2 = p2->next;
      41:         if (p1 == p2) {
      42:             return p1;
      43:         }
      44:     }
      45:     
      46:     return NULL; 
      47: }

    实现2:

    将其中一个链表首尾相连,这样就转换成为判断另一个链表是否有环即求进入环的结点的问题。

    4.判断单链表是否有环, 如果有环则返回进入环的第一个结点.

    实现1:

    设置快慢指针,初始都指向链表头,快指针每次前进两步,慢指针每次前进一步,如果有环则两个指针必定相遇。

    判读是否有环:

       1: bool HaveCircle(Node *head)
       2: {
       3:     if (!head) {
       4:         return false;
       5:     }
       6:     
       7:     Node *fast, *slow;
       8:     fast = slow = head;
       9:     
      10:     while (fast && fast->next) {        
      11:         slow = slow->next;
      12:         fast = fast->next->next;
      13:         if (fast == slow) {
      14:             return true;
      15:         }
      16:     }
      17:     
      18:     return false;
      19: }
    找出环的位置:
    实现2:

    将结点的地址做hash,遍历链表,检测是否有地址相等的结点。

    5.找出单链表的中间元素

    实现:

    设置快慢指针,初始都指向链表头,快指针每次前进两步,慢指针每次前进一步,当快指针到达链表末尾时,慢指针所指即为单链表的中间元素。

       1: Node *FindMid(Node *head)
       2: {
       3:     if (!head) {
       4:         return NULL;
       5:     }
       6:     
       7:     Node *fast, *slow;
       8:     fast = slow = head;
       9:     while (fast && fast->next) {
      10:         slow = slow->next;
      11:         fast = fast->next->next;
      12:     }
      13:     /* 如果是fast为NULL, 则链表长度为奇数, slow为中间结点
      14:     *  如果是fast->next为NULL, 则链表长度为偶数, slow 和 slow->next 为中间结点 
      15:     */    
      16:     return slow;
      17: }

    6.删除单链表中倒数第k个结点

    实现:

    设置两个指针p1和p2,p1指向链表第一个结点,p2指向第k+1个结点,两个指针同时前进,当p2到达链表尾时,p1指向倒数第k+1个结点,删除p1后面的一个结点即可。

       1: Node *DeleteK(Node *head, int k) {
       2:     if (!head) {
       3:         return NULL;
       4:     }
       5:     
       6:     int i;
       7:     Node *p1, *p2;
       8:     p1 = p2 = head;
       9:     for (i = 0; i <= k; ++i) {
      10:         if (p2) {
      11:             p2 = p2->next;
      12:         } else {
      13:             return NULL;
      14:         }
      15:     }
      16:     
      17:     while (p2) {
      18:         p1 = p1->next;
      19:         p2 = p2->next;
      20:     }
      21:     p2 = p1->next;
      22:     p1->next = p2->next;
      23:     
      24:     return p2;    
      25: }

    7.从单链表中删除指定的中间结点

    实现:

    将指定结点的后继的值赋值给指定结点,然后删除其后继即可。

       1: void DeleteMidNode(Node *del)
       2: {
       3:     if (!del) {
       4:         return; 
       5:     }
       6:     
       7:     Node *next = del->next;
       8:     if (next) {
       9:         del->data= next->data;
      10:         del->next= next->next;
      11:         free(next);    
      12:     }
      13: }

    8.在单链表的指定结点前插入一个结点

    实现:

    将结点插入到指定结点后,然后交换两节点的值即可。

       1: int InsertBeforeNode(Node *node, Node *insert)
       2: {
       3:     if (!node || !insert) {
       4:         return -1;
       5:     }
       6:     
       7:     Node temp = *node;
       8:     node->data = insert->data;
       9:     node->next= insert;
      10:     *insert = temp;
      11:     
      12:     return 0;    
      13: }
  • 相关阅读:
    measure time program
    Visual Studio Code 好用的 source code editor
    tmux
    singleTask, singleInstance使用心得
    IIS7中配置FastCGI运行PHP
    Node.js入门
    Excel的文件打开特别慢,xls文件特别大解决一例
    SQL Server开启READ_COMMITTED_SNAPSHOT
    [转]最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等本文出处
    “VS2013无法连接远程数据库”解决方案
  • 原文地址:https://www.cnblogs.com/newth/p/2479903.html
Copyright © 2011-2022 走看看