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: }
  • 相关阅读:
    sencha touch 扩展篇之将sencha touch打包成安装程序(上)- 使用sencha cmd打包安装程序
    sencha touch 扩展篇之使用sass自定义主题样式 (下)通过css修改官方组件样式以及自定义图标
    一个不错的android组件的网站
    sencha touch 扩展篇之使用sass自定义主题样式 (上)使用官方的api修改主题样式
    sencha touch 入门系列 (九) sencha touch 布局layout
    面试题总结
    国外接活网站Elance, Freelancer和ScriptLance的介绍和对比
    sencha touch 入门系列 扩展篇之sencha touch 项目打包压缩
    Android Design Support Library——Navigation View
    设计模式——命令模式
  • 原文地址:https://www.cnblogs.com/newth/p/2479903.html
Copyright © 2011-2022 走看看