Java学习第十四天 链表 Linked List

链表与线性数据结构

链表:

  1. 最简单的动态数据结构

  2. 更深入的理解引用(或指针)

  3. 更深入的理解递归

  4. 辅助组成其他数据结构

优点:真正的动态,不需要处理固定容量的问题

缺点:丧失了自由访问的能力

 

数组和链表的对比

链表的头:head 指向第一个节点

package com.dataStructrue;

public class LinkedList <E>{

    private class Node{
        public E e;
        public Node next;

        public Node(E e,Node next){
            this.e=e;
            this.next=next;
        }

        public Node(E e){
            this(e,null);
        }

        public Node(){
            this(null,null);
        }

        @Override
        public String toString(){
            return e.toString();
        }
    }

    private Node head;
    private int size;

    public LinkedList(){
        head=null;
        size=0;
    }
    //获取链表中元素个数
    public int getSize(){
        return size;
    }

    //
    public boolean isEmpty(){
        return size==0;
    }

    //链表头添加新的元素e
    public void addFirst(E e){
//        Node node=new Node(e);
//        node.next=head;
//        head=node;

        head=new Node(e,head);
        size++;
    }

    //链表中间第index(0-based)个位置添加新的元素e
    //在实际中不常用这个操作,做练习题用
    public void add(int index,E e){

        if (index<0||index>size)
        throw new IllegalArgumentException("位置异常");

        if (index==0)
            addFirst(e);
        else {
            Node prev=head;
            for (int i = 0; i < index - 1; i++) {
                prev=prev.next;
            }

//                Node node=new Node(e);
//                node.next=prev.next;
//                prev.next=node;

                prev.next=new Node(e,prev);
                size++;
        }
    }

    //在链表末尾添加新的元素e
    public void addLast(E e){
        add(size,e);
    }

}

为链表设立虚拟头节点

package com.dataStructrue;

public class LinkedList <E>{

    private class Node{
        public E e;
        public Node next;

        public Node(E e,Node next){
            this.e=e;
            this.next=next;
        }

        public Node(E e){
            this(e,null);
        }

        public Node(){
            this(null,null);
        }

        @Override
        public String toString(){
            return e.toString();
        }
    }

    private Node dummyHead;
    private int size;

    public LinkedList(){
        dummyHead=new Node(null,null);
        size=0;
    }
    //获取链表中元素个数
    public int getSize(){
        return size;
    }

    //
    public boolean isEmpty(){
        return size==0;
    }

   

    //链表中间第index(0-based)个位置添加新的元素e
    public void add(int index,E e){

        if (index<0||index>size)
        throw new IllegalArgumentException("位置异常");
        
            Node prev=dummyHead;
            for (int i = 0; i < index; i++) {
                prev=prev.next;
            }

                prev.next=new Node(e,prev);
                size++;

    }
    //链表头添加新的元素e
    public void addFirst(E e){
        add(0,e);
    }
    //在链表末尾添加新的元素e
    public void addLast(E e){
        add(size,e);
    }

}

 

 从链表中删除元素

调用toString时,由于定义了虚拟头部,导致e值为null,无法输出

错误示范

package com.dataStructrue;

public class LinkedList <E>{

    private class Node{
        public E e;
        public Node next;

        public Node(E e,Node next){
            this.e=e;
            this.next=next;
        }

        public Node(E e){
            this(e,null);
        }

        public Node(){
            this(null,null);
        }

        @Override
        public String toString(){

                return e.toString();

        }
    }

    private Node dummyHead;
    private int size;

    public LinkedList(){
        dummyHead=new Node(null,null);
        size=0;
    }
    //获取链表中元素个数
    public int getSize(){
        return size;
    }

    //
    public boolean isEmpty(){
        return size==0;
    }



    //链表中间第index(0-based)个位置添加新的元素e
    public void add(int index,E e){

        if (index<0||index>size)
        throw new IllegalArgumentException("位置异常");

            Node prev=dummyHead;
            for (int i = 0; i < index; i++) {
                prev=prev.next;
            }

                prev.next=new Node(e,prev);
                size++;

    }
    //链表头添加新的元素e
    public void addFirst(E e){
        add(0,e);
    }
    //在链表末尾添加新的元素e
    public void addLast(E e){
        add(size,e);
    }

    //获得链表中第index个位置元素
    //练习用
    public E get(int index){
        if(index<0||index>=size)
            throw new IllegalArgumentException("位置异常");

        Node cur=dummyHead.next;
        for (int i = 0; i < index; i++) {
            cur=cur.next;
        }
        return cur.e;
    }

    //获得链表的第一个元素
    public E getFirst(int index){
        return get(0);
    }
    //获得链表的最后一个元素
    public E getLast(int index){
        return get(size-1);
    }

    //修改第index位置元素为e
    public void set(int index,E e){

        if(index<0||index>=size)
            throw new IllegalArgumentException("位置异常");

        Node cur=dummyHead.next;
        for (int i = 0; i < index; i++) {
            cur=cur.next;
        }
        cur.e=e;
    }

    //查找链表中是否存在元素e
    public boolean contains(E e){
        Node cur=dummyHead.next;
        while (cur!=null){
            if (cur.e.equals(e))
                return true;
            cur=cur.next;
        }
        return false;
    }

    @Override
    public String toString(){
        StringBuilder res=new StringBuilder();

//        Node cur=dummyHead.next;
//        while (cur!=null){
//            res.append(cur+"->");
//            cur=cur.next;
//        }

        for(Node cur=dummyHead.next;cur!=null;cur=cur.next)
            res.append(cur+"->");

        res.append("NULL");

        return res.toString()+"";
    }
}
package com.dataStructrue;

public class M {
    public static void main(String[] args){

        LinkedList<Integer>linkedList=new LinkedList<>();
        for (int i = 0; i < 5; i++) {
            linkedList.addFirst(i);
            System.out.println(linkedList);
        }
        linkedList.add(2,666);
        System.out.println(linkedList);
    }
}

预计输出结果:

实际输出结果:

由于25行toString中出现空指针而报错。

add方法里面,prev.next=new Node(e,prev.next);

漏掉了.next,   prev.next=new Node(e,prev);导致进入了无限套娃

时间复杂度分析

 

增、删、改、查的时间复杂度都是O(n)

此时与数组一样,但是由于是动态的,所以不会浪费大量内存

使用链表实现栈

package com.dataStructrue;

public class LinkedList <E>{


    private class Node{
        public E e;
        public Node next;

        public Node(E e,Node next){
            this.e=e;
            this.next=next;
        }

        public Node(E e){
            this(e,null);
        }

        public Node(){
            this(null,null);
        }

        @Override
        public String toString()throws IllegalArgumentException{
                if(e==null)
                    throw new IllegalArgumentException("KONG");

                return e.toString();

        }
    }

    private Node dummyHead;
    private int size;

    public LinkedList(){
        dummyHead=new Node(null,null);
        size=0;
    }
    //获取链表中元素个数
    public int getSize(){
        return size;
    }

    //
    public boolean isEmpty(){
        return size==0;
    }



    //链表中间第index(0-based)个位置添加新的元素e
    public void add(int index,E e){

        if (index<0||index>size)
        throw new IllegalArgumentException("位置异常");

            Node prev=dummyHead;
            for (int i = 0; i < index; i++) {
                prev=prev.next;
            }

                prev.next=new Node(e,prev.next);
                size++;

    }
    //链表头添加新的元素e
    public void addFirst(E e){
        add(0,e);
    }
    //在链表末尾添加新的元素e
    public void addLast(E e){
        add(size,e);
    }

    //获得链表中第index个位置元素
    //练习用
    public E get(int index){
        if(index<0||index>=size)
            throw new IllegalArgumentException("位置异常");

        Node cur=dummyHead.next;
        for (int i = 0; i < index; i++) {
            cur=cur.next;
        }
        return cur.e;
    }

    //获得链表的第一个元素
    public E getFirst(){
        return get(0);
    }
    //获得链表的最后一个元素
    public E getLast(int index){
        return get(size-1);
    }


    //修改第index位置元素为e
    public void set(int index,E e){

        if(index<0||index>=size)
            throw new IllegalArgumentException("位置异常");

        Node cur=dummyHead.next;
        for (int i = 0; i < index; i++) {
            cur=cur.next;
        }
        cur.e=e;
    }

    //查找链表中是否存在元素e
    public boolean contains(E e){
        Node cur=dummyHead.next;
        while (cur!=null){
            if (cur.e.equals(e))
                return true;
            cur=cur.next;
        }
        return false;
    }

    @Override
    public String toString(){
        StringBuilder res=new StringBuilder();

//        Node cur=dummyHead.next;
//        while (cur!=null){
//            res.append(cur+"->");
//            cur=cur.next;
//        }

        for(Node cur=dummyHead.next;cur!=null;cur=cur.next)
            res.append(cur+"->");
        res.append("NULL");

        return res.toString();
    }
//从链表中删除index位置的元素
    public E remove(int index){
        if(index<0||index>=size)
            throw new IllegalArgumentException("位置异常");

        Node prev=dummyHead;
        for (int i = 0; i < index; i++) {
            prev=prev.next;
        }
        Node retNode=prev.next;
        prev.next=retNode.next;
        retNode.next=null;
        size--;
        return retNode.e;
    }
//从链表中删除最后一个元素,返回删除的元素
public E removeLast(){
        return remove(size-1);
}

    public E removeFirst(){
        return remove(0);
    }
}
package com.dataStructrue;

import javax.annotation.Resource;

public class LinkedListStack<E> implements Stack<E>{

//    private LinkedList<E> list;
//
//    public LinkedListStack(){
//        list=new LinkedList<>();
//    }
   private LinkedList<E> list=new LinkedList<E>();

    @Override
    public int getSize(){
        return list.getSize();
    }

    @Override
    public boolean isEmpty(){
        return list.isEmpty();
    }

    @Override
    public void push(E e){
        list.addFirst(e);
    }


    @Override
    public E peak(){ return list.getFirst(); }

    @Override
    public E pop(){
        return list.removeFirst();
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append("Stack:top");
        res.append(list);
        return res.toString();
    }

    public static void main(String[] args){

        LinkedListStack<Integer>stack=new LinkedListStack<>();
        for (int i = 0; i < 5; i++) {
            stack.push(i);
            System.out.println(stack);;
    }
            stack.pop();
            System.out.println(stack);


        }
}

使用链表实现队列

由于没有dummyHead,需要注意链表为空的问题

package com.dataStructrue;

public class LinkedListQueue<E> implements Queue<E> {

    private class Node{
        public E e;
        public Node next;

        public Node(E e, Node next){
            this.e=e;
            this.next=next;
        }

        public Node(E e){
            this(e,null);
        }

        public Node(){
            this(null,null);
        }

        @Override
        public String toString(){
            return e.toString();
        }
    }

    private Node head,tail;//定义头节点和尾节点
    private int size;//定义整型记录长度

    public LinkedListQueue(){//与不写构造函数,默认的构造函数是一样的
        head=null;
        tail=null;
        size=0;
    }

    @Override
    public int getSize(){
        return size;
    }
    @Override
    public boolean isEmpty(){
        return size==0;
    }
    @Override//入队操作
    public void enqueue(E e){
        if(tail==null){
            tail=new Node(e);
            head=tail;
        }else {
            tail.next=new Node(e);
            tail=tail.next;
        }
        size++;
    }
    @Override//出队操作
    public E dequeue(){
        if (isEmpty())
            throw new IllegalArgumentException("不能出空");

        Node retNode=head;
        head=head.next;
        retNode.next=null;
        if (head==null)
            tail=null;//链表只有一个元素时,首尾是一样的
        size--;
        return retNode.e;
    }
    @Override
    public E getFront(){
        if (isEmpty())
            throw new IllegalArgumentException("不能为空");
        return head.e;
    }
    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
           res.append("Queue:front");

           Node cur=head;
           while (cur!=null){
               res.append(cur+"->");
               cur=cur.next;
           }
           res.append("NULL tail");
           return res.toString();
    }
    public static void main(String[] args) {
        LinkedListQueue<Integer>queue=new LinkedListQueue<>();
        for (int i = 0; i < 10; i++) {
            queue.enqueue(i);
            System.out.println(queue);

            if (i%3==2){
                queue.dequeue();
                System.out.println(queue);

            }
        }
    }
}

/*结果
Stack:top0->NULL
Stack:top1->0->NULL
Stack:top2->1->0->NULL
Stack:top3->2->1->0->NULL
Stack:top4->3->2->1->0->NULL
Stack:top3->2->1->0->NULL
*/

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值