学习数据结构Day4

链表

 

之前看过了动态数组,栈和队列,虽然我们把第一个叫做动态数组,但是,他们的底层实质上还是静态数组。靠

resize来实现动态数组。而链表是真正的数据结构

  • 链表需要一个节点。
  • 数据存储在链表中

相当于是一串火车,将数据放在车厢中,两个车厢之间还需要一个个节点来相互串联。

优点:实现了真正的动态。

缺点:无法进行随机访问

public class LinkedList<E> {

    private class Node {

        public E e;
        public Node next;

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

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

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

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

    private Node head;
    private int size;

    public LinkedList(Node head, int size) {
        head = null;
        this.size = 0;
    }

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

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

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

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

    //在链表的index位置添加新的元素e
    //在链表中不是一个常用的操作 :)
    public void add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Add failed,Illegal index");
        }
        if (index == 0) {
            addFirst(e);
        } else {
            Node prev = new Node(e);
            for (int i = 0; i < index - 1; i++) {
                prev.next = prev;
            }
//            Node node = new Node(e);
//            prev.next = node.next;
//            prev.next = node;
            prev.next = new Node(e,prev.next);

            size++;
        }
    }

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

这是自己建立的链表,在此处,一定要注意几点

  • 在增加或删除元素时,不要忘了维护size
  • 再添加链表时,一定不要忘了顺序的问题,一定是先prev.next = node.next.之后才是prev.next = node;
  • 一开始的时候 head = prev

再添加操作时,由于头结点的上一个节点时null,所以我们需要特殊处理,为了解决这个问题,我们增加了一个虚拟

头结点。这个节点不存出任何数据。

public class LinkedList<E> {

    private class Node {

        public E e;
        public Node next;

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

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

        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 LinkedList(Node head, int size) {
        head = null;
        this.size = 0;
    }

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

    //返回链表是否为空
    public boolean isEmpty() {
        return size == 0;
    }
    //在链表的index位置添加新的元素e
    //在链表中不是一个常用的操作 :)
    public void add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Add failed,Illegal index");
        }

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

        size++;

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

        add(0,e);
        size++;
    }
    //在末尾添加元素
    public void addLast(E e) {
        add(size, e);
    }


}

链表的遍历,增 删 改 查。

public class LinkedList<E> {

    private class Node {

        public E e;
        public Node next;

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

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

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


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

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

        size++;

    }


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

        add(0, e);

    }


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

    /**
     * 遍历整个列表
     * 实际过程中不会这么用
     * 仅供联系
     *
     * @param index
     * @return
     */
    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;
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;
        }
res.append("null");
return res.toString();
}
}

之前这些代码我们写完了增 改 查,下面我们就要写删除操作。

 //删除链表中的一个元素
    public E remove(int index) {
        if (index > 0 || index < size) {
            throw new IllegalArgumentException("remove failed");
        }
        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);
    }

链表的时间复杂度

  • addLast(e):O(n)
  • addFirst(e):O(1)
  • add(index,e):O(n)
  • setIndex(e):O(n)
  • get(index):O(n)
  • contains(e):O(n)

如果只对链表头进行操作,那么他的时间复杂度是O(1),所以我们来尝试一下利用链表来做栈的可能性。

import java.util.List;

/**
 * @author shkstart
 * @create 2019-11-29 13:03
 */
public class LinkedListStack<E> implements Stack<E>{

    private LinkedList<E> list;

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

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

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

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

    @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<Integer>();

        for (int i = 0; i < 5; i++) {
            stack.push(i);
            System.out.println(stack);
        }

        stack.pop();
        System.out.println(stack);
    }
}

做完了栈,同样的 我们试验一下利用链表实现队列。

 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 tail, head;

    private int size;

    public LinkedListQueue(Node tail, Node head, int size) {
        this.tail = null;
        this.head = null;
        this.size = 0;
    }

    public LinkedListQueue() {
    }

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

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

    @Override
    public void enqueue(E e) {
        if (tail.next == null) {
            Node node = new Node(e);
            tail = head;
        } else {
            tail.next = new Node(e);
            tail = tail.next;
        }
        size++;
    }

    @Override
    public E dequeue() {

        if (isEmpty()) {
            throw new IllegalArgumentException("dequeue出错!");
        }

        Node ret = head;
        head = head.next;
        ret.next = null;
        if (head == null) {
            tail = head;
        }
        size--;
        return ret.e;
    }

    @Override
    public E getFront() {
        if (isEmpty()) {
            throw new IllegalArgumentException("Queue is empty");
        }
        return head.e;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Queue:");
        builder.append("front [");
        Node cur = head;
        while (cur != null) {
            cur = cur.next;
        }
        builder.append("Null tail");
        return builder.toString();

    }


    public static void main(String[] args) {
LinkedListQueue<Integer> LinkedListQueue = new LinkedListQueue<Integer>();
for (int i = 0; i < 10; i++) {
LinkedListQueue.enqueue(i);
System.out.println(LinkedListQueue);
if (i % 3 == 2) {
LinkedListQueue.dequeue();
System.out.println(LinkedListQueue);
            }
        }
    }

在这里的链表我们写了尾指针!

原文地址:https://www.cnblogs.com/xiaobaoa/p/11960642.html