链表有关的常见面试题

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: }
posted @ 2012-05-03 00:14  Newerth  阅读(6431)  评论(1编辑  收藏  举报