剑指offer算法题之单链表的反转--面试题16:反转链表

来源:互联网 发布:淘宝账户如何解绑虾米 编辑:程序博客网 时间:2024/05/02 02:56
  • 题目如下:
    这里写图片描述

  • 本题分析

第一步: 反转结点指针
一般解决与链表相关问题总是涉及到大量的指针操作,这时候代码中很容易出错。为了正确地反转一个链表,需要调整链表中指针的方向。因此我们借助图形来直观的分析本题指针的变化过程。如下图所示,(a )图中的h, i , j 是三个相邻的结点。假设进过之前的反转操作,h结点之前的指针调整完毕,可见,前面的所有结点的m_pNext指针都指向前面一个结点。接下来要做分两个步骤:1、把结点i的m _pNext指针断开 。2、把结点i的m _pNext指针连接到前一个结点h上,完成后如图(b)所示。
这里写图片描述

第二步: 找寻后继结点
在经过上面一步反转操作过后,我们的确完成了结点指针的向前反转的操作,但是此时的结点j却失去联系,因此我们需要在调整结点i的m _pNext指针前,吧结点J保存下来。
也就是说我们在调整结点i的 m _pNext指针时,需要做到以下几个步骤:
1、先找寻到当前结点的位置,如结点i的位置。
2、设置一个指针,指向结点i后继结点j的位置,然后断开i的m _pNext指针连接。
3、将结点i的m _pNext指针连接到它的前驱结点h上。
注意:本过程设计三个指针。

第三步: 找寻反转链表的头结点
找寻头结点的方法:反转链表的头结点就是之前链表的尾结点,也就是m _pNext指针连接NULL位置的结点

  • 注意事项:这道题有几种特殊情况需要在代码中注意到,否则会导致程序的崩溃。
    1、输入的链表头指针为NULL,也就是空链表或者链表中只有一个结点时,程序立即崩溃。
    2、反转后的链表会出现断裂。–需要进行连接

    在设计测试用例的过程,需要考虑以下三类情况进行功能测试:
    1、输入的链表头指针是NULL。
    2、输入的链表只有一个结点。
    3、输入的链表有多个结点。

  • 反转链表算法代码实现

注意:
1、首先需要知道,反转链表操作是需要用到3个指针,分别记录前驱结点,当前结点,后驱结点的位置。另外最后完成反转需要返回一个头结点的位置,因此还需要定义一个指针指向反转链表的头结点。
2、反转过程可以分为三步:

  • 1、用指针记录后继结点的位置,然后断开当前结点的连接,也就是与后继结点的连接。
  • 2、把当前结点的m _pNext指针指向前驱结点
  • 3、重新对当前结点和前驱结点赋值。pPrev=pNode; pNode=pNext;

3、前面一共提到链表的三种情况,分别是;空链表,含一个结点的链表和含多个结点的链表。我们上面的算法是针对第三种情况。我们发现,前两种情况,只需要返回当前结点的值即可以代表这种情况。
因此加入如下判断:while(pNode!=NULL) { };return pNode;这样即使是前两种情况,也可以包含在内,不需要单独考虑。

ListNode* ReverseList(ListNode* pHead){    ListNode* pReversedHead=NULL;    ListNode* pNode=pHead;    ListNode* pNext;    ListNode* pPrev=NULL;    //if(pHead==NULL);    //return pReversedHead;    //if(pNext==NULL)    //return pNode;    while(pNode!=NULL)    {        pNext=pNode->m_pNext;//注意        if(pNext==NULL)            pReversedHead=pNode;        //断开结点,反转指针        pNode->m_pNext=pPrev;        //重新赋值        pPrev=pNode;        pNode=pNext;    }    return pReversedHead;}
  • 整个案例代码实现
#include "stdafx.h"#include <list>struct ListNode{    int m_nKey;    ListNode* m_pNext;};ListNode* ReverseList(ListNode* pHead){    ListNode* pReversedHead=NULL;    ListNode* pNode=pHead;    ListNode* pNext;    ListNode* pPrev=NULL;    //if(pHead==NULL);    //return pReversedHead;    //if(pNext==NULL)    //return pNode;    while(pNode!=NULL)    {        pNext=pNode->m_pNext;//注意        if(pNext==NULL)            pReversedHead=pNode;        //断开结点,反转指针        pNode->m_pNext=pPrev;        //重新赋值        pPrev=pNode;        pNode=pNext;    }    return pReversedHead;}//创建链表结点模块ListNode* CreateListNode(int value){    ListNode* pNode=new ListNode();    pNode->m_nKey=value;    pNode->m_pNext=NULL;    return pNode;}//把链表的每个结点连接起来void ConnectListNodes(ListNode* pCurrent,ListNode* pNext){    if(pCurrent==NULL)        exit(1);    pCurrent->m_pNext=pNext;}//输出链表模块void PrintList(ListNode* pHead){    printf("PrintList starts.\n");    ListNode* pNode=pHead;    while(pNode)    {        printf(" %d\t",pNode->m_nKey);        pNode=pNode->m_pNext;    }    printf("\n");}//建立测试功能模块ListNode* Test(ListNode* pHead){    printf("The original list is: \n");    PrintList(pHead);    ListNode* pReversedHead=ReverseList(pHead);    printf("The reversed list is: \n");    PrintList(pReversedHead);    return pReversedHead;}//建立一个测试案例,包含四个结点void Test1(){    ListNode* pNode1=CreateListNode(1);    ListNode* pNode2=CreateListNode(2);    ListNode* pNode3=CreateListNode(3);    ListNode* pNode4=CreateListNode(4);    ConnectListNodes(pNode1,pNode2);    ConnectListNodes(pNode2,pNode3);    ConnectListNodes(pNode3,pNode4);    ListNode* pReversedHead = Test(pNode1);    return ;}int main(){    Test1();    system("pause");    return 0;}