单链表
单链表是用一组任意的存储单元存放线性表的元素。这组存储单元可以连续也可以不连续,甚至可以零散的分布在内存中的任意位置。为了能正确的表示元素之间的逻辑关系,们每个存储单元在存储数据元素的同时,还必须存储其后继元素所在的地址信息,这个地址称之为指针,这两部分组成数据元素的存储映像,成为节点。节点的结构如图所示:
data | next |
其中,data为数据域,用来存放数据元素;next 是指针域,用于存放该节点的后继节点地址。
单链表正式通过每个节点的指针讲线性表的数据元素按其逻辑次序链接在一起,由于每个节点只有一个指针,所以成为单链表。
单链表中每个节点的地址都存放在上一个节点中的next域中,而第一个元素所在的节点没有上一个节点,所以设置一个头指针指向第一个元素节点。最后一个节点没有后一个节点,所以它的next域为null.
单链表的实现
单链表有头指针唯一指定,整个单链表的操作必须从头指针开始进行。
package linkedList;
/**
*
* @ClassName: SinglyLinkedList.java
* @Description: 单链表的实现
* @Copyright: Copyright (c) 2017
* @author 周扬
* @date 2017年6月5日 上午10:52:17
* @version V1.0
*/
public class SinglyLinkedList {
/**头指针,不存储数据元素,值存储下一节点信息**/
private Node headPointer;
public SinglyLinkedList(){
headPointer=new Node();
}
public void printList(){
}
public int length(){
}
public Object get(int i) throws Exception{
}
public int locate(Object data){
}
public void insert(int i,Node node) throws Exception{
}
public Object delete(int i) throws Exception{
}
}
遍历
遍历单链表需要将单链表扫描一遍,时间复杂度为O(n).
伪代码:
1.初始化一个指针p
2.重复执行以下操作,直到p为null
2.1 输出节点p的数据域
2.2 工作指针p后移
/**
* @MethodName: printList
* @Description: 遍历操作
* @author 周扬
* @date 2017年6月5日 上午10:52:32
*/
public void printList(){
Node p=headPointer.getNextNode();
while(p!=null){
System.out.println(p.getData());
p=headPointer.getNextNode();
}
}
线性表的长度
伪代码:
1.初始化一个指针p,初始化累加器count
2.重复执行以下操作,直到p为null
2.1 工作指针p后移
2.2 count累加
3. 返回count
/**
* @MethodName: length
* @Description: 获取线性表的长度
* @author 周扬
* @date 2017年6月5日 上午11:00:50
*/
public int length(){
int count=0;
Node p=headPointer.getNextNode();
while(p!=null){
//累加计数器
count++;
//获取下一个节点
p=p.getNextNode();
}
//返回长度
return count;
}
按位查找
伪代码:
1.初始化一个指针p,初始化累加器count
2.重复执行以下操作,直到p为count
2.1 工作指针p后移
2.2 count累加
3. 判断p是否为空,是则抛出异常,否则返回p的数据元素
/**
* @MethodName: get
* @Description: 查找指定位置i的数据元素
* @param i
* @return
* @author 周扬
* @throws Exception
* @date 2017年6月5日 上午11:07:56
*/
public Object get(int i) throws Exception{
Node p=headPointer.getNextNode();
int count=1;
//获取指定位置的前一个节点
while(p!=null&&count<i){
count++;
p=p.getNextNode();
}
if(p==null){
throw new Exception("位置"+i+"不存在");
}
return p.getData();
}
按值查找
伪代码:
1.初始化一个指针p,初始化累加器count
2.重复执行以下操作,直到p为数据元素等于指定值
2.1 工作指针p后移
2.2 count累加
3. 判断p是否为空,是则返回0,否则返回count
/**
* @MethodName: locate
* @Description: 按照数据元素之查找,成功返回序号,失败返回0
* @param data
* @return
* @author 周扬
* @date 2017年6月5日 上午11:19:12
*/
public int locate(Object data){
Node p=headPointer.getNextNode();
int count=1;
while(p!=null){
if(p.getData().equals(data)){
return count;
}
p=p.getNextNode();
count++;
}
return 0;
}
插入
伪代码:
1.初始化一个指针p
2.查找第i-1个节点并使指针p指向该节点
3.判断p是否为空,是则抛出位置异常,
否则执行:
3.1 生成元素值为x的新节点s
3.2 将新节点插入到节点p之后
/**
* @MethodName: insert
* @Description: 在链表指定位置插入节点
* @param i
* @param node
* @author 周扬
* @throws Exception
* @date 2017年6月5日 上午11:25:10
*/
public void insert(int i,Node node) throws Exception{
Node p=headPointer;
int count=0;
while(p!=null&&count<i-1){
//获取原先第i位置节点的上一个节点
p=p.getNextNode();
count++;
}
if(p==null){
//如果上一个节点为空,则抛出异常
throw new Exception("位置"+i+"不存在");
}
//获取原先i位置的节点
Node oldNextp= p.getNextNode();
//设置新节点的下一个节点为oldNextp
node.setNextNode(oldNextp);
//设置原先上一个节点的下一个节点为新值
p.setNextNode(node);
}
删除
伪代码:
1.初始化一个指针p
2.查找第i-1个节点并使指针p指向该节点
3.判断p是否为空,是则抛出位置异常
4.判断p的下一个节点是否为空,是则抛出异常
5.获取目标节点,将目标节点的next域放入p中
6.返回目标节点的数据元素
/**
* @MethodName: delete
* @Description: 删除指点位置的节点,并返回被删除节点的数据元素
* @param i
* @return
* @throws Exception
* @author 周扬
* @date 2017年6月5日 上午11:52:32
*/
public Object delete(int i) throws Exception{
Node p=headPointer;
int count=0;
while(p!=null&&count<i-1){
//获取原先第i位置节点的上一个节点
p=p.getNextNode();
count++;
}
if(p==null||p.getNextNode()==null){
//如果上一个节点为空或者第i个节点为空,则抛出异常
throw new Exception("位置"+i+"不存在");
}
//获取目标节点
Node target=p.getNextNode();
//获取目标节点的下一个节点
Node targetNext=target.getNextNode();
//目标节点的上一个节点的next域指向targetNext
p.setNextNode(targetNext);
//保存被删除元素的数据元素
Object data=target.getData();
//释放被删除元素的内存
target=null;
//返回目标节点数据元素
return data;
}