五种常见操作
以下代码都是针对引入哨兵的带头链表
1、单链表反转
原地反转
public static Node reverseLinkList(Node head){
if(head.next == null){
return head;
}
Node prev = head.next;
Node pcur = prev.next;
while(pcur != null){
prev.next = pcur.next;
pcur.next = head.next;
head.next = pcur;
pcur = prev.next;
}
return head;
}
头插法反转
public static Node reverseLinkList(Node head){
if(head.next == null){
return head;
}
Node newHead = new Node();
Node pcur = head.next;
Node curNextTmp = null;
while(pcur != null){
curNextTmp = pcur.next;
pcur.next = newHead.next;
newHead.next = pcur;
pcur = curNextTmp;
}
return newHead;
}
2、链表中环检测
快慢指针法
- 两个指针同时从第一个数据节点开始,pFast每次移到两个节点,pSlow每次移到一个节点
- pFast先到尾部即pFast == null,说明没有闭环
- 如果有闭环 则最终两个指针会相遇即 pFast==pSlow
public static boolean hasLoop(Node head){
if(head.next==null){
return false;
}
Node pFast = head.next;
Node pSlow = head.next;
while (pFast!=null&&pSlow!=null){
pFast = pFast.next.next;
pSlow = pSlow.next;
if(pFast==null){
//这个判断不能少,否则可能会陷入死循环
return false;
}else if(pFast==pSlow){
return true;
}
}
return false;
}
3、两个有序链表合并
递归
- 递归代码简洁,不递归通过迭代也可以通过两个指针遍历解决;
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null&&l2==null){
return null;
}else if(l1==null){
return l2;
}else if(l2==null){
return l1;
}
//递归
ListNode l3;
if(l1.val > l2.val){
l3=l2;
l3.next=mergeTwoLists(l1,l2.next);
}else{
l3=l1;
l3.next=mergeTwoLists(l1.next,l2);
}
return l3;
//迭代
/*ListNode head = new ListNode(-1);
ListNode pcur = head;
while(l1!=null && l2!=null){
if(l1.val<=l2.val){
pcur.next = l1;
l1 = l1.next;
}else{
pcur.next = l2;
l2 = l2.next;
}
pcur = pcur.next;
}
pcur.next = l1==null?l2:l1;
return head.next;*/
}
4、删除链表倒数第 n 个节点
快慢指针法
- 让fast指针先移动n个节点之后slow节点再加入一起向后移动,直至fast==null,此时slow指向的就时倒是第N个;
- 链表为空或者n小于0或者超出链表长度返回null;
public static Node removeNthFromEnd(Node head,int n){
if(head.next==null || n<=0){
return head;
}
//fast和slow都指向哨兵
Node fast = head;
Node slow = head;
int count = 0;
//循环结束条件要注意时fast.next!=null
//如果时fast!=null,则n=1的时候会出问题
//注意边界条件
while (fast.next!=null){
if(count<n){
//这里至少会执行一次
fast = fast.next;
count++;
}else{
fast = fast.next;
slow = slow.next;
}
}
slow.next = slow.next.next;
return head;
}
5、求链表的中间节点
快慢指针法
- fast每次移动两个节点,slow每次移动一个节点同时向尾部移动,fast.next==null时结束,此时slow指向中间节点
public static Node middleNode(Node head) {
if (head.next == null) {
return head;
}
Node slow = head;
Node fast = head;
//长度可能为奇数和偶数,奇数结束fast==null,偶数结束fast.next==null
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
熄灯
以上代码链表都是引入哨兵的带头链表