——示例1链表:
方便链表中的对于特殊结点的操作,简化判断一个结点是否为空,下例为对单例表中向末尾插入
哨兵结点(sentinel):
可以简化边界条件,降低实现难度,它并不存储任何东西,只是为了操作的方便而引入的。
在链表中的插入、删除操作,需要对插入第一个结点和删除最后一个结点进行特殊处理,
比如插入时判断head结点是否null,使用哨兵结点后可以最大限度减少这种判断。
1.不使用哨兵
private Node head=null; //头结点
//插入
public void insert(Node node){
if(head==null)
head=node;
Node tmpHead=head;
while(tmpHead.next!=null){
tmpHead=tmpHead.next;
}
tmpHead.next=node;
}
2.使用哨兵结点
private final Node sentry = new Node(); //哨兵结点
private Node head = sentry; //**头结点指向哨兵结点,这样链表就不会为空了,
//插入
public void insert(Node node){
Node tmpHead=head;
while(tmpHead.next!=null){
tmpHead=tmpHead.next;
}
tmpHead.next=node;
}
使用哨兵结点后,可以用统一的代码进行实现,无论是不是第一个结点或者其他结点 ,减少链表对第一个元素是否为空的判断
同样,哨兵结点也可以放在最后 来简化删除最后一个结点的特殊处理
——示例2数组:
尾部哨兵 如果要在含n个数的数组array中找个数value
1.普通写法:
for (int i = 0; i < n; ++i) {
if (value == array[i])
return i;
}
2.使用哨兵:
array[n] = value;
for (int i = 0;; i++) {
if (value == array[i]) {
if (i != n)
return i;
}
}
假设n为9,array[8]为value,也就是数组中的最后一个元素是我们要找的数,
普通写法
int i=0 执行1次
i<n 执行9次
++i 执行8次
if (value == array[i]) 执行9次
return i 执行1次
假设每个操作消耗的时间单元是一样的,那么普通写法一共消耗了28个时间单元
使用哨兵
array[n] = value; 执行1次
int i = 0 执行1次
i++ 执行8次
if (value == array[i]) 执行9次
if (i != n) 执行1次
return i 执行1次
使用哨兵一共消耗了21个时间单元,可以看使用哨兵比普通写法节省了每次 i<n 的耗时,而这个消耗会随着n的增大而增大
刚才是要找的元素在数组中,如果不在数组中,使用哨兵也不会出现异常,因为原数组的末尾添加了我们要找的数字,一定会有value==array[i]时
判断该数字是否是我们手动添加的数字,也就是if (i != n),i==n即为我们手动添加的数字,若i!=n,则提前找到了value 该位置即为所求。