单链表的逻辑就不多说了,别的文章有很多细致的分析,直接上代码
首先是节点的实现:
/**
*
* 节点类型
*
* @author 网络W信号
*
* @param <E>
*/
public class Node<E>{
private Node<E> next;//下一节点地址
private E e;//数据域
//构造方法
public Node (){
}
public Node (E e){
this.e = e;
next = null;
}
//构造器和读取器
public Node<E> getNext() {
return next;
}
public void setNext(Node<E> next) {
this.next = next;
}
public E getE() {
return e;
}
public void setE(E e) {
this.e = e;
}
}
接下来是单链表的实现:
/**
* 实现链表功能
*
* @author 网络W信号
*
* @param <E>
*/
public class LinkList <E>{
private Node<E> head;//头结点
private Node<E> last;//尾结点
private int size = 0;//链表长度
//创建链表
public LinkList(){
head = new Node<E>();
last = head;
}
public LinkList(E e){
head = new Node<E>();
last = head;
}
/**
* 判断是否为空
*
* @return 为空返回false,不为空返回true
*/
public boolean isEmpty(){
if(head == last){
return false;
}
return true;
}
/**
* 清空链表
*/
public void clear(){
head = last;
}
/**
* 返回长度
*
* @return
*/
public int size(){
return size;
}
/**
* 查找并返回目标位置的节点
*
* @param i (int)目标位置
* @return 目标节点
*/
public Node<E> find(int i){
if(i < 0 || i >= size){
return null;
}
Node<E> temp = head.getNext();
for(int k = 0 ; k < i ; k ++){
temp = temp.getNext();
}
return temp;
}
/**
* 查找并返回目标位置的数据域
*
* @param i (int)目标位置
* @return 目标节点数据域
*/
public E getE(int i){
if(i < 0 || i >= size){
return null;
}
Node<E> temp = find(i);
return temp.getE();
}
/**
* 按数据域内容查找节点位置,并返回位置I
* @param e (E)目标内容
* @return 返回元素i,-1为不存在
*/
public int getI(E e){
E temp = e;
int i;
//找到指定位置
for(i = 0 ; ; i ++){
temp = getE(i);
if(temp == e) {
break;
}
if(temp == null){
return -1;
}
}
return i;
}
/**
* 判断数据域为e的节点是否在链表中
*
* @param e 目标数据域
* @return 存在返回true,不存在返回false
*/
public boolean exist(E e){
int i = getI(e);
if(i == -1){
return false;
}
return true;
}
/**
* 判断i位置是否存在节点
*
* @param i 目标位置
* @return 存在返回true,不存在返回false
*/
public boolean exist(int i){
if(find(i) == null){
return false;
}
return true;
}
/**
* 在尾部添加数据域为e的节点
*
* @param e 目标节点
*/
public void add(E e){
Node<E> newNode = new Node<E>(e);
last.setNext(newNode);
last = newNode;
size++;
}
/**
* 在指定位置(i)添加数据域为e的节点
*
* @param e 数据域
* @param i 目标位置
*/
public void add(E e,int i){
if(i >= 0 && i < size){
Node<E> newNode = new Node<E>(e);
//如果添加位置为第一个节点则改变头结点next地址
if(i == 0){
newNode.setNext(head.getNext());
head.setNext(newNode);
}
else if(i == (size-1)){
last.setNext(newNode);
last = newNode;
}
else{
newNode.setNext(find(i));
find(i-1).setNext(newNode);
}
}
//将在队列中的添加到最后
else {
add(e);
}
size++;
}
/**
* 删除指定位置的节点e
*
* @param i (int)目标位置
*/
public void delete(int i){
if(i >= 0 && i < size){
Node<E> temp = find(i);
//当删除第一个节点时,改变头结点的next
if(i == 0){
head.setNext(find(i+1));
}
find(i-1).setNext(temp.getNext());//删除k位置的节点
}
size--;
}
/**
* 删除所有拥有指定数据域(e)的节点
*
* @param e (E)目标数据域的内容
*/
public void delete(E e){
int i = getI(e);//查找目标位置
if(i != -1){
Node<E> temp = find(i);
//当删除第一个节点时,改变头结点的next
if(i == 0){
head.setNext(find(i+1));
}
find(i-1).setNext(temp.getNext());//删除k位置的节点
size--;
if(i < size){
delete(e);
}
}
}
/**
* 修改指定位置(k)的数据域为(e)
*
* @param e 修改后的数据域
* @param i 指定位置
*/
public void remodel(E e,int i){
if(i >= 0 && i < size){
find(i).setE(e);
}
}
/**
* 修改所有指定数据域为e的节点的数据域为x
*
* @param x 修改后的数据域
* @param e 指定数据域
*/
public void remodel(E x,E e){
int i = getI(e);
if(i != -1){
find(i).setE(x);
if(i < size){
remodel(x,e);
}
}
}
/**
* 将指定位置i的节点替换为目标节点node
*
* @param node 修改后的节点
* @param i 修改后的目标节点
*/
public void remodel(Node<E> node,int i){
if(i >= 0 && i < size){
find(i).setE(node.getE()) ;
}
}
/**
* 将对应节点(node)替换为新节点newNode
*
* @param newNode 修改后的节点
* @param node 修改前的目标节点
*/
public void remodel (Node<E> newNode,Node<E> node){
int i = getI(node.getE());
if(i != -1){
find(i).setE(newNode.getE()) ;
}
}
/**
* 输出链表的数据域
*/
public String toString(){
String temp = new String();
for(int i = 0 ; i < size ; i ++){
if(i == 0 ){
E e = getE(i);
temp = (String)e;
}
else{
E e = getE(i);
temp = temp+","+(String)e;
}
}
return temp;
}
}
顺便提供一个测试类:
class Main{
public static void main(String[] adsb){
LinkList<String> a = new LinkList<String>();//创建新链表
System.out.println(a.isEmpty());//判断是否为空
//添加节点
a.add("123");
a.add("456");
a.add("789");
System.out.println(a.toString());//输出链表
System.out.println(a.isEmpty());//再次判空
System.out.println(a.size());//判断长度
//在指定位置添加节点
a.add("234",1);
a.add("245",0);
System.out.println(a.toString());
//获取节点数据域与获得数据位置
System.out.println(a.getE(1));
System.out.println(a.getI("123"));
//测试各种删除模式
System.out.println(a.toString());//首先输出列表用于比对
a.delete(1);//删除1的节点
System.out.println(a.toString());
a.delete("234");//删除数据域为“234”的节点
System.out.println(a.toString());
//判断元素是否在单链表中
System.out.println(a.exist("234"));
System.out.println(a.exist("789"));
//各种替换测试
a.remodel("567", 2);//替换固定位置节点数据域
System.out.println(a.toString());
a.remodel("789","567");//用数据域替换节点数据域
System.out.println(a.toString());
Node<String> b = new Node<String>("789");//定义新的节点用于测试节点替换
Node<String> c = new Node<String>("567");//同上
a.remodel(c, 2);//固定位置的节点替换
System.out.println(a.toString());
a.remodel(b, c);//用节点替换节点
System.out.println(a.toString());
//测试清除方法
a.clear();
System.out.println(a.isEmpty());
}
}
链表的逻辑部分还有很大优化的空间,还有很多功能没有实现,不过对于我这次的实验来说已经够用了,所以就先这样,把这个单链表放在这里当做备忘录,也希望对大家有所帮助。