不能手牵手之双链表

双链表

还是先说一下,在程序设计语言中的双链表的概念。

继单链表之后,我们在来说一说另外的一种链表方式,双链表。

在内存的表现结构上,还是分成下面的两种方式:

1,就是连续的内存结构。

2,就是跳转的内存结构。

在程序设计中,连续的内存结构,就是数组。

跳转的数据结构包括很多,链表只是其中的一种表现方式。上一次已经把数组和单链表的内存结构图,画出来了,那么我们在来看看在

内存中,双链表的表现方式又是什么样的呢?

在看完以上的,内存结构图后,如果对双链表还是没有一个直观的感受的话,那么你就听听我说的这个故事吧,也许会给你不一样的启发。

话说,有这样一只队伍,队员有女性也有男性,队伍有着统一的着装(就是定义的双链表的结构),他们喜欢挑战极限。

有一次,他们需要经过一个悬崖峭壁,悬崖上面的只能通过一个人,每个人必须要背贴在悬崖上,慢慢的往前走才能通过,

这个时候,队长发话了,所有队员一致排开,“不能手牵手” “不能手牵手” “不能手牵手”,重要的事情说三遍,只能抓住

前一个人的腰带或者后一个人的腰带,才可以。于是乎每一个队员都按照要求,把队伍排好了,他们就开始出发过悬崖了。

想像一下这样的场景是不是,和我们内存的结构图很像。

至于为什么不能手牵手,我想是因为,队长可能害怕刚进队伍的同志,心里防线比较弱,会手心出汗,导致抓的不牢固,会带来危险。

那么好了再理解了这样的数据结构后,我们要怎么操作这样的数据结构呢?

我们还是先从取值开始演示:

class DoubleNodeList {
    int value;

    public DoubleNodeList(int val) {
        value = val;
    }

    DoubleNodeList next;
    DoubleNodeList last;
}

class Main {

    // 实现双列表逆序
    private static DoubleNodeList doubleNodeListRevert(DoubleNodeList head) {
        DoubleNodeList pre = null;
        DoubleNodeList next;
        while (head != null) {
            next = head.next;
            head.next = pre;
            head.last = next;
            pre = head;
            head = next;
        }
        return pre;
    }

    // 拼接两个有序链表
    private static NodeList sortNodeListSum(NodeList head1, NodeList head2) {
        //边界值判断,如果有一个链表是空的那么就返回
        if (head1 == null || head2 == null) {
            return head1 == null ? head2 : head1;
        }
        // 1,先找头,谁小谁当头,这个头一旦找到就不变到最后返回的还是这个头
        NodeList head = head1.value <= head2.value ? head1 : head2;
        // 2,找到头的下一个节点
        NodeList cur1 = head.next;
        NodeList cur2 = head == head1 ? head2 : head1;
        // 需要记录一个移动指针
        NodeList pre = head;

        while (cur1 != null && cur2 != null) {
            if (cur1.value <= cur2.value) {
                pre.next = cur1; // 如果链接的是当前连上的,那么 cur1 向下走一个
                cur1 = cur1.next;
            } else {
                pre.next = cur2; // 如果链接的是第二条链上的,那么 cur2 向下走一个
                cur2 = cur2.next;
            }

            pre = pre.next;
        }
        // 有可能一个短一个长
        pre.next = cur1 == null ? cur2 : cur1;
        return head;
    }


    public static void main(String[] args) {
        DoubleNodeList doubleNodeList = new DoubleNodeList(1);
        doubleNodeList.last = null;

        DoubleNodeList doubleNodeList2 = new DoubleNodeList(2);
        doubleNodeList.next = doubleNodeList2;

        doubleNodeList2.last = doubleNodeList;
        doubleNodeList2.next = null;
        while (doubleNodeList != null) {
            System.out.println(doubleNodeList.value);
            doubleNodeList = doubleNodeList.next;
        }
    }
}

上面的代码是有关,双链表的基本操作。关于双链表和单链表的操作,远比止于此。目前的话先掌握一些基本的,基础好了,在往上盖的话,会相对于容易些。如果文章中出现了错误,或者是描述不正确的地方,请大家积极指出来,一起学习一起进步。

小明和他的小伙伴们经常玩这样一个游戏: 假设有 k k位小朋友一起玩游戏,他们会站成一个圈。每个小朋友的手上有一个计数器,每轮游戏开始时, i i号小朋友的计数器值为 x i x i ​ 。每一个小朋友的脚下还有一个按钮,每按一下,这个小朋友的计数器值会 + 1 +1。 我们规定,当圈中两个相邻小朋友的计数器值相同时,这两个小朋友可以牵手。对于已经牵手的两个小朋友,当其中一个小朋友的计数器值增加时,另外一个也会跟着一起增加。 现在,他们想知道,所有人一共最少按下多少次按钮,可以使得这个圈中任意相邻两个小朋友都牵上手。 此外,小朋友是不断加入的。一开始只有 1 1号小朋友,接下来小朋友会按照编号为 2 , 3 , 4 , 5 , … , n 2,3,4,5,…,n的顺序一个一个加入,第 i i号小朋友加入时,会选择插入到 a i a i ​ 号小朋友顺时针的下一个位置。 比如,在 5 5号小朋友加入之前,四个小朋友按照顺时针顺序分别为 4 , 2 , 1 , 3 4,2,1,3,如果 a 5 = 4 a 5 ​ =4,则 5 5号小朋友加入后,这个圈按照顺时针顺序就变成了 4 , 5 , 2 , 1 , 3 4,5,2,1,3。 你的任务是,帮助他们计算出,每加入完一个小朋友后,如果他们新开始一轮游戏,最少按下多少次按钮呢? 【输入格式】 从文件game.in中读取数据 第一行一个整数 n n,表示小朋友的总数。 接下来一行 n n个整数, x 1 … n x 1…n ​ , x i x i ​ 表示每轮游戏开始时,编号为 i i的小朋友,计数器初始值为 x i x i ​ 。 接下来一行 n − 1 n−1个整数, a 2 … n a 2…n ​ , a i a i ​ 表示当小朋友 i i加入进来时会站在编号为 a i a i ​ 的小朋友的顺时针的下一个位置。 【输出格式】 输出到文件game.out中 输出 n − 1 n−1行,每行一个整数。表示当小朋友 2 , 3 , 4 , … , n 2,3,4,…,n加入后,玩一局游戏的最少按按钮的次数。 【输入样例 1】 4 2 3 4 1 1 2 3 【输出样例 1】 1 2 3 【样例 1解释】 当第二个小朋友加入后,环上的顺序为 1 , 2 1,2,他们计数器的初始值为 2 , 3 2,3。只需要让小朋友 1 1按一次按钮,就可以让两人牵手。 当第三个小朋友加入后,环上的顺序为 1 , 2 , 3 1,2,3,他们计数器的初始值为 2 , 3 , 4 2,3,4。他们玩游戏时: 先让小朋友 1 1按一次按钮,此时计数器的值变为了 3 , 3 , 4 3,3,4,小朋友 1 1和小朋友 2 2计数器相同,可以牵手。 接下来让小朋友 1 1再按一次按钮。由于 1 1和 2 2已经牵手,所以他们计数器的值会同时增加 1 1。计数器的值为 4 , 4 , 4 4,4,4。此时所有小朋友计数器都相同,游戏结束。 当第四个小朋友加入后,环上的顺序为 1 , 2 , 3 , 4 1,2,3,4,他们计数器的初始值分别为 2 , 3 , 4 , 1 2,3,4,1。他们玩游戏时: 先让小朋友 4 4按一次按钮。接下来小朋友 1 1和小朋友 4 4可以牵手。 让小朋友 1 1按一次按钮,小朋友 1 1和小朋友 4 4计数器会同时增加,此时小朋友 1 1和小朋友 2 2可以牵手。 让小朋友 2 2按一次按钮,小朋友 1 , 2 , 4 1,2,4计数器会同时增加。此时所有小朋友计数器都相同,游戏结束。 大样例 【数据范围与约定】 对于 20 % 20%的数据满足: n ≤ 100 n≤100 对于 40 % 40%的数据满足: n ≤ 10 4 n≤10 4 对于另外 20 % 20%的数据满足: x i x i ​ 单调递增, a i = i − 1 a i ​ =i−1 对于 100 % 100%的数据满足: 1 ≤ n ≤ 10 6 1≤n≤10 6 1 ≤ x i ≤ 10 9 1≤x i ​ ≤10 9 1 ≤ a i < i 1≤a i ​ <i
08-17
小明和他的小伙伴们经常玩这样一个游戏: 假设有 � k位小朋友一起玩游戏,他们会站成一个圈。每个小朋友的手上有一个计数器,每轮游戏开始时, � i号小朋友的计数器值为 � � x i ​ 。每一个小朋友的脚下还有一个按钮,每按一下,这个小朋友的计数器值会 + 1 +1。 我们规定,当圈中两个相邻小朋友的计数器值相同时,这两个小朋友可以牵手。对于已经牵手的两个小朋友,当其中一个小朋友的计数器值增加时,另外一个也会跟着一起增加。 现在,他们想知道,所有人一共最少按下多少次按钮,可以使得这个圈中任意相邻两个小朋友都牵上手。 此外,小朋友是不断加入的。一开始只有 1 1号小朋友,接下来小朋友会按照编号为 2 , 3 , 4 , 5 , … , � 2,3,4,5,…,n的顺序一个一个加入,第 � i号小朋友加入时,会选择插入到 � � a i ​ 号小朋友顺时针的下一个位置。 比如,在 5 5号小朋友加入之前,四个小朋友按照顺时针顺序分别为 4 , 2 , 1 , 3 4,2,1,3,如果 � 5 = 4 a 5 ​ =4,则 5 5号小朋友加入后,这个圈按照顺时针顺序就变成了 4 , 5 , 2 , 1 , 3 4,5,2,1,3。 你的任务是,帮助他们计算出,每加入完一个小朋友后,如果他们新开始一轮游戏,最少按下多少次按钮呢? 【输入格式】 从文件game.in中读取数据 第一行一个整数 � n,表示小朋友的总数。 接下来一行 � n个整数, � 1 … � x 1…n ​ , � � x i ​ 表示每轮游戏开始时,编号为 � i的小朋友,计数器初始值为 � � x i ​ 。 接下来一行 � − 1 n−1个整数, � 2 … � a 2…n ​ , � � a i ​ 表示当小朋友 � i加入进来时会站在编号为 � � a i ​ 的小朋友的顺时针的下一个位置。 【输出格式】 输出到文件game.out中 输出 � − 1 n−1行,每行一个整数。表示当小朋友 2 , 3 , 4 , … , � 2,3,4,…,n加入后,玩一局游戏的最少按按钮的次数。 【输入样例 1】 4 2 3 4 1 1 2 3 Copy 【输出样例 1】 1 2 3 Copy 【样例 1解释】 当第二个小朋友加入后,环上的顺序为 1 , 2 1,2,他们计数器的初始值为 2 , 3 2,3。只需要让小朋友 1 1按一次按钮,就可以让两人牵手。 当第三个小朋友加入后,环上的顺序为 1 , 2 , 3 1,2,3,他们计数器的初始值为 2 , 3 , 4 2,3,4。他们玩游戏时: 先让小朋友 1 1按一次按钮,此时计数器的值变为了 3 , 3 , 4 3,3,4,小朋友 1 1和小朋友 2 2计数器相同,可以牵手。 接下来让小朋友 1 1再按一次按钮。由于 1 1和 2 2已经牵手,所以他们计数器的值会同时增加 1 1。计数器的值为 4 , 4 , 4 4,4,4。此时所有小朋友计数器都相同,游戏结束。 当第四个小朋友加入后,环上的顺序为 1 , 2 , 3 , 4 1,2,3,4,他们计数器的初始值分别为 2 , 3 , 4 , 1 2,3,4,1。他们玩游戏时: 先让小朋友 4 4按一次按钮。接下来小朋友 1 1和小朋友 4 4可以牵手。 让小朋友 1 1按一次按钮,小朋友 1 1和小朋友 4 4计数器会同时增加,此时小朋友 1 1和小朋友 2 2可以牵手。 让小朋友 2 2按一次按钮,小朋友 1 , 2 , 4 1,2,4计数器会同时增加。此时所有小朋友计数器都相同,游戏结束。 大样例 【数据范围与约定】 对于 20 % 20%的数据满足: � ≤ 100 n≤100 对于 40 % 40%的数据满足: � ≤ 10 4 n≤10 4 对于另外 20 % 20%的数据满足: � � x i ​ 单调递增, � � = � − 1 a i ​ =i−1 对于 100 % 100%的数据满足: 1 ≤ � ≤ 10 6 1≤n≤10 6 1 ≤ � � ≤ 10 9 1≤x i ​ ≤10 9 1 ≤ � � < � 1≤a i ​ <i
08-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值