数据结构——链表逆置!

链表逆置:是将形如 1 →2 →3 →4 →5 →NULL 的链表逆置改为:5 →4 →3 →2 →1 →NULL
对于这个问题,有两种方法:

1、采用三个指针:将整个链表翻转!!
时间复杂度O(N^2) 嵌套循环

具体思路如下:首先要先找到新的头结点,则需要一个指针pCur1遍历链表,找到原尾结点,将其设置为新的头结点,因为我们需要从原头结点开始遍历,则需要一个pOldHead指针来保存原头结点,现在在找一个pCur2来保存新链表的最后一个结点,每次遍历前将pCur1更新指向pOldHead,当pCur1的next恰好等于pCur2结点时,将pCur1尾插至pCur2,再更新pCur2pCur1,最后当pOldHead等于pCur2时,逆置完毕,再将pCur2的next赋空即可!
这里写图片描述

代码如下:

void ReverseSList(PNode* pHead)
{
    assert(*pHead);                                         //参数检测

PNode pOldHead = *pHead;
PNode pCur2;
PNode pCur1;

if (NULL == *pHead)                                      //空链表
{
    printf("链表为空,无法逆置!!\n");
    return;
}

pCur1 = *pHead;

while (pCur1->_pNext)                                         //找到新的头结点  为原链表的尾结点
{
    pCur1 = pCur1->_pNext;
}
*pHead = pCur1;

pCur2 = *pHead;                                         //pCur2 指向逆置之后的头结点,插入一个结点,pCur2更新指向其next
pCur1 = pOldHead;

while (pCur2 != pOldHead)                                    //当pCur2 == 原来的头结点时,逆置完毕,跳出循环
{
    while (pCur2 == pCur1->_pNext)                           //当pCur1的next指向pCur2时   
    {
        pCur2->_pNext = pCur1;                               // 将pCur2的next指向pCur1
        pCur2 = pCur1;                                       //并且更新pCur2 指向pCur1,
        pCur1 = pOldHead;                                    //pCur1重新指向原来的头结点
    }
    pCur1 = pCur1->_pNext;                                   //pCur1从原头结点开始遍历链表,

}

pCur2->_pNext = NULL;                //将尾指针的next赋空
}

2、采用头插的方法,不更新头结点

思路:大家知道链表的头插法的思路,将新的结点中的data与头结点data交换,然后将新结点插入到头结点的next处,从而达到看起来是头插的目的!

同样的:链表逆置也可以采用这种方法:从链表的第二个结点开始,将其结点的data用头插的方式插入到链表中,最终我们会得到:1 →2 →3 →4 →5 →4 →3 →2 →1 →NULL,,看到这个链表,我们是否应该想起,要将data为5的结点的下一个结点赋空,赋空之后,链表则成功逆置了!于是,在插入的过程中,我们需要一个标记的pIndex指针指向data为5的结点,具体怎么实现:可以知道第一个插入结点,于是

        if (pHead->_pNext->_pNext == pWait)                //在头结点的原本的第二个结点作为标记,逆置完毕后,其会成为新链表的尾结点
            pIndex = pHead->_pNext;

就可以将其标记!
如图:
这里写图片描述

代码:

PNode ReverseSListOP(PNode pHead)
{
    assert(pHead);

PNode pWait = pHead->_pNext;                    
PNode pIndex = NULL;

if (NULL == pHead)
{
    printf("链表为空,无法逆置!!!\n");
    return NULL;
}

for (; pWait != NULL; pWait = pWait->_pNext)          //从头结点的第二个结点开始 头插
{
    PNodePushFront(pHead, pWait->_data);
    if (pHead->_pNext->_pNext == pWait)                //在头结点的原本的第二个结点作为标记,逆置完毕后,其会成为新链表的尾结点
        pIndex = pHead->_pNext;
}
if (pIndex != NULL)
    pIndex->_pNext = NULL;                             //将标记的next赋空,即将尾结点的next赋空
return pHead;
}

关于链表具体怎么头插:我的另外一篇博客讲的详细 https://blog.youkuaiyun.com/code_zx/article/details/80024207

测试函数:

void testReverse()
{
    PNode pHead;
    PNode pos;

SListInit(&pHead);

PNodePushBack(&pHead, 1);
PNodePushBack(&pHead, 2);
PNodePushBack(&pHead, 3);
PNodePushBack(&pHead, 4);
PNodePushBack(&pHead, 5);
printSList(pHead);

ReverseSList(&pHead);
printSList(pHead);

pos = ReverseSListOP(pHead);
printSList(pos);
}

具体测试结果:
这里写图片描述

想了解关于链表的另外一些题,可以点一波关注,谢谢
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值