不管是指针还是引用,都是存储着所指对象的地址
p->next = x; //p的next指针指向x结点
x->next = p->next;//将x结点的next指针指向b结点
在第一行代码结束之后,已经不在指向原先的结点b,而是指向结点x;
像java有虚拟机自动管理的不需要考虑那么多,其他的语言在删除链表结点的时候,切记要手动释放内存空间,防止出现内存泄漏;
对于单链表中间结点的插入和删除,只需要两行代码即可搞定。但是首结点和尾结点的插入和删除逻辑就不一样了。
引入哨兵结点是为了解决边界问题,例如:head表示头结点指针,指向链表的第一个结点。在任何时候,不管链表是否为空,head指针都会指向这个哨兵结点,这种被称为带头链表。
想写出没有bug的链表代码,边界条件需要考虑全面,以下是两个常用的检查链表是否正确的边界条件:
1、反转一个单链表:
https://leetcode-cn.com/problems/reverse-linked-list/
设定两个指针,依次反转;注意边界条件,以及循环终止的条件即可。
class ListNode{
int val;
ListNode next;
ListNode(int x){
val = x;
}
}
class Solution{
public ListNode reverseList(ListNode head){
if(head == null || head.next == null){
return head;
}
ListNode p1 = head;
ListNode p2 = head.next;
head = null;
while(p2!=null){
ListNode temp = p2.next;
p2.next = p1;
p1 = p2;
p2 = temp;
}
return p1;
}
}
2、链表中环的检测
https://leetcode-cn.com/problems/linked-list-cycle/
这题的关键是设定两个快慢指针,当快慢指针相遇,说明链表有环,反之无环;
class ListNode{
int val;
ListNode next;
ListNode(int x){
val = x;
}
}
public class Solution{
public boolean hasCycle(ListNode head){
if(head == null || head.next == null){
return false;
}
ListNode slow = head;
ListNode fast = head;
while(fast!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
if(slow==fast){
return true;
}
}
return false;
}
}
3、合并两两有序链表
public class Solution{
public ListNode combine(ListNode head1,ListNode head2){
if(head1==null)
return head2;
else if(head2==null)
return head1;
ListNode p1 = head1;
ListNode p2 = head2;
ListNode head = new ListNode(0);
ListNode p3 = head;
while(p1!=null&&p2!=null){
if(p1.val<=p2.val)
{
p3.next=p1;
p1 = p1.next;
}else{
p3.next=p2;
p2 = p2.next;
}
p3 = p3.next;
}
if(p1!=null) {p3.next = p1; }
if(p2!=null) {p3.next = p2; }
return head.next;
}
}
4、删除链表倒数第n个结点
设置三个指针prev,p1 p2,二者分别指向头结点,p2,先向后移n个结点,p1 p2同时向后移,直到p2到达尾结点,prev用于记录p1结点的前驱节点,方便最终对p1删除。
public ListNode deleteLastKth(ListNode head,int n){
if(head == null) return head;
ListNode p1 = head;
ListNode p2 = head;
ListNode prev = null
for(int i=0;i<n;i++){
p2 = p2.next;
}
while(p2.next!=null){
prev = p1;
p1 = p1.next;
p2 = p2.next;
}
if(prev == null)
{
head = head.next;
}else{
prev.next = prev.next.next;
}
return head;
}
5、求链表的中间结点
同样是设定快慢指针,快指针是慢指针速度的两倍,当快指针到达尾结点的时候,此时慢指针,即为链表的中间节点;
public ListNode middleNode(ListNode head){
if(head==null||head.next==null) return head;
ListNode slow = head;
ListNode fast = head;
while(fast.next!=null&&fast.next.next!=null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
6、两两交换链表中的结点
https://leetcode-cn.com/problems/swap-nodes-in-pairs/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head==null||head.next==null)
return head;
ListNode prev = new ListNode(0);
prev.next = head;
ListNode self = head.next;
while(prev.next!=null&&prev.next.next!=null)
{
ListNode p1 = prev.next;
ListNode p2 = p1.next;
ListNode p3 = p2.next;
prev.next = p2;
p1.next =p3;
p2.next =p1;
prev = p1;
}
return self;
}
}