数据结构之链表


链表

数组要一块连续的内存空间来存储,对内存的要求比较高。如果我们申请一个100MB大小的数组,当内存中没有连续的、足够大的存储空间 时,即便内存的剩余总可用空间大于 100MB,仍然会申请失败。
链表恰恰相反,它并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用,所以如果我们申请的是 100MB 大小的链表,根本不会有问题。

链表通过指针将一组零散的内存块串联在一起。其中,我们把内存块称为链表的“结点”。为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点 的地址。如图所示,我们把这个记录下个结点地址的指针叫作后继指针 next。

单链表(数组)

其中有两个结点是比较特殊的,它们分别是第一个结点和最后一个结点。我们习惯性地把第一个结点叫作头结点,把最后一个结点叫作尾结点。其中,头结点用来记录链表的基地址。有了它,我们就可以遍历得到整条链表。而尾结点特殊的地方是:指针 不是指向下一个结点,而是指向一个空地址 NULL,表示这是链表上最后一个结点。与数组一样,链表也支持数据的查找、插入和删除操作。只不过效率会不高。

循环链表

循环链表是一种特殊的单链表。它跟单链表唯一的区别就在尾结点:单链表的尾结点指针指向空地址,表示这就是最后的结点了。而循环链表的尾结点指针是指向链表的头结点。

双向链表

双向链表需要额外的两个空间来存储后继结点和前驱结点的地址。所以,如果存储同样多的数据,双向链表要比单链表占用更多的内存空间。虽然两个指针比较浪费存储空间,但可以支持双向遍历,这样也带来了双向链表操作的灵活性。那相比单链表,双向链表适解决删除结点中“值等于某个给定值”的结点,删除给定指针指向的结点。

双向循环链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

代码实现

单向链表

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

    //为链表头添加新的元素E
    public void addFirst(E e) {
        add(0, e);
    }

    //在链表的index(0-based)位置添加新的元素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;
        }

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

    public void addLast(E e) {
        add(size, e);
    }

    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)个位置的元素
    //不常用的操作
    public void set(int index, E e) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Update Failed.Illegal index");
        } else {
            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;
    }

    public E remove(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Update Failed.Illegal index");
        } else {
            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();
        
        for (Node cur = dummyHead.next; cur != null; cur = cur.next) {
            res.append(cur + "->");
        }
        res.append("NULL");
        return res.toString();
    }

}
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.add(2, 666);
        System.out.println(linkedList);
        linkedList.remove(2);
        System.out.println(linkedList);
        linkedList.removeFirst();
        System.out.println(linkedList);
        linkedList.removeLast();
        System.out.println(linkedList);

    }
}

循环链表

public class SinglyLoopLink {
    public Node head;
    public Node tail;
    public int size;

    public SinglyLoopLink(){
        this.size=0;
        this.head=new Node(0);
        this.tail=new Node(0);
        head.next=tail;
        tail.next=head;
    }

    class Node {
        Node next;
        int data;
        public Node(){

        }
        public Node(int data){
            this.data=data;
        }
    }

    public void add(int data){
        Node newNode=new Node(data);
        if (head == null) {
            newNode.next=tail;
            head.next=newNode;

        }else{
            Node temp=head;
            while(temp.next!=tail){
                temp=temp.next;
            }
            temp.next=newNode;
            newNode.next=tail;
        }
        size++;
    }

    public String add(int index,int data){
        Node temp=head;
        Node newNode=new Node(data);
        if(index<0||index>size){
            return "数组指标有误";
        }
        for(int i=0;i<size;i++){
            temp=temp.next;

            if(index==0){
                head.next=newNode;
                newNode.next=temp;
                size++;
                break;
            }else if(i==index-1){
                System.out.println("this is "+size);
                newNode.next=temp.next;
                temp.next=newNode;
                size++;
                break;
            }
        }
        return null;
    }

    public String addFirst(int data){
        return add(0,data);
    }

    public String addLast(int data){
        return add(size,data);
    }


    public String disPlay(){
        SinglyLoopLink.Node temp=head;
        StringBuffer result=new StringBuffer("[=>head=>");
        for(int i=0;i<size;i++){
            temp=temp.next;
            result.append(temp.data+"=>");

        }
        result.append("tail=>]");
        return result.toString();
    }

    public static void main(String[] args) {
        SinglyLoopLink singlyLoopLink=new SinglyLoopLink();
        singlyLoopLink.add(1);
        singlyLoopLink.add(2);
        singlyLoopLink.add(0,-9);
        singlyLoopLink.add(1,9);
        singlyLoopLink.add(4,10);
        singlyLoopLink.addFirst(-99);
        singlyLoopLink.addLast(100);
        singlyLoopLink.add(0,-155);
        singlyLoopLink.add(3,10);
        System.out.println(singlyLoopLink.disPlay());
    }

}

双向链表

public class LinkList {
    Node head;
    Node tail;
    //申明该变量不会被持久化
    transient int size=0;
    int data;
    class Node{
        int data;
        Node pre;
        Node next;
        Node(int data,Node pre,Node next){
            this.data=data;
            this.pre=pre;
            this.next=next;
        }
        Node(int data){
            this.data=data;
        }
        Node(){
        }
    }

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

    public LinkList(){
        head=new Node();
        tail=new Node();
    }


    //添加头部节点(只有一个元素的时候)
    public void addHeadNode(int data){
        Node node=new Node(data,null,null);
        head.next=node;
        node.pre=head;
        node.next=tail;
        tail.pre=node;
        size++;
    }

    //尾插法
    public void addLast(int data){
        if(head.next==null){
            addHeadNode(data);
        }else{
            Node temp=head;
            Node newNode=new Node(data);
            for(int i=0;i<size;i++){
                temp=temp.next;
            }
            newNode.pre=temp;
            newNode.next=tail;
            temp.next=newNode;
            tail.pre=newNode;
            size++;
        }
    }

    //头插法
    public void addBegin(int data){
//        add(0,data);
        if(head.next==null){
            addHeadNode(data);
            size++;
        }else {
            Node newNode = new Node(data);
            newNode.next = head.next;
            newNode.pre = head;
            head.next = newNode;
            size++;
        }
    }

    //从指定索引位置插入相应的内容
//    public void add(int index,int data){
//        //链表里面已经有相应的元素了
////        if(head.next!=null){
//            Node temp=head;
//            Node newNode=new Node(data);
//            if(index==0){
//                newNode.pre=head;
//                newNode.next=head.next;
//                head.next=newNode;
//            }
//            if(index<size&&index>0){ //最后一个节点处插入需要特殊处理
//                for(int i=0;i<index;i++){
//                    temp=temp.next;
//                }
//                newNode.next=temp.next;
//                newNode.pre=temp;
//                temp.next.pre=newNode;
//                temp.next=newNode;
//            }
//            if(index==size&&size!=0){
//                for(int i=0;i<index;i++){
//                    temp=temp.next;
//                }
//                temp.next=newNode;
//                newNode.pre=temp;
//                newNode.next=tail;
//                tail.pre=newNode;
//            }
//            size++;
////        }
//
//    }


    public Node get(int index){
        if(index>size || index<0){
            throw new RuntimeException("链表下标超出范围了!");
        }
        Node currentNode=head;
        for(int j=0;j<size;j++){
            currentNode=head.next;
            if(j==index){
                return currentNode;
            }
        }
        return null;
    }

    //根据索引,删除某一个链表元素内容
    public String remove(int index){
        Node temp=head;
        if(index>=size){
            return "下标超值";
        }
        for(int i=0;i<size;i++){
            //并非最后一个数值
            if(i==index){
                temp.next=temp.next.next;
                temp.next.pre=temp;
                size--;
                break;
            }
            temp=temp.next;
        }
        return null;
    }

    public void removeData(Integer data){
        Node temp=head;
        Node preNode;
        for(int i=0;i<size;i++){
            preNode=temp;
            temp=temp.next;
            if(temp.data==data){
                preNode.next=temp.next;
                size--;
                break;
            }
        }
    }

    public void removeNode(Node itemNode){
      Node preNode=itemNode.pre;
      Node nextNode=itemNode.next;
      preNode.next=nextNode;
      size--;
    }

    public String removeFirst(){
        return remove(0);
    }

    public String removeLast(){
//        if(size==2){ //剩余头尾两个节点和一个元素的时候
//            remove(0);
//        }
        return remove(size-1);
    }


    public String disPlay(){
        Node temp=head.next;
        StringBuffer result=new StringBuffer("[head<==>");
        int index=0;
        for(int i=0;i<size;i++){
            index++;
            result.append(temp.data+"<==>");
            temp=temp.next;
        }
        result.append("tail]");
        return result.toString();
    }

    public static void main(String[] args) {
        LinkList linkList=new LinkList();
        linkList.addLast(1);
        linkList.addLast(2);
        linkList.addLast(3);
        linkList.addBegin(34);
        linkList.addLast(44);
        System.out.println(linkList.disPlay());
        linkList.removeData(2);
        linkList.removeData(3);
        System.out.println(linkList.disPlay());
        Node node=linkList.get(0);

        linkList.removeNode(node);
        System.out.println(linkList.disPlay());
    }

双向循环链表

public class DoubleLoopLink {
    Node head;
    Node tail;
    //申明该变量不会被持久化
    transient int size=0;
    int data;
    class Node{
        int data;
        Node pre;
        Node next;
        Node(int data,Node pre,Node next){
            this.data=data;
            this.pre=pre;
            this.next=next;
        }
        Node(int data){
            this.data=data;
        }
        Node(){
        }
    }

    public DoubleLoopLink(int size,Node head,Node tail){
        this.size=0;
        this.head=head;
        this.tail=tail;

    }

    public DoubleLoopLink(){
        head=new Node();
        head.pre=tail;
        head.next=tail;
        tail=new Node();
        tail.pre=head;
        tail.next=head;
    }


    //添加头部节点(只有一个元素的时候)
    public void addHeadNode(int data){
        Node node=new Node(data,null,null);
        head.next=node;
        node.pre=head;
        node.next=tail;
        tail.pre=node;
        size++;
    }

    //尾插法
    public void add(int data){
        if(head.next==null){
            addHeadNode(data);
        }else{
            Node temp=head;
            Node newNode=new Node(data);
            for(int i=0;i<size;i++){
                temp=temp.next;
            }
            newNode.pre=temp;
            newNode.next=tail;
            temp.next=newNode;
            tail.pre=newNode;
            size++;
        }
    }

    //头插法
    public void addBegin(int data){
        if(head.next==null){
            addHeadNode(data);
            size++;
        }else {
            Node newNode = new Node(data);
            newNode.next = head.next;
            newNode.pre = head;
            head.next = newNode;
            size++;
        }
    }

    //从指定索引位置插入相应的内容
    public void add(int index,int data){
        //链表里面已经有相应的元素了
//        if(head.next!=null){
        Node temp=head;
        Node newNode=new Node(data);
        if(index==0){
            newNode.pre=head;
            newNode.next=head.next;
            head.next=newNode;
        }
        if(index<size&&index>0){ //最后一个节点处插入需要特殊处理
            for(int i=0;i<index;i++){
                temp=temp.next;
            }
            newNode.next=temp.next;
            newNode.pre=temp;
            temp.next.pre=newNode;
            temp.next=newNode;
        }
        if(index==size&&size!=0){
            for(int i=0;i<index;i++){
                temp=temp.next;
            }
            temp.next=newNode;
            newNode.pre=temp;
            newNode.next=tail;
            tail.pre=newNode;
        }
        size++;
//        }

    }

    //根据索引,删除某一个链表元素内容
    public String remove(int index){
        Node temp=head;
        if(index>=size){
            return "下标超值";
        }
        for(int i=0;i<size;i++){
            //并非最后一个数值
            if(i==index){
                temp.next=temp.next.next;
                temp.next.pre=temp;
                size--;
                break;
            }
            temp=temp.next;
        }
        return null;
    }

    public String removeFirst(){
        return remove(0);
    }

    public String removeLast(){
        return remove(size);
    }


    public String disPlay(){
        Node temp=head.next;
        StringBuffer result=new StringBuffer("[<==>head<==>");
        int index=0;
        for(int i=0;i<size;i++){
            index++;
            result.append(temp.data+"<==>");
            temp=temp.next;
        }

        result.append("<==>tail<==>]");
        return result.toString();
    }

    public static void main(String[] args) {
        DoubleLoopLink doubleLoopLink=new DoubleLoopLink();
        doubleLoopLink.add(-1);
        doubleLoopLink.add(-2);
        doubleLoopLink.add(-3);
        System.out.println(doubleLoopLink.disPlay());
    }
}

时间复杂度分析

添加操作 O(n)
addFirst O(1)
addLast O(n)
add(index,e) O(n/2)=O(n)
删除操作 O(n)
rremoveFirst(e) O(1)
removeLast O(n)
remove(index,e) O(n/2)=O(n)
修改操作 O(n)
set(index,e) O(n)
查找操作 O(n)
get(index) O(n)
contains(e) O(n)

如果值对链表头进行操作时间复杂度为O(1)

链表栈

public interface Stack<E> {

    int getSize();
    boolean isEmpty();
    void push(E e);
    E pop();
    E peek();
}
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;
    }

    // 在链表的index(0-based)位置添加新的元素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;

        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(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("Update 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;
    }

    // 从链表中删除index(0-based)位置的元素, 返回删除的元素
    // 在链表中不是一个常用的操作,练习用:)
    public E remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        // E ret = findNode(index).e; // 两次遍历

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

    // 从链表中删除元素e
    public void removeElement(E e){

        Node prev = dummyHead;
        while(prev.next != null){
            if(prev.next.e.equals(e))
                break;
            prev = prev.next;
        }

        if(prev.next != null){
            Node delNode = prev.next;
            prev.next = delNode.next;
            delNode.next = null;
            size --;
        }
    }

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

性能比较

数组栈和链表栈对比测试:

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 = 20000000;

        ArrayStack<Integer> arrayStack = new ArrayStack<>();
        System.out.println("opCount:"+opCount);
        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操作
    }
}

链表队列

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("Cannot dequeue from an empty queue.");

        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("Queue is empty.");
        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);
            }
        }
    }
}

队列性能

性能比较

import java.util.Random;

public class Main {

    // 测试使用q运行opCount个enqueueu和dequeue操作所需要的时间,单位:秒
    private static double testQueue(Queue<Integer> q, int opCount){

        long startTime = System.nanoTime();

        Random random = new Random();
        for(int i = 0 ; i < opCount ; i ++)
            q.enqueue(random.nextInt(Integer.MAX_VALUE));
        for(int i = 0 ; i < opCount ; i ++)
            q.dequeue();

        long endTime = System.nanoTime();

        return (endTime - startTime) / 1000000000.0;
    }

    public static void main(String[] args) {

        int opCount = 100000;

        ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();
        double time1 = testQueue(arrayQueue, opCount);
        System.out.println("ArrayQueue, time: " + time1 + " s");

        LoopQueue<Integer> loopQueue = new LoopQueue<>();
        double time2 = testQueue(loopQueue, opCount);
        System.out.println("LoopQueue, time: " + time2 + " s");

        LinkedListQueue<Integer> linkedListQueue = new LinkedListQueue<>();
        double time3 = testQueue(linkedListQueue, opCount);
        System.out.println("LinkedListQueue, time: " + time3 + " s");
    }

}

资料参考

<<数据结构与算法之美>>

<<玩转数据结构>>

Gitee: https://gitee.com/IdeaHome_admin/projects

斯坦福链表问题


文章作者: 清风笑丶
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 清风笑丶 !
 上一篇
数据结构之递归 数据结构之递归
递归(英语:Recursion),又译为递回,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。递归一词还较常用于描述以自相似方法重复事物的过程。例如,当两面镜子相互之间近似平行时,镜中嵌套的图像是以无限递归的形式出现的。也可以理
2019-05-06
下一篇 
数据结构之队列 数据结构之队列
简介队列是是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。 队列是一种先进先出的线性表,简称FIFO允许插入的以端称为队尾,允许删除的一端被称为队头。 入队 出队 数组实现队列public class Array<E> {
2019-05-03
  目录