简介
从上一篇博客我们已经初步了解到了不带有哨兵节点的链表,这篇文我们就着重讲解哨兵节点,以及哨兵节点的作用。
首先什么是哨兵节点呢,简单来说哨兵节点就是一个value不为空节点 ,我们用图来解释一下。
我们用代码来构建一下含哨兵节点的链表。
public class SingLinkeList {//代表链表整体
Node werWu=new Node(666,null);
private Node head=werWu;;//头指针指向哨兵
/*
* 节点类
* */
private static class Node {
int value;//值00
Node next;//下一个节点指针
public Node(int value, Node next) {
this.value = value;
this.next = next;
}
}
}
与原来的不带哨兵的链表相比,不带哨兵的链表头指针直接指向了第一个节点,带哨兵节点的链表head指向了哨兵节点,相比之下两种链表,除了刚开始头指针的指向之外并没有什么很不一样的地方,那加哨兵节点的作用是什么。
private Node findLast() {
//首先判断链表是否为空
if (head == null) {
return null;
}
Node p;
//循环遍历链表,遍历完成返回节点
for (p = head; p.next != null; p = p.next) {
}
return p;
}
这是没有哨兵节点的链表的遍历,我们会发现,他在最开始的时候进行了链表是否为空的判断,但是当我们加了哨兵节点以后,我们的链表是不是永远都会有元素,不可能为空,就不会出现空指针异常的情况之类的,那么我们所有插入法中大部分关于空指针判断的地方是不是就可以删除掉了。
加入哨兵节点以后的三种插入方式代码演示:
//寻找尾部节点
private Node findLast() {
Node p;
for (p = head; p.next != null; p = p.next) {
}
return p;
}
//尾插法
public void addLast(int value) {
Node last = findLast();
last.next = new Node(value, null);
}
//根据索引查找节点
private Node findNode(int index){
int i=-1;
//从-1开始遍历,是因为入过在索引为0处插入,插入位置就不合法,因为index传过来等于0,findNode查找的就是-1,所以才从-1开始遍历。
for(Node p=head;p !=null;p=p.next,i++){
if(i==index){
return p;
}
}
return null;
}
//向索引位置插入
public void insertNode(int index, Integer value){
Node prev=findNode(index-1);
if(prev==null){
System.out.println("你插入的位置有误!!");
}
prev.next=new Node(value,prev.next);
}
//头插法
public void addFirst(int value) {
//相当于一种随机位置插入的特例
insertNode(0,null);
}
//删除索引位置节点
public void removeNode(int index){
Node beforeNode=findNode(index-1);
if(beforeNode==null){
System.out.println("删除索引不合法!");
}
Node pointNode=findNode(index);
if(pointNode.next==null){
System.out.println("删除索引不合法!");
}
beforeNode.next=pointNode.next;
}
//从头开始删除链表节点
public void removeFirst(){
removeNode(0);
}
总结
从上述代码可以看出,在加入了哨兵节点之后代码的复杂程度得到了极大程度的简化,由此可以看出哨兵节点的重要作用。