前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据结构之链表解析

数据结构之链表解析

作者头像
Kevin_Zhang
发布2019-03-14 00:46:36
3910
发布2019-03-14 00:46:36
举报
文章被收录于专栏:Kevin-ZhangCGKevin-ZhangCG

  我们知道,数组作为数据存储结构有一定的缺陷。在无序数组中,搜索时低效的;而在有序数组中,插入效率又很低;不管在哪一种数组中删除效率都很低。况且一个数组创建后,它的大小是无法改变的。而链表可能是继数组之后第二种使用得最广泛的通用数据结构了。这里主要来讨论并写一个单链表和双向链表。

  顾名思义,单链表只能从表头到表尾的顺序,每个节点中保存了指向下一个节点的指针;双向链表则可以反向遍历,因为节点中既保存了向后节点的指针,又保存了向前节点的指针。由于链表结构相对简单,这里不再赘述,直接通过程序来查看它们常见的操作:

单链表

代码语言:javascript
复制
public class Link {
    public int data;
    public Link next;

    public Link(int data) {
        this.data = data;
        next = null;
    }

    public void displayLink() {
        System.out.print("[ " + data + " ]");
    }

}
代码语言:javascript
复制
public class LinkedList {
    //头节点
    private Link first;
    //链表中节点数量
    private int nElem;

    //添加头结点
    public void insertFirst(int value) {
        Link newLink = new Link(value);
        // newLink --> old first
        newLink.next = first;
        // first --> newLink
        first = newLink;
        nElem++;
    }

    //删除头结点
    public Link deleteFirst() {
        if (isEmpty()) {
            System.out.println("The Link is empty!");
            return null;
        }
        Link temp = first;
        first = first.next;
        nElem--;
        return temp;
    }

    /* 下面是有序链表的插入
    * 这样简单排序就可以用链表来实现,复杂度为O(n)
    * 定义一个方法,传入一个数组
    * 在方法内,遍历数组并调用insert方法就可以将数组中的数据排好序*/

    public void insert(int value) {
        Link newLink = new Link(value);
        Link current = first;
        Link previous = null;
        while (current != null && value > current.data) {
            previous = current;
            current = current.next;
        }
        if (previous == null) {
            first = newLink;
        } else {
            previous.next = newLink;
        }
        newLink.next = current.next;
        nElem++;
    }
    //查找特定节点
    public Link find(int value) {
        Link current = first;
        while (current.data != value) {
            if (current.next == null) {
                return null;
            }
            current = current.next;
        }
        return current;
    }
    //删除特定节点
    public Link delete(int value) {
        Link current = first;
        Link previous = first;
        while (current.data != value) {
            if (current.next == null) {
                return null;
            }
            previous = current;
            current = current.next;
        }
        if (current == first) {
            first.next = first;
        } else {
            previous.next = current.next;
        }
        nElem--;
        return current;
    }

    public void display() {
        if (isEmpty()) {
            System.out.println("The link is empty!");
            return;
        }
        Link current = first;
        while (current != null) {
            current.displayLink();
            current = current.next;
        }
        System.out.println(" ");
    }


    public boolean isEmpty() {
        return (first == null);
    }

    public int size() {
        return nElem;
    }

}

双向链表

代码语言:javascript
复制
public class Node {
    public long data;
    public Node previous;
    public Node next;

    public Node(long value) {
        this.data = value;
        previous = null;
        next = null;
    }

    public void display() {
        System.out.print("[" + data + "]");
    }
}
代码语言:javascript
复制
public class DoublyLinkedList {
    //头结点
    private Node first;
    //尾节点
    private Node last;
    private int size;

    public DoublyLinkedList() {
        first = null;
        last = null;
        size = 0;
    }

    //插入头结点
    public void insertFirst(long value) {
        Node newNode = new Node(value);
        if (isEmpty()) {
            first = newNode;
        } else {
            // newLink <-- oldFirst.previous
            first.previous = newNode;
            // newLink --> first
            newNode.next = first;
        }
        //first --> newLink
        first = newNode;
        size++;
    }

    //插入尾节点
    public void insertLast(long value) {
        Node newNode = new Node(value);
        if (isEmpty()) {
            last = newNode;
        } else {
            // newlink <-- oldLast.newxt
            last.next = newNode;
            // newLink.previous --> last
            newNode.previous = last;
        }
        last = newNode;
        size++;
    }

    //删除头结点
    public Node deleteFirst() {
        Node temp = first;
        if (isEmpty()) {
            System.out.println("The link is Empty!");
            return null;
        }
        //只有一个节点
        if (first.next == null) {
            last = null;
        } else {
            first.next.previous = null;
        }
        first = first.next;
        size--;
        return temp;
    }

    //删除尾节点
    public Node deleteLast() {
        Node temp = last;
        if (isEmpty()) {
            System.out.println("The link is empty!");
            return null;
        }
        //只有一个节点
        if (last.previous == null) {
            first = null;

        } else {
            last.previous.next = null;
        }
        last = last.previous;
        size--;
        return temp;
    }

    public boolean insertAfter(long key, long value) {
        Node current = first;
        while (current.data != key) {
            current = current.next;
            if (current == null) {
                return false;
            }
        }
        if (current == last) {
            insertLast(value);
        } else {
            Node newNode = new Node(value);
            newNode.next = current.next;
            current.next.previous = newNode;
            newNode.previous = current;
            current.next = newNode;
            size++;
        }
        return true;
    }

    public Node deleteNode(long value) {
        Node current = first;
        while (current.data != value) {
            current = current.next;
            if (current == null) {
                return null;
            }
        }
        if (current == first) {
            deleteFirst();
        } else if (current == last) {
            deleteLast();
        } else {
            current.previous.next = current.next;
            current.next.previous = current.previous;
            size--;
        }
        return current;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return (first == null);
    }
    //从头到尾遍历链表
    public void displayForward() {
        Node current = first;
        while (current != null) {
            current.display();
            current = current.next;
        }
        System.out.println();
    }
    //从未到头遍历链表
    public void displayBackward() {
        Node current = last;
        while (current != null) {
            current.display();
            current = current.previous;
        }
        System.out.println();
    }
}

  在表头插入和删除速度很快,仅需改变一两个引用值,所以花费 O(1) 的时间。平均起来,查找、删除和在指定节点后面插入都需要搜索链表中的一半节点,需要O(N)次比较。在数组中执行这些操作也需要 O(N) 次比较,但是链表仍然要比数组快一些,因为当插入和删除节点时,链表不需要移动任何东西,增加的效率是很显著的,特别是当复制时间远远大于比较时间的时候。

  当然,链表比数组优越的另一个重要方面是链表需要多少内存就可以用多少内存并且可以扩展到所有可用内存。数组的大小在它创建的时候就固定了,所以经常由于数组太大导致效率低下,或者数组太小导致空间溢出。可变数组可以解决这个问题,但是它经常只允许以固定大小的增量扩展,这个解决方案在内存使用率上来说还是比链表要低。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-02-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单链表
  • 双向链表
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档