接口
public interface MyLinkedList<E> {
//添加元素--尾插法
void add(E e); //参数为任意类型
//添加元素--头插法
void addFirst(E e); //参数为任意类型
//获得元素的个数
int size(); //返回值类型为int
//获得元素
E get2(int ge); //参数类型为int,返回值类型为任意类型
E get(int ge); //参数类型为int,返回值类型为任意类型
//修改
boolean set(int index,E e); //参数类型为int和任意类型,返回值类型为boolean
//删除
boolean remove(int index); //参数类型为int,返回值类型为boolean
}
实现类
public class MyLinkedListImpl<E> implements MyLinkedList<E> {
private Node<E> first;//头节点
private Node<E> last;//尾结点
private int size;//代表链表的长度 也就是说有几个节点
//添加元素-尾插法
@Override
public void add(E e) {
//获取当前尾节点对象
Node<E> oldLastNode=this.last; //第一次赋值尾节点是null,将它赋值给oldLastNode;第二次赋值oldLastNode地址为0x530
//创建新的节点,因为我们现在是尾插 所以现在新的节点就是最后一个节点
Node<E> newNode=new Node<>(oldLastNode,e,null); //第一次创建新的链表为null,1,null;第二次创建新的链表为0x530,2,null,并且头部指向第一次创建节点的尾部
//把当前新建的节点指定成尾节点
this.last=newNode; //第一次创建的链表对象赋值给尾节点为null,第二次创建链表对象的尾节点0x532
if (oldLastNode==null){ //代表是第一次进行节点的插入,将第一次创建的地址值赋值给头节点
this.first=newNode;
}else {
oldLastNode.next=newNode; //把旧尾节点next指向新节点对象,将第二次创建的地址值赋值给第一次尾部节点
}
size++; //添加完成节点 整体加一
}
//元素添加-头插法
@Override
public void addFirst(E e) {
//获得目前的头节点元素
Node<E> oldFirstNode=this.first;
//创建新节点
Node<E> newNode=new Node<>(null,e,oldFirstNode);
//把当前新节点设置为头节点
this.first=newNode;
if(oldFirstNode==null){ //代表是第一次添加节点
this.last=newNode;
}else{ //新的元素对象赋值给 之前旧头节点的pre
oldFirstNode.pre=newNode;
}
size++;//总体长度加一
}
//返回链表的长度
@Override
public int size() {
return size;
}
//获得元素实现
@Override
public E get2(int ge) {
checkedIndex(ge);//判断下标是否越界
Node<E> fis=this.first; //获得链表的头节点
//一定注意ge 不可以等于 如果是等于这个时候就取到了目标元素下一个
for (int i = 0; i <ge; i++) {
fis=fis.next; //获取下一个地址值
}
//循环结束 当前fis对象就是指定目标元素对象
return fis.item;//返回目标对象的item item就是节点中保存的值
}
//查询的升级版本
@Override
public E get(int ge) {
checkedIndex(ge);//判断下标是否越界
Node<E> node = getNode(ge);//根据下标 查询到指定节点对象,并返回给对象node
return node.item; //返回给中间值
}
//封装查询节点对象方法
private Node<E> getNode(int index){
if(index < (size>>1)){ //如果用户查询的元素是小于长度的1/2 这个时候正着查询元素
Node<E> fis=this.first; //获得链表的头节点
//一定注意ge 不可以等于 如果是等于这个时候就取到了目标元素下一个
for (int i = 0; i <index; i++) {
fis=fis.next;
}
return fis;
}else{
//如果大于使用元素反正查询即可
Node<E> las=this.last;
for (int i=size-1;i>index;i--){
las=las.pre;
}
return las;
}
}
//修改的实现
@Override
public boolean set(int index, E e) {
try {
checkedIndex(index);//判断用户输入的下标是否越界
Node<E> node = getNode(index);//根据下标获得指定节点对象
node.item=e;//把用户传入的值 赋值给目标节点中item
return true;
} catch (Exception ex) {
return false;
}
}
//删除的实现
/*
* 1.删除的即为头结点又为尾结点
* 将头结点设为为null ---first
* 将尾结点设置为null ---last
* 将被删除的头结点设为为null
*
* 2.删除的为头结点
* 将删除头结点的下一个结点的上一个结点的地址设置为null
* 将删除头结点的下一个结点, 设置为新的头结点
* 将被删除的头结点设为为null
*
* 3.删除的为尾结点
* 将删除尾结点的上一个结点的下一个结点的地址设置为null
* 将删除结点的上一个结点, 设置为新的尾结点
* 将被删除的尾结点设置为null
*
* 4.删除非头尾结点
* 将删除结点的上一个结点指向下一个结点的地址变换为删除结点的下一个结点的地址
* 将删除结点的下一个结点指向上一个结点的地址变换为删除结点的上一个结点的地址
* 将被删除的姐点设置为null
* 1 , 2, 3, 4 都需要进行size--
* */
@Override
public boolean remove(int index) {
checkedIndex(index);//检查下标是否合法
try {
Node<E> node = getNode(index);//获得删除的节点
Node<E> p = node.pre; //获得删除节点前一个地址
Node<E> n = node.next;//获得删除节点后一个地址
if(p==null&&n==null){ //删除节点及时头节点 又是尾结点
this.first=null;
this.last=null;
}else if(p==null){ //删除的是首节点元素
n.pre=null; // 将删除头结点的下一个结点的上一个结点的地址设置为null
this.first=n;//将删除头结点的下一个结点, 设置为新的头结点
}else if(n==null){ //删除是尾结点
p.next=null;//将删除尾结点的上一个结点的下一个结点的地址设置为null
this.last=p;//将删除结点的上一个结点, 设置为新的尾结点
}else{ //删除是中间的元素
p.next=n;//将删除结点的上一个结点指向下一个结点的地址变换为删除结点的下一个结点的地址
n.pre=p;//将删除结点的下一个结点指向上一个结点的地址变换为删除结点的上一个结点的地址
}
node=null;
size--;//删除完成整体长度减一
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private void checkedIndex(int ge){
if(ge<0||ge>=size){
throw new ArrayIndexOutOfBoundsException("数组下标越界");
}
}
//新建内部类 内部类就是节点类
private class Node<E>{
private Node<E> pre; //前一个节点对象
private E item;//中间保存的值
private Node<E> next;//下一个节点对象
public Node(){
}
public Node(Node<E> pre, E item, Node<E> next) { //有参构造,参数分别为: 前一个节点对象,中间保存的值,下一个节点对象
this.pre = pre; //将用户传过来的参数赋值给当前属性pre
this.item = item; //将用户传过来的参数赋值给当前类属性item
this.next = next; //将用户传过来的参数赋值给当前类属性next
}
}
}
测试类
public class TestA {
public static void main(String[] args) {
MyLinkedList<Integer> list=new MyLinkedListImpl<>();
//list.add(1);
//list.add(2);
list.add(100);
list.add(200);
list.add(300);
list.add(400);
list.add(500);
list.add(600);
list.add(700);
list.add(800);
list.add(900);
list.add(1000);
// System.out.println(list.get(9));
//list.set(1,8888);
list.remove(9);
System.out.println("-----------------数组的遍历--------------------");
for (int i = 0; i <list.size(); i++) {
System.out.print(list.get(i)+"\t");
}
}
}