数据结构:LinkedList与链表
1:链表的概念及结构:
逻辑上连续,物理上不一定连续

重点掌握

2:创建MySingleList类
再定义一个内部类ListNode,整形val为节点的值域,ListNode型的next为下一个节点的地址,再给出一个带参数的构造方法用于初始化val。再定义head为链表的头结点,size为链表的长度。

3:createList方法:创建链表
用new关键字实例化5个节点并分别赋值,然后用next指针连接起来,并将node1设置为头节点。

效果图:

4:addFirst方法:在链表头部插入元素
先实例化node对象,并赋值为data。
再判断头结点是否为空,如果为空将node赋值给head。
如果不是将node的next指针设为head,再将node赋给head。

5:addLast方法:在链表尾部插入元素:
new关键字实例化node对象,并赋值为data。
判断head是否为空,如果为空直接把node赋给head,结束程序。
创建一个cur对象并其赋值为head。
用while循环遍历到链表最后一个元素,此时设cur的next指针为node。

6:add方法:任意位置插入元素
先判断下标是否小于0或大于链表长度,如果是就结束程序。
如果下标为0,调用头插法;如果下标为链表长度,调用尾插法。
都不是创建node对象,赋值为data,调用subNode1方法找到pos位置的前一个元素sub,把sub的next指针赋给node的next指针,实现插入的操作(改线),最后让sub的next指针指向node。

效果图:


输出结果:

7:find方法:查找是否包含关键字key在链表中
创建一个cur对象,将head赋值给它。
用while循环遍历链表,如果某个cur的val值等于key,返回true。如果遍历完也没找到,返回false。

8:remove方法:删除第一次出现关键字为key的节点
创建一个cur节点,并将head赋值给它。
然后用while循环遍历链表,如果某个cur的val值等于key,则通过subNode2方法找到key的前一个结点sub,让sub的next指针指向原本cur指向的next指针,也就是cur的下一个元素,相当于改线间接跳过了cur,达到了删除cur的效果。

9:subNode2方法:找到数值为data的元素的前一个元素
创建cur对象,并将head赋值给它。
用while循环遍历链表,如果cur的下一个元素的值等于data,返回cur,如果没有就返回null。

10:removeAllKey方法:删除所有值为key的结点(面试题1)
创建对象cur和node1,将head赋值它们。
创建对象node2,将head的下一个元素赋值给它。
如果头结点的val值等于key,将head向后移一个,删除第一个头结点。
然后用while循环遍历链表,如果node2的val值等于key,让node1的next指针指向node2的下一个元素,不再指向node2,然后node2向后移一个,原来的node2位置的元素就被删除了。
如果node2的val值不等于key,就将node1赋值给node2,让两者处于同一个结点上,node2往后移一个,直到遍历完链表

11:display方法:遍历链表
定义cur对象,并把head赋值给它。
然后用while循环遍历链表,打印每个节点的val值,同时计算链表的长度。

12 :size方法:计算链表的长度
用while循环遍历链表,然后size++


输出结果:

13:clear方法:清空链表
将头结点置为空。

14:reverseList方法:反转一个单链表(面试题2)
(1)如果链表为空,直接返回空。
(2)如果链表的头结点的next为空,直接返回head。
(3)将头结点的next指针赋给cur,再将头结点的next指针置为空,达到反转的效果。
(4)while循环遍历链表,创建curNext用于保存的cur的next指针,然后将cur的next指针指向头结点,再移动头结点到cur位置上,cur再移动到下一个节点,直到完成逆转。

效果图:


输出结果:

15:middleNode方法:返回链表的中间节点(面试题3)
创建两个节点fast和slow,都赋值为head。
然后用while循环,让fast速度是slow的两倍,遍历整个链表,最后slow所在的节点就是中间节点。

效果图:


输出结果:

16:findKthToTail方法:返回该链表中倒数第K个结点 (面试题4)
此题的核心思想:让fast先走k-1步,再让fast和slow同步走,最终返回倒数第k个结点。

效果图:


输出结果:

17:mergeTwoLists方法:拼接两个链表 (面试题5)
(1)创建两个节点newHead和tmpHead,并没有实际含义的结点。
(2)然后while循环遍历链表,headA和headB都不为空,如果headA的val大于headB,tmpHead的next指针指向headB,然后headB向后移动一个长度。反之同理。
(3)最后判断完以后,tmpHead往后移动一个节点。

(1):链表B遍历完了,剩下的结点就放到链表A里面。
(2):链表A遍历完了,剩下的结点就放到链表B里面。
(3):最后返回newHead的next指针,就是两个链表的中头结点val值更小的那个结点。

示意图:

在main方法中运行:

输出结果:

18:partition方法:以定值x为基准把链表分成两部分,小于x的结点排在前,大于x的结点排在后。(面试题6)
将链表分为两部分,前半部分的头和尾分别为bs和be,后半部分的头和尾分别为as和ae,将head赋值给cur。

然后用while循环遍历链表:
(1)如果cur的val值比x小,判断bs是否为空,如果为空就cur赋值给bs和be,如果不是就把cur赋给be的next指针,be再往后移一个。
(2)如果cur的val值比x大,as和ae的操作与bs和be同理。

让前半部分的尾部be的next指针指向后半部分的头部as。
为了防止最大的元素不是最后一个,要将ae的next指针置为空。
再将bs赋给cur1,用while循环遍历分隔后的链表。

效果图:


输出结果:

19:chkPalindrome方法:判断链表是否回文(面试题7)
(1)要先找到链表的中间节点,然后反转链表,与前面提到过的方法一致,最后比较val值,如果不一样就返回false,全部一样就返回true。

输出结果:

20:getIntersectionNode方法:输入两个链表,找到它们的第一个公共节点 。(面试题8)
首先普及一个误区,不是数值一样就是公共节点,而是像第2条链表的第二个结点一样,其next指针指向第一个链表的结点,实现相交,呈现Y字形。

效果图:

(1)分别设定链表A和链表B的长度为lenA和lenB。
(2)设pl指向的是最长的链表的头结点,ps指向的是最短的链表的头结点。
(3)然后用while循环遍历链表,分别求出lenA和lenB的长度。
(4)再次将headA和headB分别赋给pl和ps。

(1)求出lenA和lenB的长度差len,如果差值小于0,则说明A的长度小于B,将headB赋给pl,将headA赋给ps,用lenB减去lenA,确保len是正数。
(2)用while循环,让pl遍历完比ps长的那一部分。
(3)再用while循环,分别让pl和ps遍历链表,直到相遇,返回pl。
(4)创建一个方法相交链表,为的是能在idea上实现代码的运行。


效果图:

在main方法中运行:

输出结果:

21: hasCycle方法:判断链表是否有环(面试题9)
(1)先判断头结点是否为空,为空直接返回false。
(2)再定义两个节点fast和slow,同时赋值给head,然后用while循环遍历链表,fast走的速度是slow的两倍,如果fast和slpw相遇了返回true,遍历完了没相遇返回false。

效果图:


输出结果:

22:detectCycle方法:返回链表入环的第一个节点,如果链表无环则返回null(面试题10 )
(1)如果头结点为空,直接返回空。
(2)然后定义两个节点fast和slow,同时赋值为head。
(3)然后用while循环遍历链表,fast的速度是slow的2倍,如果fast和slow相遇了就结束循环。

如果fast或者fast的next指针为空,则说明链表无环,直接返回空。
然后再次把头结点赋给fast,再通过while循环,让fast和slow一步一步走,直到相遇,最后返回相遇结点。

createLoop方法:创建一个环。
通过while循环,遍历到链表最后一个结点,让这个结点的next指针指向头结点的next,也就是链表的第二个结点,形成一个环。

效果图:

在main方法中调用:

输出结果:

1:无头双向链表
效果图:

2:创建MyLinkedList链表
创建内部类ListNode,定义数值val, ListNode类型的prev和next指针,同时给出一个构造方法实例化数值val,然后定义head和last结点和size长度。

3:addFirst方法(在链表头部插入元素)
如果头结点为空,将node赋给head和last。
绕过node的next指针指向头结点,再让head的prev的指针指向node,最后把node赋给head。

示意图:

4:addLast尾插法:插入尾部元素
如果头结点为空,把node赋给head和last。
让last的next指针指向node,让node的prev指针指向last,把node赋给node。

示意图:

5:addIndex方法:任意位置插入
(1)先判断下标index是否违规,如果是则直接结束程序。
(2)然后找到下标为index的元素cur,实例化数值为data的结点node。
(3)再让node的next指向cur,再让node的前一个结点的next指针指向node,再让node的prev指针指向cur的前一个元素,最后让cur的prev的指针指向node。

searchIndex方法:通过while循环找到下标为index的元素。

示意图:

6:contain方法:查找链表中是否包含某元素
用while循环遍历链表,如果某个cur.val等于key,直接返回true。

7: size方法:求链表的长度
用while循环遍历链表,同时size++,最后返回size。

8:clear方法:清空链表
通过while循环,将每个结点的prev和next指针、head和last都置为空。

在main方法中调用:

输出结果:
9:remove方法:删除第一次出现的关键字key

思路图:


思路分析:

在main方法中调用:

输出结果:

10:removeAllKey方法:删除所有的关键字的key

大体思路:与remove方法差不多,但是删除key以后还要继续遍历链表


思路分析:

在main方法中运行:

输出结果:

11:ArrayList与LinkedList的区别:
ArrayList的核心是数组,LinkedList的核心是改线。
