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

16 篇文章 9 订阅
10 篇文章 1 订阅
  • 题目如下:
    这里写图片描述

  • 本题分析

第一步: 反转结点指针
一般解决与链表相关问题总是涉及到大量的指针操作,这时候代码中很容易出错。为了正确地反转一个链表,需要调整链表中指针的方向。因此我们借助图形来直观的分析本题指针的变化过程。如下图所示,(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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值