进阶Day3 实现List的方法 手写单链表数据结构

3 篇文章 0 订阅
3 篇文章 0 订阅

温馨提示: 在遍历如LinkedList等链表结构的集合时 请使用迭代器遍历,而不是for{list.get()}  for的时间复杂度是O(n²)  迭代器遍历是O(n)     

测试代码:

    public void test02(){
        List<Integer> list = new LinkedArrayClass();
        list.add(1);
        list.add(3);
        list.add(2);

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        Iterator<Integer> iterator = list.iterator();

        System.out.println(iterator.next());
        iterator.remove();
        System.out.println(iterator.next());

        for (int j = 0; j < list.size(); j++) {
            System.out.println(list.get(j));
        }
    }

  链表代码:

package com.yeyu.study.day02.linked;

import java.util.*;
import java.util.function.Consumer;

/**
 * @description: 自定义集合 数据结构为单向链表
 * @author: ganzj
 * @create: 2021-03-27 22:03
 */
public class LinkedArrayClass<Y> implements List<Y>{


    private int size = 0;  //集合大小  计数器

    private Node<Y> first;  //链表开始的节点

    private Node<Y> last;  //链表最后一个节点

    /**
     * 引用一个变量做计数器  记录链表的大小
     * @return
     */
    @Override
    public int size() {
        return this.size;
    }

    /**
     * 判断是否是一个空集合  判断计数器是否等于0即可
     * @return
     */
    @Override
    public boolean isEmpty() {
        return size==0;
    }


    /**
     * 根据传参 判断当前集合中 是否存在该值
     * @param o  需要判断的值
     * @return
     */
    @Override
    public boolean contains(Object o) {
        return indexOf(o)>0;  //调用indexOf方法 判断下标大小即可得出是否存在
    }


    @Override
    public Iterator<Y> iterator() {
        return new Ite();
    }


    /**
     * 内部类 实现迭代器  简单实现 没做扩展
     */
    private class Ite implements Iterator{
        private int index = 0;
        private Node<Y> lastNode;
        private Node<Y> next;
        private int modNum;

        Ite(){
            next = first;
            modNum = size;
        }

        @Override
        public boolean hasNext() {
            return index<size;
        }

        @Override
        public Object next() {
            if(modNum != size){
                throw new RuntimeException("数据有改动,抛出异常");
            }
            index++;
            lastNode = next;
            next = next.next;
            return lastNode.e;
        }

        @Override
        public void remove() {
            next = next.next;
            lastNode.next = next;
            modNum--;
            size--;
        }

        /**
         * 待补充
         * @param action
         */
        @Override
        public void forEachRemaining(Consumer action) {

        }
    }


    @Override
    public Object[] toArray() {
        Object[] result = new Object[size];   //创建一个等于集合长度的数组
        int i = 0;
        for (Node<Y> n = first; n != null; n = n.next)    //遍历将集合的值传入数组
            result[i++] = n.e;
        return result;
    }

    /**
     * JDK的文档写的是 : 以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。
     *   感觉是
     * @param a
     * @param <T>
     * @return
     */
    @Override
    public <T> T[] toArray(T[] a) {
        return null;
    }

    @Override
    public boolean add(Y y) {
        Node temp = last;  //将记录的最后一个链表放入临时变量
        last = new Node<Y>(y,null); //生成一个节点 记为最后一个节点
        if(first == null){  //如果第一个节点为null则将此节点记录为第一个节点
            first = last;
        }else{
            temp.next = last;  //将临时变量的下一个节点指向last
        }
        size++;  //计数器+1
        return true;
    }

    /**
     * 根据值删除节点
     * @param o
     * @return
     */
    @Override
    public boolean remove(Object o) {
        if(first == null){   //判断first是否为null  如果是则链表为null 直接返回false
            return  false;
        }
        
        //判断传值是否为null 执行相应的比较方法  比较完返回Boolean
        if(o == null ){
            for (Node n = first; n!=null ; n=n.next){
                if(n.e==null){
                    return true;
                }
            }
        }else{
            for (Node n = first; n!=null ; n=n.next){
                if(o.equals(n.e)){
                    return true;
                }
            }
        }

        return false;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean addAll(Collection<? extends Y> c) {
        return false;
    }

    @Override
    public boolean addAll(int index, Collection<? extends Y> c) {
        return false;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return false;
    }

    /**
     * 初始化
     * 就不做遍历清除了   直接去掉first的引用等待GC回收
     * 如果数据量大 或者其他业务需求比如有节点在被引用等 可以做循环清除每个节点的数据
     */
    @Override
    public void clear() {
        first = null;
        last = null;
        size = 0;
    }

    /**
     * 根据下标 获得值
     * @param index
     * @return
     */
    @Override
    public Y get(int index) {
        checkIndexOutOf(index);
        if(first == null){   //判断first是否为空  如果为空则直接返回
            return null;
        }
        if(index ==0){    //如果是获取0的值 则直接返回first的值
            return first.e;
        }
        int num = 0;  //循环标志位
        for (Node<Y> n = first; n!=null ; n=n.next,num++){    //循环到指定下标时 返回相应值
            if(num == index){
                return n.e;
            }
        }
        return null;
    }

    /**
     * 替换指定的下标的值
     * @param index
     * @param element
     * @return
     */
    @Override
    public Y set(int index, Y element) {
        checkIndexOutOf(index);
        if(index ==0){   //如果是0则直接修改first的值
            if(first ==null){  //如果first为null  则先实例化first再赋值
                first = new Node<Y>(element,null);
                return element;
            }
            Y temp = first.e;
            first.e = element;
            return temp;
        }
        int num = 1;
        for (Node<Y> n = first.next; n!=null ; n=n.next,num++){   //循环赋值
            if(num == index){
                Y temp = n.e;
                n.e = element;
                return temp;
            }
        }
        return null;
    }

    /**
     * 将值插入到指定下标  后面的下标依次往后移1位
     * @param index
     * @param element
     */
    @Override
    public void add(int index, Y element) {
        checkIndexOutOf(index);
        if(index ==0){
            if(first ==null){
                first = new Node<Y>(element,null);
            }
            first.e = element;
        }
        int num = 1; //first以及比较过了  此处可以从1开始
        for (Node<Y> n = first.next; n!=null ; n=n.next,num++){
            if(num == index){
                n.e = element;
            }
        }
    }

    /**
     * 删除该列表中指定位置的元素。 将后续元素往前移1位  返回被删除的值
     * @param index
     * @return
     */
    @Override
    public Y remove(int index) {
        checkIndexOutOf(index);
        if(index ==0){
            if(first ==null){
                return null;
            }
            Y temp = first.e;
            first = first.next;
            return temp;
        }
        int num = 1; //first已经比较过了  此处可以从1开始
        Node tempNode = null;
        for (Node<Y> n = first.next; n!=null ; n=n.next,num++){
            if(num == index){
                Y temp = n.e;
                if(num==1){
                    first.next = n.next;
                }else{
                    tempNode.next = n.next;
                }
                return  temp;
            }
            tempNode = n;
        }
        return null;
    }

    /**
     * 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1
     * @param o
     * @return
     */
    @Override
    public int indexOf(Object o) {
        int num = -1;
        if(o != null){  //判断参数是否为null  比较方式不同 如果为null没有实例化调用equas方法 会抛出异常
            for (Node n = first; n != null; n=n.next){   //循环  当指向的下一个节点为null时  代表是最后一个节点了 结束循环
                num++;
                if(o.equals(n.e)){  //如果发现有匹配到的值 则直接返回下标
                    return num;
                }
            }
        }else{
            for (Node n = first; n != null; n=n.next){   //循环  当指向的下一个节点为null时  代表是最后一个节点了 结束循环
                num++;
                if(n.e==null){  //如果包含null值 则直接返回下标;
                    return num;
                }
            }

        }
        return num;
    }

    /**
     * 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
     * @param o
     * @return
     */
    @Override
    public int lastIndexOf(Object o) {
        int num = 0;
        int index = -1;
        if(o != null){  //判断参数是否为null  比较方式不同 如果为null没有实例化调用equas方法 会抛出异常
            for (Node n = first; n != null; n=n.next){   //循环  当指向的下一个节点为null时  代表是最后一个节点了 结束循环
                num++;
                if(o.equals(n.e)){  //如果发现有匹配到的值 则将当前下标赋值给index
                    index = num;
                }
            }
        }else{
            for (Node n = first; n != null; n=n.next){   //循环  当指向的下一个节点为null时  代表是最后一个节点了 结束循环
                num++;
                if(n.e==null){  //如果包含null值 则将当前下标赋值给index
                    index = num;
                }
            }

        }
        return index;
    }

    @Override
    public ListIterator<Y> listIterator() {
        return null;
    }

    @Override
    public ListIterator<Y> listIterator(int index) {
        return null;
    }

    @Override
    public List<Y> subList(int fromIndex, int toIndex) {
        LinkedArrayClass<Y> linkedArrayClass = new LinkedArrayClass<>();
        int num = 0;
        for (Node<Y> n = first.next; n!=null&&num>=fromIndex&&num<=toIndex; n=n.next,num++){
            linkedArrayClass.add(n.e);
        }
        return linkedArrayClass;
    }

    /**
     * 判断是否下标溢出
     * @param index
     * @return
     */
    private void checkIndexOutOf(int index){
        //判断索引是否为0 或则大于集合的总大小   抛出异常
        if(index<0 || index>size){
            throw new IndexOutOfBoundsException("下标溢出:"+index);
        }
    }

    //内部类 链表结构 包含下一节点的单向链表结构
    private class Node<Y>{
        private Y e;  //当前数据
        private Node<Y> next;  //下一节点数据

        public Node(Y e, Node<Y> next) {
            this.e = e;
            this.next = next;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值