链表--Reorder List

重排序一个链表

Given a singly linked list L:L0->L1->...->Ln-1->Ln

reorder it to :L0->Ln->L1->Ln-1->L2->Ln-2->...

You must do this in-place without altering the node's values.

Example:Given 1->2->3->4->null , reorder it to 1->4->2->3->null

思路:将链表一分为二,逆序后半段,然后融合这两段链表。

ListNode *reorderList(ListNode *head)
{
    if(head == NULL || head->next == NULL || head->next->next == NULL)
        return head;
    
    //寻找到链表的中点
    ListNode *middle = findMiddle(head);
    
    //逆序后半部
    ListNode *right = reverse(middle->next);
    
    //middle成了前半部的终点,使其指向NULL
    middle->next = NULL;

    //融合头节点和后半部
    return merge(head,right);    
}

//寻找链表的中点
ListNode *findMiddle(ListNode *head)
{
    if(head == NULL || head->next == NULL)
        return head;

    ListNode *fastNode = head;
    ListNode *slowNode = head;
    //例如:1->2->3->4->5->6,
    //注意:如果链表长度为奇数个,中点很好找,分成的两段前一段比后一段多一个.
    //如果链表的长度为偶数个,如果下面的循环加上fastNode->next->next != NULL,那么
    //链表的两段元素个数相同,分别是1->2->3和4->5->6
    //如果不加fastNode->next->next != NULL,那么前一段的元素个数比后一段的元素个数多2个。
    //前段是1->2->3->4,后段是5->6->null,但是这并不影响最后的结果.
    //不加fastNode->next->next != NULL时,结果是1->6->2->5->3->4
    //加fastNode->next->next != NULL时,结果是1->6->2->5->3->4.
    //所以下面循环中的fastNode->next->next != NULL可不加.
    
    while(fastNode != NULL && fastNode->next != NULL && fastNode->next->next != NULL)
    {
        fastNode = fastNode->next->next;
        slowNode = slowNode->next;
    }

    return slowNode;
}

ListNode *reverse(ListNode *head)
{
    if(head == NULL || head->next == NULL)    
        return head;
    
    ListNode *newHead = reverse(head->next);
    head->next->next = head;
    head->next = NULL;

    return newHead;
}


ListNode *merge(ListNode *L1,ListNode *L2)
{
    if(L1 == NULL)    return L2;
    if(L2 == NULL)    return L1;

    ListNode *head = L1;
    ListNode *left = L1;
    ListNode *right = L2;
    while(L1 && L2)
    {   
        L1 = L1->next;
        left->next = right;
        left = L1;    
        L2 = L2->next;
        right->next = left;
        right = L2;
    }

    //left一定是大于等于right的.
    //相等的话L1和L2都是NULL
    //L1大于L2的话,L1不是NULL,是最后一个元素
    //这是针对本应用场景的merge
    if(L1)   L1->next = NULL;

    return head;
}

/*
    另一个版本的merge,本版本是通用的合并两链表的算法,本版本优于上一种解法.
 */

void merge(ListNode *left,ListNode *right)
{
    if(left == NULL)    return right;
    if(right == NULL)    return left;

    ListNode *dummy = new ListNode(0);
    ListNode *tmp = dummy;
    
    while(left && right)
    {
        dummy->next = left;
        dummy = dummy->next;
        left = left->next;
        
        dummy->next = right;
        dummy = dummy->next;
        right = right->next;
    }

    dummy->next = (NULL != left) ? left : right;

    delete tmp;    
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云镛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值