一. 链表有无头结点的区别(单链表)
首先
我们需要了解,删除节点p, 我们只需要找到 p的上一个结点pre的位置, 进行 pre.next = p.next 即可。
头结点: 指针域指向首元结点(具有实际意义的第一个元素结点) ,数据域可以不存任何信息,指针域指向单链表第一个元素的结点。头结点可有可无,但为了操作方便,一般情况下单链表都具有头结点
优点:
为了减少程序的复杂性(添加和删除操作,在首元结点上有区别与其他的操作 ), 如果链表没有头结点,则删除或添加时都得需要判断一次首元结点,有了头结点以后,首元结点实际为链表的第二个结点,可以使得在添加删除的操作上更具有统一性
缺点: 会多出一个不必要的空间
1 Example1 有头结点
// 题目大意:删除,值为val的结点(单次删除), 并返回头结点
public ListNode removeElement(ListNode head, int val) {
if(head.next==null) return head;//空链表
ListNode pre = head, p = head.next;
while(p.val!=val&&p.next!=null) {
pre = p;
p = p.next;
}
if(p.val==val) {
pre.next = p.next;
}else {
//此链表无,值为val的结点
}
return head;
}
}
1 Example2 无头结点
// solution 1 使用上面 "Example1 无头结点"的解法,最后再处理head ---> Acceted / Used
public ListNode removeElements(ListNode head, int val) {
if(head==null) return head;//空链表
ListNode pre = head, p = head.next;
if(p!=null) {
while(p.val!=val&&p.next!=null) {
pre = p;
p = p.next;
}
if(p.val==val) {
pre.next = p.next;
return head;
}else {
//此链表无,值为val的结点
}
}
if(head.val==val) head = head.next;//最后判断头结点
return head;
}
}
//solution 2
public ListNode removeElements(ListNode head, int val) {
if(head==null) return head;//空链表
ListNode p = head, pre;
while(p.val!=val&&p.next!=null) {
pre = p;
p = p.next;
}
if(p.val==val) {
if(p==head) {// 多次此处的条件,相比于 "Example1 无头结点"
return head = p.next;
}else {
pre.next = p.next;
}
}else {
//此链表无,值为val的结点
}
return head;
}
}
1 Example3 无头结点(删除链表中所有值为val的结点)
//Solution 1 迭代 ---> 根据上面"Example2 无头结点 solution 1" 拓展使用 --->Acceted / Used
// 耗时 O(n),空间O(1)
public ListNode removeElements(ListNode head, int val) {
if(head==null) return head;//空链表
ListNode pre = head, p = head.next;
while(p!=null) {
while(p.val!=val&&p.next!=null) {
pre = p;
p = p.next;
}
if(p.val==val) {
pre.next = p.next;
}else {
//此链表无,值为val的结点
}
p = p.next;
}
if(head.val==val) head = head.next;//最后判断头结点
return head;
}
}
//Solution 2 递归 --->Acceted 时空都是O(n),
//
public ListNode removeElements(ListNode head, int val) {
if(head==null) {
return head;
}
head.next = removeElements(head.next,val);//当前结点只需要考虑下一个节点即可,递归即可
return head.val==val?head.next:head;//从后面开始判断,返回head/head.next 即可
}
//Solution 3 官方:构造有头结点的链表 ---> (Acceted / Used) Optimally
//题解链接https://leetcode.cn/problems/remove-linked-list-elements/solution/yi-chu-lian-biao-yuan-su-by-leetcode-sol-654m/
// 耗时 O(n),空间O(1)
public ListNode removeElements(ListNode head, int val) {
ListNode pre = new ListNode(0);
pre.next = head;
ListNode temp = pre;
while(temp.next!=null) {
if(temp.next.val==val) {
temp.next = temp.next.next;//指针指向
}else {
temp = temp.next;//指针指向
}
}
return pre.next;
}
//(含头结点)单链表的节点删除,增加—最易犯错!!!
https://blog.csdn.net/weixin_46273997/article/details/106087607