您的位置:首页 > 职场人生

程序员面试题精选100题(19)-反转链表

2012-11-20 22:41 429 查看
程序员面试题精选100题(19)-反转链表

题目:输入一个链表的头结点,反转该链表,并返回反转后链表的头结点。链表结点定义如下:

struct ListNode
{
      int       m_nKey;
      ListNode* m_pNext;
};

分析:这是一道广为流传的微软面试题。由于这道题能够很好的反应出程序员思维是否严密,在微软之后已经有很多公司在面试时采用了这道题。

为了正确地反转一个链表,需要调整指针的指向。与指针操作相关代码总是容易出错的,因此最好在动手写程序之前作全面的分析。在面试的时候不急于动手而是一开始做仔细的分析和设计,将会给面试官留下很好的印象,因为在实际的软件开发中,设计的时间总是比写代码的时间长。与其很快地写出一段漏洞百出的代码,远不如用较多的时间写出一段健壮的代码。

为了将调整指针这个复杂的过程分析清楚,我们可以借助图形来直观地分析。假设下图中l、m和n是三个相邻的结点:

a?b?…?l  mànà…

假设经过若干操作,我们已经把结点l之前的指针调整完毕,这些结点的m_pNext指针都指向前面一个结点。现在我们遍历到结点m。当然,我们需要把调整结点的m_pNext指针让它指向结点l。但注意一旦调整了指针的指向,链表就断开了,如下图所示:

a?b?…l?m  nà…

因为已经没有指针指向结点n,我们没有办法再遍历到结点n了。因此为了避免链表断开,我们需要在调整m的m_pNext之前要把n保存下来。

接下来我们试着找到反转后链表的头结点。不难分析出反转后链表的头结点是原始链表的尾位结点。什么结点是尾结点?就是m_pNext为空指针的结点。

基于上述分析,我们不难写出如下代码:

///////////////////////////////////////////////////////////////////////
// Reverse a list iteratively
// Input: pHead - the head of the original list
// Output: the head of the reversed head
///////////////////////////////////////////////////////////////////////
ListNode* ReverseIteratively(ListNode* pHead)
{
      ListNode* pReversedHead = NULL;
      ListNode* pNode = pHead;
      ListNode* pPrev = NULL;
      while(pNode != NULL)
      {
            // get the next node, and save it at pNext
            ListNode* pNext = pNode->m_pNext;

            // if the next node is null, the currect is the end of original 
            // list, and it's the head of the reversed list
            if(pNext == NULL)
                  pReversedHead = pNode;

            // reverse the linkage between nodes
            pNode->m_pNext = pPrev;

            // move forward on the the list
            pPrev = pNode;
            pNode = pNext;
      }

      return pReversedHead;
}

另一种方法:以递归来实现反转链表

#include <iostream>  

using namespace std;  

  

struct ListNode  

{  

    int data;  

    struct ListNode *next;  

};  

  

//创建链表  

void createList(ListNode *&Head)  

{  

     int num = 0;  

     int flag = 0;  

     ListNode *p = NULL;  

     cin >> num;  

       

     Head = (ListNode *)malloc(sizeof(ListNode));  

     while(num != 0)  

     {  

          if(flag == 0)  

          {    

               Head->data = num;  

               Head->next = NULL;  

               flag = 1;  

               p = Head;  

          }  

          else  

          {  

               ListNode *cur = (ListNode *)malloc(sizeof(ListNode));  

               cur->data = num;  

               cur->next = NULL;  

                

               p->next = cur;  

               p = cur;  

          }   

          cin >> num;  

     }  

}  

  

//打印链表  

void printList(ListNode *Head)  

{  

     if(Head == NULL)  

     {  

          cout << "Head empty"<<endl;  

          return ;  

     }  

     ListNode *p = Head;  

     while(p != NULL)  

     {  

          cout << p->data <<" ";  

          p = p->next;  

     }  

}  

  

//递归反转链表(关键代码)

ListNode* reverseLinkList_recursion(ListNode* pNode,ListNode*& head)  

{  

     if(pNode == NULL || pNode->next == NULL)  

    {  

          head->next = NULL;    //把反转后的最后一个节点的next域置为NULL  

          head = pNode;  

          return pNode;  

     }  

     ListNode* tmpNode = reverseLinkList_recursion(pNode->next,head);//返回原链表中pNode的下一个节点  

     tmpNode->next = pNode;  

     return pNode;  

}  

void main()  

{  

     ListNode *List = NULL;  

     cout << "创建链表:";  

     createList(List);  

     cout << "链表元素:";  

     printList(List);  

     reverseLinkList_recursion(List,List);  

     cout <<endl<< "倒序后:";  

     printList(List);  

}  

参考来源: <<剑指offer名企面试官经典题型>> 作者:何海涛

                
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: