美文网首页
1025 反转链表

1025 反转链表

作者: 初见还是重逢 | 来源:发表于2019-03-08 20:28 被阅读0次

    给定一个常数 K 以及一个单链表 L,请编写程序将 L 中每 K 个结点反转。例如:给定 L 为 1→2→3→4→5→6,K 为 3,则输出应该为 3→2→1→6→5→4;如果 K 为 4,则输出应该为 4→3→2→1→5→6,即最后不到 K 个元素不反转。

    输入格式:

    每个输入包含 1 个测试用例。每个测试用例第 1 行给出第 1 个结点的地址、结点总个数正整数 N (≤10^​5)、以及正整数 K (≤N),即要求反转的子链结点的个数。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。

    接下来有 N 行,每行格式为:

    Address Data Next
    其中 Address 是结点地址,Data 是该结点保存的整数数据,Next 是下一结点的地址。

    输出格式:

    对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。

    输入样例:

    00100 6 4
    00000 4 99999
    00100 1 12309
    68237 6 -1
    33218 3 00000
    99999 5 68237
    12309 2 33218

    输出样例:

    00000 4 33218
    33218 3 12309
    12309 2 00100
    00100 1 99999
    99999 5 68237
    68237 6 -1

    思路:

    本题难度略高,有两个测试用例不好通过,一是大量的节点数据,查找超时的问题,二是不一定所有的节点都是有效节点,对于这种情况需要删除无效的节点
    例如这种:

    00100 6 2
    00000 4 99999
    00100 1 12309
    68237 6 -1
    33218 3 00000
    99999 5 77777
    12309 2 33218

    在这个测试用例中,节点5的下个地址是77777,但是并没有节点的地址是77777,因此在链表中5之后的节点就应该要删除,最后的结果应该是2-1-4-3-5


    image

    另外本题还需要注意的是:对于最后小于K的节点,是不需要逆序的。例如这个测试用例,最后剩两个节点5,6,个数是小于4的,因此5,6就不需要逆序,最后的结果应该是4-3-2-1-5-6

    00100 6 4
    00000 4 99999
    00100 1 12309
    68237 6 -1
    33218 3 00000
    99999 5 68237
    12309 2 33218

    image

    而解决查找速度的问题,本人使用了< algorithm >库中的find_if函数
    关于find_if函数,以后如有机会可以详细介绍一下,在这里的关键代码如下:

    先定义判断函数:

    class judge//对find_if算法的第三个函数参数的定义
    {
    private:
        int address;//judge函数是对节点node a进行判断,判断其地址是不是int address
    public:
        judge(int add) :address(add){}//必须对该类进行构造函数的定义,由于在find_if中,第三个参数需要传入一个变量add,需要判断该变量与node中的地址是否相同
        bool operator()(node a)//由于find_if第三个参数无法传入自己的node值,因此需要对操作符()进行重新定义,使其可以使用操作符来间接调用自己的值
        {
            return a.address == address;//判断judge(add),如果a与node a的address相同返回true
        }
    };
    

    可以直接调用函数查找下一个节点:

    vector<node>::iterator it;//先定义指针
    it = find_if(L.begin(), L.end(), judge(first));
    //找到地址为first的节点
    

    以上是该题的两个难点的解决方法。

    最后总结一下整个程序的思路


    image

    代码:

    反转链表

    //1025  反转链表
    //本题有两个难点,一是对于大量的节点数据,查找超时的问题,二是不一定所有的节点都是有效的节点,无效的节点应该删除
    #include<iostream>
    #include<vector>
    #include<algorithm>
    
    using namespace std;
    
    struct node//首先需要定义节点结构体
    {
        int address;
        int data;
        int next;
    };
    
    void exchange(node &a, node &b)//定义交换两个节点的函数
    {
        node temp;
        temp = a;
        a = b;
        b = temp;
        return;
    }
    
    class judge//对find_if算法的第三个函数参数的定义
    {
    private:
        int address;//judge函数是对节点node a进行判断,判断其地址是不是int address
    public:
        judge(int add) :address(add){}//必须对该类进行构造函数的定义,由于在find_if中,第三个参数需要传入一个变量add,需要判断该变量与node中的地址是否相同
        bool operator()(node a)//由于find_if第三个参数无法传入自己的node值,因此需要对操作符()进行重新定义,使其可以使用操作符来间接调用自己的值
        {
            return a.address == address;//判断judge(add),如果a与node a的address相同返回true
        }
    };
    
    int main()
    {
        int first, N, K;
        cin >> first >> N >> K;
        //存入第一行的首地址,节点个数,已经每隔K反转的值
    
        vector<node> L;//定义node数组L
        node temp;//临时存放node的值
        int  data, address, next;//存放每一行的地址,数据,下一个地址
        //将所有数据读取,然后每一行一次存入L中
        for (int i = 0; i < N; i++)
        {
            scanf("%d %d %d", &address, &data, &next);
            temp.address = address;
            temp.data = data;
            temp.next = next;
            L.push_back(temp);
        }
        //至此,将所有数组存储完毕
    
        vector<node>::iterator it;//定义数组指针
        it = find_if(L.begin(), L.end(), judge(first));//找到地址为first的节点使用find_if()函数,注意第三个变量是一个函数,函数的定义在上面,这个函数可以传入参数first
        exchange(*it, L[0]);//将地址为首地址的节点与L数组的第一个交换
    
      //从第二个元素开始查找,找到最后一个元素,将所有的节点按照节点的顺序进行排序
        for (int i = 1; i < N; i++)
        {
            it = find_if(L.begin() + i, L.end(), judge(L[i - 1].next));//从i的元素开始查找,查找地址为L[i-1]的下一个地址
            if (it != L.end())//如果找到将其与L[i]的后一个节点进行交换
                exchange(*it, L[i]);
            else//如果没有找到,证明i-1节点后面断了,后面的元素需要都删除
            {
                L.erase(L.begin() + i, L.end());
                break;
            }
        }
    
        //将有效的节点进行题目要求转序
        int count = L.size() / K;//计算需要转序的次数,例如有6个节点,K=4,只需要转序一次,K=2则需要转序3次
        it = L.begin();
        for (int i = 0; i < count; i++)//转序count次,每一次将it与it+K之间的进行转序
        {
            reverse(it, it + K);
            it += K;
        }
    
        //转序完后将每一个节点的next地址改为下一个节点的地址,并将最后一个节点的next地址设为-1
        for (int i = 0; i < L.size() - 1; i++)
        {
            L[i].next = L[i + 1].address;
        }
        L[L.size() - 1].next = -1;
    
        //按照要求输出结果
        for (int i = 0; i < L.size() - 1; i++)
        {
            printf("%05d %d %05d\n", L[i].address, L[i].data, L[i].next);
        }
        printf("%05d %d %d\n", (L.end() - 1)->address, (L.end() - 1)->data, (L.end() - 1)->next);
    
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:1025 反转链表

          本文链接:https://www.haomeiwen.com/subject/xqmdpqtx.html