单链表:是用一组任意的存储单元存放线性表的元素,这组存储单元可以连续也可以不连续,甚至可以零散的分布在内存中的任意位置。为了正确表示元素之间的逻辑关系,每个存储单元在存储数据元素的同时,还必须存储其后继元素所在的地址信息。其中data是数据域,,用来存放数据元素,next是指针域,用来存放该结点的后继结点的地址。 单链表的基本思想就是用指针表示结点之间的逻辑关系,首先要正确区分指针变量,指针、指针所指的结点和结点的值四个概念!
显然,单链表中每个结点的存储地址存放在其前驱结点的next域中,而第一个元素无前驱,所以设头指针指向第一个元素所在结点(称为开始结点),整个单链表的存取必须从头开始进行,因而头指针具有标识一个单链表的作用;同时由于最后一个元素无后继,故最后一个元素所在的结点的指针域为空,即NULL,也称尾标志。
data
next
package data.LineList.LinkedList.SingleLinkedList;
public class SingleLinkedList<T> {
/**
* 节点类
* @author zhouhai
*
*/
class Node<T>{
private T data;//数据域
private Node next;//指针域保存着下一节点的引用
Node(T data,Node next){
this.data=data;
this.next=next;
}
Node(T data){
this(data,null);
}
Node(){
}
}
/**
* 下面是SingleLinkedList的成员变量和方法,
*/
private Node<T> head,tail;//头指针是没有数据(data)域的,只有next.尾标志(tail)的数据域为最后一个结点,next为null
/**
* 无参构造方法
*/
public SingleLinkedList(){
}
/**
* 判断链表是否为空
*/
public boolean isEmpty(){
return head==null;
}
/**
* 返回链表长度
*/
public int length(){
Node<T> p=head;
int len=0;
while(p.next!=null){
len++;
p=p.next;
}
return len;
}
/**
* 创建头指针,该方法只用一次
*/
public void addToHead(T item){
head=new Node<T>();
head.next=null;
}
/**
* 增加尾指针,该方法复用
*/
public void addToTail(T item){
if(!isEmpty()){//若链表非空,将链表的尾指针的next初始化为一个新的元素
tail.next=new Node<T>(item);
tail=tail.next;
}else{//如果为空,这创建一个新的,并将头尾同时指向他
head=tail=new Node<T>(item);
}
}
/**
* 遍历打印整个链表
*@Title: printList
*@Description: TODO
*@param
*@return void
*@throws
*/
public void printList(){
if(isEmpty())throw new RuntimeException("该链表为空");
else{
Node node=head.next;//工作指针初始化(链表的第一个元素)
while(node!=null){
System.out.println(node.data);
node=node.next;
}
}
}
/**
* 在表头插入节点,效率非常高
*/
public void addFirst(T item){
Node<T> node=new Node<T>(item);
node.next=head.next;
head.next=node;
}
/**
* 在表尾插入节点,效率低
*/
public void addLast(T item){
Node<T> node=new Node<T>(item);
Node<T> p=head;
while(p.next!=null){
p=p.next;
}
p.next=node;
node.next=null;
}
/**
* 在表头删除结点
*/
public void deleteFirst(){
if(!isEmpty()){
head.next=head.next.next;
}else System.out.println("这是空表");
}
/**
* 在表尾删除结点
* 寻找链表最后一个结点,将倒数第二个结点的next指向null
* ,则删掉了倒数第一个
*/
public void deleteLast(){
Node<T> curr=head,prev=null;
while(curr.next!=null){
prev=curr;
curr=curr.next;
if(curr.next==null)prev.next=null;
}
}
/**
* 返回链表第i(i>0)个元素
*/
public Node<T> get(int i){
if(i>length()||i<=0)throw new ArrayIndexOutOfBoundsException();
else{
Node<T> node=head.next;
for(int j=1;j<i;j++){
node=node.next;
}
return node;
}
}
/**
* 设置第i个元素的值为value
*@Title: set
*@Description: TODO
*@param @param i
*@param @param value
*@return void
*@throws
*/
public void set(int i,T value){
if(i<=0||i>length())throw new ArrayIndexOutOfBoundsException();
else{
Node p=head.next;
for(int j=1;i<i;j++){
p=p.next;
}
p.data=value;
}
}
/**
* 按值查找
*@Title: indexOf
*@Description: TODO
*@param @param value
*@return void
*@throws
*/
public int indexOf(T value){
int index=0;
Node p=head.next;
for(;p!=null;p=p.next){
index++;
if(p.data==value)return index;
}
return -1;
}
/**
* 是否包含值为value的元素
*@Title: contains
*@Description: TODO
*@param @param value
*@param @return
*@return boolean
*@throws
*/
public boolean contains(T value){
return indexOf(value)!=-1;
}
/*
* 在链表的第i个位置插入元素vlaue
*/
public void insert(int i,T value){
Node node=new Node(value);
Node p=head.next;
for(int j=1;j<i-1;j++){
p=p.next;
}
//找到i-1个结点p,将node元素插在P后面
node.next=p.next;
p.next=p;
}
/*
* 删除第i个元素
*/
public void delete(int i){
Node p=head.next;
for(int j=1;j<i-1;j++){
p=p.next;
}
p.next=p.next.next;
}
}