数据结构单链表的定义(Java)

来源:互联网 发布:sql 截取字符串函数 编辑:程序博客网 时间:2024/05/18 20:32

定义一个接口

public interface ILinarList<E> {    public abstract boolean add(E item);          //添加元素    public abstract boolean add(int i,E item);    //插入元素    public abstract E remove(int i);              //删除元素    public abstract int indexOf(E item);          //定位元素    public abstract E get(int i);                 //取表元素     public abstract int size();                   //求线性表长度    public abstract void clear();                 //清空线性表    public abstract boolean isEmpty();            //判断线性表是否为空}

定义一个结点类

/* * 单链表的的原理就在结点这里,在每一个结点中都包含一个下一个结点的地址, * 如果想要访问下一个结点,就要通过上一个结点来调用他的成员变量next,以此类推 */public class Node<E> {    E item;//创建一个泛型类item    Node<E> next;//创建一个结点类类型    public Node(E element,Node <E> next) {        this.item=element;        this.next=next;    }}

创建一个SLinkList类来实现接口

public class SLinkList<E> implements ILinarList<E>{    private Node<E> start;//1    新建一个空的带头节点    int size;    public SLinkList(){        start=null;        size=0;    }    /*一个节点中的成员变量指向一个新的Node,从实例对象的角度,整条链表中有实例化的对象为start,     * 详见1、2,可以看出,private Node<E> start=new Node<E>(item,null),实例化了一个start     * 接下来add方法中,Node<E> current=start 为引用了start 的地址,start 的成员变量next的类型是Node<E>的引用类型,     * 里面包含一个E类型的item,和一个Node<E>类型的next     * 也就是说每添加一个节点都是没有实例化对象的,直接从start 的next成员指向一个新的Node<E>,     * 再添加就是从新的Node<E>中的next成员指向新的Node<E>     * 如下面的语句     */    //添加元素到链表的末尾    public boolean add(E item) {        if(start==null)//如果带头节点为空,将新建一个带头节点            start=new Node<E>(item,null);//2        else {//如果带头节点不为空的话,新建一个current指向start的地址            Node<E> current=start;            while(current.next!=null){//依次访问每一个节点,当一个节点的next为空时,说明此节点为最后一个节点                current=current.next;//注意,这里的赋值,每次都是赋予地址,并不是修改            }            current.next=new Node<E>(item,null);//引用最后一个节点的next,创建一个新的节点        }        size++;        return true;    }    //插入元素到i索引位置前插入一个数据元素    public boolean add(int i, E item) {        if(i<0||i>size)//等于size时候即为在末尾调加一个元素            throw new IndexOutOfBoundsException("Index:"+i+",Size:"+size);//抛出越界异常        Node<E> newnode=new Node<E>(item, null);        if(i==0){//第一个元素前插入一个元素            newnode.next=start;//newnode.next指向start的地址,此时原头元素有了一个指向他的地址            start=newnode;//start的地址指向newnode的地址,所以此时有两个实例对象指向带头元素,分别是start和newnode            size++;        }else{             Node<E> current=start;//将current指向头元素的地址             Node<E> previous=null;             int number=0;//定义一个number用来计算访问节点的次数             while(number<i){//从0开始自加,加到i时候,此时current指向i的索引位置,previous指向前一个                 previous=current;//previous始终保存current前一个节点的地址                 current=current.next;//循环访问current的next的地址                 number++;//每访问一次number自加一次             }             previous.next=newnode;//将前一个节点的地址的next指向修改为newnode             newnode.next=current;//将newnode的next指向当前的节点元素             size++;        }        return true;    }    //清楚索引的元素    public E remove(int i) {        E oidValue=null;//先赋值为null,两个循环都没有进入时,此方法返回一个null        if(i<0||i>size-1)            throw new IndexOutOfBoundsException("Index:"+i+",Size:"+size);//抛出越界异常        else if(!isEmpty()){//当整个链表不为空时,进去此语句            if(i==0){//当要清楚头元素时                oidValue=start.item;//将返回元素赋值                start=start.next;                size--;            }else{//以下方法同add重写的第二次方法                Node<E> previous=null;                Node<E> current=start;                int number=0;                while(number<i){                    previous=current;                    current=current.next;                    number++;                }                oidValue=current.item;                previous.next=current.next;//将指定元素的前一个元素的next指向指定元素的下一个元素                current.next=null;//释放当前元素的next                current=null;//同上(个人觉得不做这两步好像也没有什么问题?)                size--;            }        }        return oidValue;    }    public int indexOf(E item) {        int number=0;        if(item==null){//需要单独对item==null的情况判定,因equals没有比较null,空指针错误            for(Node<E> x=start;x!=null;x=x.next){                if(x.item==null)                    return number;                number++;            }        }else{            for(Node<E>x=start;x!=null;x=x.next){                if(item.equals(x.item))//判定是否为所要的元素                    return number;                number++;            }        }        return -1;//当遍历完整个链表之后没有所要的元素,说明此链表不存在此元素,返回-1    }    public E get(int i) {        E item=null;        if(i<0||i>size-1)            throw new IndexOutOfBoundsException("Index:"+i+",Size:"+size);//抛出越界异常        else if(!isEmpty()){            Node<E> current=start;            for(int j=0;j<i;j++)//当知道要取第i个元素的时候,用for循环执行i次                current=current.next;            item=current.item;        }        return item;    }    public int size() {        return size;    }    public void clear() {        for(Node<E> x=start;x!=null;){//当x为空时停止            Node<E> next=x.next;//保存x.next的地址            x.item=null;//将x中的元素清空            x.next=null;//将x的指向清空,注意,x.next不代表是下一个节点,仅仅是指向下一个节点的地址            x=next;        }        start =null;//start也是指向一片地址,如果没有清空的话,依然可以访问,只不过start.item和start.next都为空罢了        size=0;    }    public boolean isEmpty() {        return size==0;    }}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小米5c死机了怎么办 苹果x自拍反方向怎么办 硅胶手机壳出油怎么办 指环扣松了怎么办图解 塑料放久了发粘怎么办 橡胶时间久了粘怎么办 胶的手机套变黄怎么办 手机壳硅胶变黄怎么办 硅胶手机壳大了怎么办 硅胶手机壳变大了怎么办 硅胶手机壳有点大怎么办 硅胶手机壳粘手怎么办 透明手机壳变黄怎么办? 耳机胶套经常掉怎么办 硅胶手机壳粘毛怎么办 耳机海绵套坏了怎么办 沙发垫海绵坏了怎么办 汽车坐海绵坏了怎么办 苹果手机边框有缝隙怎么办 孕期牙套子掉了怎么办 平果充电线不匹配怎么办 苹果六外壳掉漆怎么办 苹果平板充电没反应怎么办 苹果平板黑屏没反应怎么办 苹果平板卡机了怎么办 苹果7plus掉漆怎么办 皮的手机壳脏了怎么办 小米5x边边裂开怎么办 荣耀8的后盖摔了怎么办 hp打印机卡了纸怎么办 华为荣耀9进水了怎么办 小米5x屏幕脱胶怎么办 小米5x后盖松动怎么办 苹果手机没电了怎么办 荣耀9的后盖裂了怎么办 手机一直在开机画面怎么办华为 华为手机一直显示开机画面怎么办 华为p7手机开不了机怎么办 华为荣耀8弯了怎么办 手机壳掉漆了怎么办 华为5a手机音量小怎么办