无论以何种存储方式实现线性表,都要支持线性表的基础操作。如果head指针直接指向表头结点,那么执行删除操作且被删除的是头结点,则必须修改头指针,令其指向新的头结点,插入操作也会遇到类似的问题。解决的方法是在表的前端增加一个特殊的表头结点,称为哨位结点。
哨位结点的结构与其他表结点结构相同。也是由数据域与指针域构成的,但数据域没有被赋值。指针域则存储指向第一个真正表结点的指针。需要说明的是,哨位结点不被看做表中的实际结点,链表中的第k个结点仍然是第k个实际的表结点,若表中只有哨位结点,则称其为空链表,即表的长度为0.
/**
* 单链表结点类
* @author liangxiamoyi
*
* @param <T>
*/
public class SLNode<T> {
/**
* 数据域
*/
protected T data;
/**
* 下一个结点
*/
protected SLNode<T> nextNode;
/**
* 构造方法
* @param node 下一结点
*/
public SLNode(SLNode<T> node){
this.nextNode=node;
}
/**
* 构造方法
* @param data 数据
* @param node 下一结点
*/
public SLNode(T data,SLNode<T> node){
this.data=data;
this.nextNode=node;
}
/**
* 获得数据
* @return
*/
public T getData(){
return data;
}
/**
* 获得下一结点
* @return
*/
public SLNode<T> getNextNode(){
return nextNode;
}
/**
* 设置数据
* @param data
*/
public void setData(T data){
this.data=data;
}
/**
* 设置下一结点
* @param node
*/
public void setNextNode(SLNode<T> node){
this.nextNode=node;
}
}
/**
* 单链表类
* @author liangxiamoyi
*
* @param <T>
*/
public class SLList<T>{
/**
* 表头
*/
private SLNode<T> head;
/**
* 表尾
*/
private SLNode<T> tail;
/**
* 当前结点
*/
private SLNode<T> currNode;
/**
* 单链表大小
*/
private int size;
/**
* 构造只有一个哨位结点的空表
*/
public SLList(){
this.head=new SLNode<T>(null);
this.size=0;
}
/**
* 构建有一个结点的单链表
* @param item 数据域
*/
public SLList(T item){
tail=currNode=new SLNode<T>(item,null);
head=new SLNode<T>(currNode);
size=1;
}
/**
* 判断是否为空
* @return
*/
public boolean isEmpty(){
return head.getNextNode()==null;
}
/**
* 得到单链表的长度
* @return
*/
public int getSize(){
return this.size;
}
/**
* 存取,得到第k个结点的数据域
* @param k 第k个结点
* @return 返回第k个结点的数据
*/
public T find(int k){
if(k<0||k>size||size==0){
throw new RuntimeException("empty list or unreasonable position!");
}
currNode=head.nextNode;
for(int i=2;i<=k;i++){
currNode=currNode.nextNode;
}
return currNode.data;
}
/**
* 查找,得到第一个数据为item的结点的位置
* @param item 数据
* @return 位置
*/
public int search(T item){
currNode=head.nextNode;
for(int i=1;i<=size;i++){
if(currNode.data==item)return i;
else{
currNode=currNode.nextNode;
}
}
return -1;
}
/**
* 删除当前结点的后继结点,并将其数据返回
* @return
*/
public T delete(){
if(currNode==tail||isEmpty()){
throw new RuntimeException("no next node or empty list");
}
SLNode<T> temp=currNode.nextNode;
currNode.setNextNode(temp.nextNode);
size--;
if(temp==tail){
tail=currNode;
}
return temp.data;
}
/**
* 删除哨位结点后的第一个真正表结点,并将数据返回
* @return
*/
public T deleteFromHead(){
if(isEmpty()){
throw new RuntimeException("empty list");
}
SLNode<T> temp=head.nextNode;
head.setNextNode(temp.nextNode);
size--;
if(temp==tail){
tail=head;
}
return temp.data;
}
/**
* 删除表尾结点,并将数据返回
* @return
*/
public T deleteFromTail(){
if(isEmpty()){
throw new RuntimeException("empty list");
}
if(currNode==tail){
currNode=head;
}
SLNode<T> temp=currNode;
while(temp.nextNode!=tail){
temp=temp.nextNode;
}
SLNode<T> node=tail;
tail=temp;
size--;
return node.data;
}
/**
* 在当前结点后插入一个数据为item的结点
* @param item
*/
public void insert(T item){
currNode.setNextNode(new SLNode<T>(item,currNode.getNextNode()));
if(tail==currNode){
tail=currNode.getNextNode();
}
size++;
}
/**
* 从表尾插入一个数据为item的结点
* @param item
*/
public void insertFromTail(T item){
tail.setNextNode(new SLNode<T>(item,null));
tail=tail.getNextNode();
size++;
}
/**
* 在哨位结点后插入一个数据为item的结点
* @param item
*/
public void insertFromHead(T item){
if(isEmpty()){
head.setNextNode(new SLNode<T>(item,head.getNextNode()));
tail=head.getNextNode();
}
else{
head.setNextNode(new SLNode<T>(item,head.getNextNode()));
}
size++;
}
/**
* 打印所有结点的数据
*/
public void showNodes(){
currNode=head.nextNode;
for(int i=1;i<=size;i++){
System.out.println(currNode.data);
currNode=currNode.nextNode;
}
}
//测试
public static void main(String[]args){
SLList<Integer> list=new SLList<Integer>(1);
list.insert(2);
list.insertFromHead(3);
list.insertFromTail(4);
list.showNodes();
System.out.println(list.search(1));
System.out.println(list.find(2));
list.deleteFromHead();
list.deleteFromTail();
list.showNodes();
}
}