Lc-143重排链表

问题描述 :

给定一个单链表 L:L0→L1→…→Ln-1→Ln ,

将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

 

示例 1:

给定链表 1->2->3->4, 重新排列为 1->4->2->3.

示例 2:

给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

 

可使用以下代码,完成其中的reorderList函数,其中形参head指向无头结点单链表。

#include<iostream>

using namespace std;

struct ListNode

{

    int val;

    ListNode *next;

    ListNode() : val(0), next(NULL) {}

    ListNode(int x) : val(x), next(NULL) {}

    ListNode(int x, ListNode *next) : val(x), next(next) {}

};

 

class Solution

{

public:

    void reorderList(ListNode* head)

    {

             //填充本函数完成功能

    }

};

ListNode *createByTail()

{

    ListNode *head;

    ListNode *p1,*p2;

    int n=0,num;

    int len;

    cin>>len;

    head=NULL;

    while(n<len && cin>>num)

    {

        p1=new ListNode(num);

        n=n+1;

        if(n==1)

            head=p1;

        else

            p2->next=p1;

        p2=p1;

    }

    return head;

}

 

void  displayLink(ListNode *head)

{

    ListNode *p;

    p=head;

    cout<<"head-->";

    while(p!= NULL)

    {

        cout<<p->val<<"-->";

        p=p->next;

    }

    cout<<"tail\n";

}

int main()

{

    ListNode* head = createByTail();

    Solution().reorderList(head);

    displayLink(head);

    return 0;

}

 

输入说明 :首先输入链表长度len,然后输入len个整数,以空格分隔。

输入范例 :

 5

1 2 3 4 5

输入范例 :

head-->1-->5-->2-->4-->3-->tail

思路:

1.找到链表的中间节点

2.将中间节点之后的节点进行反转

3.按照要求依次合并前半截链表和后半截链表

因此,需要写2个函数:找到链表的中间的节点,反转链表。

1.找到链表的中间节点 

使用快慢指针:使用两个指针变量,刚开始都位于链表的第 1 个结点,一个永远一次只走 1 步,一个永远一次只走 2 步,一个在前,一个在后,同时走。这样当快指针走完的时候,慢指针就来到了链表的中间位置。

 本题使用的是后者:

private:
    ListNode *midOfList(ListNode *head){
        //用快慢指针求中间结点
        ListNode *slowTemp = head;
        ListNode *fastTemp = head;
while(fastTemp->next && fastTemp->next->next){
            slowTemp = slowTemp->next;
            fastTemp = fastTemp->next->next;
        }
        return slowTemp;
    }

2.反转链表(参考

利用两个指针来反转

private:
    ListNode *reverseList(ListNode *head){
        //反转之后为链表的尾结点,故要定义一个指针指向NULL
        ListNode *tail = NULL;
        ListNode *cur = head;//当前要反转的结点
        while(cur){
            ListNode *nextCur = cur->next;
            //将结点放在尾部
            cur->next = tail;
            tail = cur;//tail指向反转后的节点cur
            //cur指针后移,等待处理下一个结点
            cur = nextCur;
        }
        return tail;
    }

3.合并链表

链接:合并两个有序链表(使用递归的思想)

本题:需要依次合并链表中的节点

private:
    void mergeList(ListNode *l1, ListNode *l2){
//        将后半部分的结点插入前半部分结点之后
        ListNode *tmp1 = NULL;
        ListNode *tmp2 = NULL;

        while(l1 && l2){
            //存储next节点
            tmp1 = l1->next;
            tmp2 = l2->next;
            //连接节点
            l1->next = l2;
            l2->next = tmp1;
            //指针后移
            l1 = tmp1;
            l2 = tmp2;
        }
    }
};

因此,整体代码为

class Solution
{

public:
    //填充本函数完成重排链表
    //利用找链表的中间结点和反转链表
    void reorderList(ListNode *head)
    {   //特殊情况判断:空链表
        if(head == NULL){
            return;
        }

        //1.寻找链的中间结点
        ListNode *midNode = midOfList(head);


        //p指向链表
        ListNode *fronts = head;

        //q指向中间结点
        ListNode *latter = midNode->next;
        midNode->next = NULL;
        //2.对中间结点的后半部分进行反转
        latter = reverseList(latter);

        //3.按顺序合并处理好的链表
        mergeList(fronts, latter);
    }

private:
    ListNode *midOfList(ListNode *head){
        //用快慢指针求中间结点
        ListNode *slowTemp = head;
        ListNode *fastTemp = head;
        while(fastTemp->next && fastTemp->next->next){
            slowTemp = slowTemp->next;
            fastTemp = fastTemp->next->next;
        }
        return slowTemp;
    }

private:
    ListNode *reverseList(ListNode *head){
        //反转之后为链表的尾结点,故要定义一个指针指向NULL
        ListNode *tail = NULL;
        ListNode *cur = head;//当前要反转的结点
        while(cur){
            ListNode *nextCur = cur->next;
            //将结点放在尾部
            cur->next = tail;
            tail = cur;//tail指向反转后的节点cur
            //cur指针后移,等待处理下一个结点
            cur = nextCur;
        }
        return tail;
    }

private:
    void mergeList(ListNode *l1, ListNode *l2){
//        将后半部分的结点插入前半部分结点之后
        ListNode *tmp1 = NULL;
        ListNode *tmp2 = NULL;

        while(l1 && l2){
            //存储next节点
            tmp1 = l1->next;
            tmp2 = l2->next;
            //连接 节点
            l1->next = l2;
            l2->next = tmp1;
            //指针后移
            l1 = tmp1;
            l2 = tmp2;

        }

    }

};

 

 

 

 

posted @ 2022-09-05 17:07  夏天最爱的冰淇淋  阅读(51)  评论(0)    收藏  举报