数据结构-链表 (手写双向非循环链表)

数据结构-链表 (手写双向非循环链表),第1张

接口

public interface MyLinkedList {
    //添加元素--尾插法
    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 implements  MyLinkedList {

    private   Node  first;//头节点
    private   Node   last;//尾结点
    private  int        size;//代表链表的长度  也就是说有几个节点


    //添加元素-尾插法
    @Override
    public void add(E e) {
        //获取当前尾节点对象
        Node oldLastNode=this.last;  //第一次赋值尾节点是null,将它赋值给oldLastNode;第二次赋值oldLastNode地址为0x530
        //创建新的节点,因为我们现在是尾插 所以现在新的节点就是最后一个节点
        Node 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  oldFirstNode=this.first;
        //创建新节点
        Node  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  fis=this.first; //获得链表的头节点

        //一定注意ge 不可以等于 如果是等于这个时候就取到了目标元素下一个
        for (int i = 0; i  node = getNode(ge);//根据下标 查询到指定节点对象,并返回给对象node
        return  node.item;  //返回给中间值
    }

    //封装查询节点对象方法
    private    Node   getNode(int  index){

        if(index < (size>>1)){ //如果用户查询的元素是小于长度的1/2 这个时候正着查询元素
            Node  fis=this.first; //获得链表的头节点
            //一定注意ge 不可以等于 如果是等于这个时候就取到了目标元素下一个
            for (int i = 0; i  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 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 node = getNode(index);//获得删除的节点
            Node p = node.pre; //获得删除节点前一个地址
            Node 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{

          private  Node  pre; //前一个节点对象
          private  E        item;//中间保存的值
          private  Node  next;//下一个节点对象

        public Node(){

        }
        public Node(Node pre, E item, Node next) {  //有参构造,参数分别为: 前一个节点对象,中间保存的值,下一个节点对象
            this.pre = pre;  //将用户传过来的参数赋值给当前属性pre
            this.item = item; //将用户传过来的参数赋值给当前类属性item
            this.next = next; //将用户传过来的参数赋值给当前类属性next
        }
    }

}

测试类

public class TestA {

    public static void main(String[] args) {

          MyLinkedList  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 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/562327.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-01
下一篇 2022-04-01

发表评论

登录后才能评论

评论列表(0条)