写链表的时候,必须保证引用不为空引用。像cur.next!=null,这种代码得保证cur不为空。
1 链表插入
1.1 不带傀儡结点的插入
1.1.1 插入到链表的中间位置
注:(只变化next存放的地址 需要找到待插入节点前一个位置)
例如:把100这个节点插入到1和2之间
把100这个节点插入到1和2之间,此时需要先知道1(待插入位置的前一个节点)这个节点的引用
- 定义一个prev引用,里面存放1的地址
Node pre=new Node(1); - 定义一个cur引用,里面存放新节点的地址
Node cur=new Node(100); 关键代码:
1.先修改cur.的指向,让cur指向2(即cur.next存放2的地址)
cur.next=prev.next;
2.pre 指向cur(pre的next存放cur的地址)
prev.next=cur;
1.1.2 头节点插入(插入到链表的头结点,使之为头结点)
注:头结点插入会影响head指向,之前的插入中间位置,需要找到待插入位置的前一个位置。但是头插前面没有位置
关键代码: 1.先让cur的next指向head cur.next=head; 2.再让head指向新节点 head=cur;
1.3 尾插和中间插的(插入)关键代码相同(要找到末尾结点)
思路:先找到末尾结点,然后进行插入
public static void insertTail(Node head,int val){
if (head==null){
return ;
}
Node prev=head;
while(prev.next!=null){
prev=prev.next;
}
Node cur=new Node(10);
cur.next=prev.next;
prev.next=cur;
}
1.2 带傀儡结点的插入
注:不带傀儡结点的链表,插入中间位置和插入头部是两种不同的代码。 带傀儡结点插入把两个操作统一。 此时的头插也相当于中间插.
1.2.1 中间插(要找到待插入结点前一个结点的位置)
public class Main {
public static void main(String[] args) {
Node head= createListWithDummy();
Node prev=head.next;
Node cur=new Node(10);
cur.next=prev.next;
prev.next=cur;
}
private static Node createListWithDummy() {
Node dummy=new Node(100);
Node a=new Node(1);
Node b=new Node(2);
Node c=new Node(3);
Node d=new Node(4);
dummy.next=a;
a.next=b;
b.next=c;
c.next=d;
d.next=null;
return dummy;
}
}
1.2.2头插
注:插入到所有元素之前,也就是傀儡结点的后面
关键代码: cur.next=prev.next; prev.next=cur;
public class Main {
public static void main(String[] args) {
Node head= createListWithDummy();
Node prev=head;
Node cur=new Node(10);
cur.next=prev.next;
prev.next=cur;
}
private static Node createListWithDummy() {
Node dummy=new Node(100);
Node a=new Node(1);
Node b=new Node(2);
Node c=new Node(3);
Node d=new Node(4);
dummy.next=a;
a.next=b;
b.next=c;
c.next=d;
d.next=null;
return dummy;
}
}
总结
1.带傀儡结点的头结点插入和中间插插入,代码相同 2.不带傀儡结点的头插和尾插
2.链表的删除
2.1不带傀儡结点
2.1.1 删除中间结点(找到前一个结点位置)
remove() 返回新的head的位置。 关键代码:prev.next=toDelete.next
2.1.1.1 按值删除
public static Node remove(Node head,int value){
if(head==null){
return null;
}
if(head.val==value){
head=head.next;
return head;
}
Node prev=head;
while(prev !=null && prev.next!=null && prev.next.val != value){
prev=prev.next;
}
if(prev==null && prev.next==null){
return head ;
}
Node toDelete=prev.next;
prev.next=toDelete.next;
return head;
}
2.1.1.2 按位置删除
public static Node remove(Node head,Node toDelete){
if(head==null){
return null;
}
if(head==toDelete){
head=head.next;
return head;
}
Node prev=head;
while(prev !=null && prev.next!=toDelete){
prev=prev.next;
}
if(prev==null){
return null ;
}
prev.next=toDelete.next;
return head;
}
2.1.1.3按下标删除
public static Node remove(Node head,int index){
if(index<0 || index>size(head)){
return null;
}
if(index==0){
head=head.next;
return head;
}
Node prev=head;
for(int i=0;i<index-1;i++){
prev=prev.next;
}
Node toDelete=prev.next;
prev.next=toDelete.next;
return head;
}
尾删
public static Node removeTail(Node head){
if(head==null){
return null;
}
if(head.next==null){
return null;
}
Node prev=head;
while(prev!=null && prev.next!=null && prev.next.next!=null){
prev=prev.next;
}
Node toDelete=prev.next;
prev.next=toDelete.next;
return head;
}
2.1.2 删除链表的头结点
最关键的代码:head=head.next;
2.2带傀儡结点(不常用)
public static void removeWithDummy(Node head,int val){
Node prev=head;
while(prev!=null &&prev.next!=null && prev.next.val!=val){
prev=prev.next;
}
if(prev==null || prev.next==null){
return;
}
Node toDelete=prev.next;
prev.next=toDelete.next;
return;
}
总结:
不带傀儡结点的删除,头删和中间删,删除方式不一样。 带傀儡节点的删除,头删和中间删,山出发那个是相同
|