java实现链表,用链表实现链表栈和链表队列

链表:真正的动态数据结构

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

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

  3. 更深入的理解递归

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

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

缺点 :丧失了随机访问的能力


数组和链表的对比

数组:最好用于索引有语义的情况,支持快速查询

链表:不适合用于索引有语义的情况,动态。


内部类Node

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();
        }
    }
}

添加元素

 //在链表的index(0-based)位置添加新的元素e
    //在链表中不是一个常用的操作,练习用
    public void add(int index, E e) {
        if (index < 0 || index > size)
            throw new IllegalArgumentException("Add failed, IllegalIndex");

        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) {
        /*Node node=new Node(e,null);
        node.next=head;
        head=node;*/


        /*head=new Node(e,head);
        size++;*/

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

    }

获取元素

//获得链表的第index(0-based)个位置的元素
    //在链表中不是一个常用的操作,练习用
    public E get(int index){
        if(index<0||index>size)
            throw new IllegalArgumentException("Get Failed, Illegal Index");
        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(){
        return get(size-1);
    }

修改元素

//修改链表的第index(0-based)个位置的元素为e
    //在链表中不是一个常用的操作,练习用
    public void set(int index, E e){
        if(index<0||index>size)
            throw new IllegalArgumentException("Set Failed, Illegal Index");
        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;
        /*for (int i = 0; i < size-1; i++) {
            if(cur.e==e)return true;
            cur=cur.next;
        }*/

        while(cur!=null){
            if(cur.e.equals(e))return true;
            cur=cur.next;
        }
        return false;
    }

删除元素

  //从链表中删除index(0-based)位置的元素,返回删除的元素
    //在链表中不是一个常用的操作,练习用
    public E remove(int index){
        if(index<0||index>size)
            throw new IllegalArgumentException("Remove Failed, Illegal Index");
        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 removeFirst(){
        return remove(0);
    }
 //从链表中删除最后一个元素,返回删除的元素
    public E removeLast(){
        return remove(size-1);
   }

输出

@Override
    public String toString() {
        StringBuilder res=new StringBuilder();
        Node cur=dummyHead.next;
        while(cur!=null){
            res.append(cur.e+"->");
            cur=cur.next;
        }
        res.append("NULL");
        return res.toString();
    }

LinkedList.java 完整代码

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();
        size = 0;
    }

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

    //链表是否为空
    public boolean isEmpty() {
        return size == 0;
    }

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


        /*head=new Node(e,head);
        size++;*/

        add(0, e);
    }

    //在链表的index(0-based)位置添加新的元素e
    //在链表中不是一个常用的操作,练习用
    public void add(int index, E e) {
        if (index < 0 || index > size)
            throw new IllegalArgumentException("Add failed, IllegalIndex");

        Node prev = dummyHead;
        for (int i = 0; i < index; i++)
            prev = prev.next;
        prev.next = new Node(e, prev.next);
        size++;
    }

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

    }

    //获得链表的第index(0-based)个位置的元素
    //在链表中不是一个常用的操作,练习用
    public E get(int index){
        if(index<0||index>size)
            throw new IllegalArgumentException("Get Failed, Illegal Index");
        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(){
        return get(size-1);
    }

    //修改链表的第index(0-based)个位置的元素为e
    //在链表中不是一个常用的操作,练习用
    public void set(int index, E e){
        if(index<0||index>size)
            throw new IllegalArgumentException("Set Failed, Illegal Index");
        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;
        /*for (int i = 0; i < size-1; i++) {
            if(cur.e==e)return true;
            cur=cur.next;
        }*/

        while(cur!=null){
            if(cur.e.equals(e))return true;
            cur=cur.next;
        }
        return false;
    }
    //从链表中删除index(0-based)位置的元素,返回删除的元素
    //在链表中不是一个常用的操作,练习用
    public E remove(int index){
        if(index<0||index>size)
            throw new IllegalArgumentException("Remove Failed, Illegal Index");
        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 removeFirst(){
        return remove(0);
    }
    //从链表中删除最后一个元素,返回删除的元素
    public E removeLast(){
        return remove(size-1);
    }
    @Override
    public String toString() {
        StringBuilder res=new StringBuilder();
        Node cur=dummyHead.next;
        while(cur!=null){
            res.append(cur.e+"->");
            cur=cur.next;
        }
        res.append("NULL");
        return res.toString();
    }
}



Main.java 测试用例

public class Main {
    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.addLast(999);
        System.out.println(linkedList);

        linkedList.add(3,787);
        System.out.println(linkedList);

        linkedList.remove(1);
        System.out.println(linkedList);

        linkedList.removeFirst();
        System.out.println(linkedList);
    }
}

运行结果:

0->NULL
1->0->NULL
2->1->0->NULL
3->2->1->0->NULL
4->3->2->1->0->NULL
4->3->2->1->0->999->NULL
4->3->2->787->1->0->999->NULL
4->2->787->1->0->999->NULL
2->787->1->0->999->NULL

时间复杂度分析

添加操作 时间复杂度
add(index,e) O(n/2)=O(n)
addFirst() O(1)
addLast() O(1)
删除操作 时间复杂度
remove(index,e) O(n/2)=O(n)
removeFirst() O(1)
removeLast() O(n)
修改操作 时间复杂度
set(index,e) O(n)
查询操作 时间复杂度
get(index) O(n)
contains(e) O(n)

用链表实现栈

Stack接口

public interface Stack<E> {

    int getSize();
    boolean isEmpty();
    void push(E e);
    E pop();
    E peek();
}

具体实现类 LinkedListStack.java

public class LinkedListStack<E> implements Stack<E> {
    private LinkedList<E> list;
    public LinkedListStack(){
        list=new LinkedList<>();
    }

    @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 pop() {
        return list.removeFirst();
    }

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

    @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);
    }
}

运行结果:

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

思考一下 链表实现的栈和数组实现的栈哪个时间复杂度更低?

测试一下

import java.util.Random;

public class Main {
    //测试Stack运行opCount个push和pop操作所需要的时间,单位:秒
    private static double testStack(Stack<Integer> stack, int opCount){
        long startTime=System.nanoTime();

        Random random=new Random();
        for (int i = 0; i < opCount; i++)
            stack.push(random.nextInt(Integer.MAX_VALUE));
        for (int i = 0; i < opCount; i++)
            stack.pop();

        long endTime=System.nanoTime();

        return (endTime-startTime)/1000000000.0;

    }
    public static void main(String[] args) {

        int opCount=100000;
        ArrayStack<Integer> arrayStack=new ArrayStack<>();
        double time1=testStack(arrayStack,opCount);
        System.out.println("ArrayStack, time: " + time1 + " s");

        LinkedListStack<Integer> linkedListStack=new LinkedListStack<>();
        double time2=testStack(linkedListStack,opCount);
        System.out.println("LinkedListStack, time: " + time2 + " s");
        //实际中这个时间更加复杂,因为LinkedListStack中包含了更多的new操作


    }


}

运行结果:

ArrayStack, time: 0.016972503 s
LinkedListStack, time: 0.020020522 s

根据不同操作系统不同内部因素影响,这两者的比较还是相对复杂的,但总体来说LinkedListStack耗时更长,因为它会不停地进行new操作,当然还有许多原因,不去细究。

将opCount换成10000000的结果

ArrayStack, time: 2.662845123 s
LinkedListStack, time: 4.303465165 s

总之,两者之间没有巨大的复杂度差异,后者略微逊色一点。


用链表实现队列

不用头结点实现,对首负责出队,对尾负责出队。

Queue接口

public interface Queue<E> {

    int getSize();
    boolean isEmpty();
    void enqueue(E e );
    E dequeue();
    E getFront();
}

LinkedListQueue.java

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("Connot dequeue from an empty enqueue");
        Node retNode=head;
        head=head.next;
        retNode.next=null;
        //如果队列中只会有一个元素,要维护tail,不然tail指向的是retNode,而不是null
        if(head==null){
            tail=null;
        }
        size--;
        return retNode.e;
    }

    @Override
    public E getFront() {
        if(isEmpty())
        throw new IllegalArgumentException("Connot dequeue from an empty enqueue");
    return head.e;
    }

    @Override
    public String toString() {
        StringBuilder res=new StringBuilder();
        res.append("Queue:front");
        Node cur=head;
        while(cur!=null){
            res.append(cur.e+"->");
            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);
            }

        }
    }
}


运行结果:

你可能感兴趣的:(数据结构学习,算法,链表,单链表,数据结构,java)