《java数据结构》--链表

本文深入探讨了Java中链表的基本概念及其多种类型,包括单向链表、双端链表、有序链表和双向链表的实现。文章详细介绍了每种链表的特点、应用场景以及在Java中的具体实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java数据结构

参考:数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现

主要有以下几种类型

  • 单向链表
  • 双端链表
  • 有序链表
  • 双向链表
  • 有迭代器的链表

链表的效率

这里顺便谈下链表和数组相比效率的优越性.在表头插入和删除的速度都很快,因为只需要改变一下引用所以花费O(1)的时间.

平均起来查找,删除和在指定节点后插入数据都需要搜索一半的链结点.需要O(N)次比较和数组一样.然由于链表删除插入的时候

不需要像数组那种元素的移动.所以效率还是要优于数组.

还有一点就是链表的内存可以随时的扩展内存.而数组的内存是一开始就固定好的.这样就会导致数组的效率和可用性大大下降.

链表劣势在于随机访问,无法像数组那样直接通过下标找到特定的数据项 

java代码实现

单向链表

image

package cn.zlz.structure;

/**
 * 单向链表 持有一个首部节点,可以实现栈,后进先出
 */
public class LinkedList<V> {

    // 链表头部
    private Node first;
    // 长度
    private int size;

    public LinkedList() {
        super();
    }

    // 首部插入新的节点
    public Node<V> insertFirst(V value) {
        Node<V> node = new Node<V>(value);
        // 新节点的next指向老节点
        node.setNext(first);
        first = node;
        // 长度+1
        size++;
        return node;
    }

    // 获取指定位置节点
    public Node<V> get(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("链表为空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node node = first;
        while (index-- > 0) {
            node = node.getNext();
        }
        return node;
    }

    // 删除指定位置节点
    public Node<V> remove(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("链表为空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        // 待删除节点
        Node<V> removeNode = null;
        // 待删除节点的上个节点
        Node<V> pre = null;
        if (index == 0) {
            // 没有上个节点
            pre = null;
            removeNode = first;
            first = removeNode.next;
        } else {
            pre = this.get(index - 1);
            // 已通过长度验证pre.next存在
            removeNode = pre.next;
            pre.next = removeNode.next;
        }
        if (--size <= 0) {
            first = null;
        }
        return removeNode;
    }

    // 判断linkList是否为空
    public boolean isEmpty() {
        return first == null;
    }

    // 获取链表长度
    public int getSize() {
        return size;
    }

    @Override
    public String toString() {
        if (first == null) {
            return "LinkedList ";
        }
        return "LinkedList [" + first.toString() + "]";
    }

    // 节点类
    class Node<V> {
        private V value;
        private Node next;

        public Node() {
            super();
        }

        public Node(V value) {
            super();
            this.value = value;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node [value=" + value + ", next=" + next + "]";
        }

    }

    // 测试
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<String>();
        linkedList.insertFirst("a");
        linkedList.insertFirst("b");
        linkedList.insertFirst("c");
        linkedList.insertFirst("d");
        linkedList.insertFirst("e");
        linkedList.insertFirst("f");
        System.out.println(linkedList.toString());
        LinkedList<String>.Node<String> node = linkedList.get(2);
        System.out.println(node.getValue());
        LinkedList<String>.Node<String> removeNode = linkedList.remove(0);
        System.out.println(linkedList.toString());
        System.out.println(node.getValue());

    }
}

双端单向链表

image

package cn.zlz.structure;

/**
 * 双端单向链表 持有一个首部节点引用和尾部节点引用,可以实现队列,先进先出
 * 
 * 双端链表与传统链表非常相似.只是新增了一个属性-即对最后一个链结点的引用,单向链表只能从首部开始操作,双端链表首尾都可以
 */
public class DbPortLinkedList<V> {

    // 链表头部
    private Node first;
    // 链表尾部
    private Node last;
    // 长度
    private int size;

    public DbPortLinkedList() {
        super();
    }

    // 首部添加新的节点
    public Node<V> insertFirst(V value) {
        Node<V> node = new Node<V>(value);
        // 新节点的next指向老节点
        if (this.isEmpty()) {
            last = node;
        }
        node.setNext(first);
        first = node;
        // 长度+1
        size++;
        return node;
    }

    // 尾部添加新的节点
    public Node<V> insertLast(V value) {
        Node<V> node = new Node<V>(value);
        // 新节点的next指向老节点
        if (this.isEmpty()) {
            first = node;
            last = node;
            return node;
        }
        last.setNext(node);
        last = node;
        // 长度+1
        size++;
        return node;
    }

    // 获取指定位置节点
    public Node<V> get(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("链表为空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node node = first;
        while (index-- > 0) {
            node = node.getNext();
        }
        return node;
    }

    // 删除指定位置节点
    public Node<V> remove(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("链表为空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        // 待删除节点
        Node<V> removeNode = null;
        // 待删除节点的上个节点
        Node<V> pre = null;
        if (index == 0) {
            // 没有上个节点
            pre = null;
            removeNode = first;
            first = removeNode.next;
        } else {
            pre = this.get(index - 1);
            // 已通过长度验证pre.next存在
            removeNode = pre.next;
            pre.next = removeNode.next;
        }
        // 长度-1,并验证链表是否为空
        if (--size <= 0) {
            first = null;
            last = null;
        }
        return removeNode;
    }

    // 判断linkList是否为空
    public boolean isEmpty() {
        return first == null && last == null;
    }

    // 获取链表长度
    public int getSize() {
        return size;
    }

    @Override
    public String toString() {
        if (first == null) {
            return "DbPortLinkedList ";
        }
        return "DbPortLinkedList [" + first.toString() + "]";
    }

    // 节点类
    class Node<V> {
        private V value;
        private Node next;

        public Node() {
            super();
        }

        public Node(V value) {
            super();
            this.value = value;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node [value=" + value + ", next=" + next + "]";
        }

    }

    // 测试
    public static void main(String[] args) {
        DbPortLinkedList<String> dbPortLinkedList = new DbPortLinkedList<String>();
        dbPortLinkedList.insertFirst("a");
        dbPortLinkedList.insertFirst("b");
        dbPortLinkedList.insertLast("c");
        dbPortLinkedList.insertFirst("d");
        dbPortLinkedList.insertLast("e");
        dbPortLinkedList.insertFirst("f");
        System.out.println(dbPortLinkedList.toString());
        DbPortLinkedList<String>.Node<String> node = dbPortLinkedList.get(2);
        System.out.println(node.getValue());
        DbPortLinkedList<String>.Node<String> removeNode = dbPortLinkedList.remove(0);
        System.out.println(dbPortLinkedList.toString());
        System.out.println(removeNode.getValue());

    }
}

有序链表

package cn.zlz.structure;

/**
 * 有序单向链表:链表中的数据按从小到大排列 持有一个首部节点
 * 有序链表插入数据效率为O(N),但查找跟删除最大数据就是表头数据效率为O(1).所以在最小数据存储频繁,但又不需要快速插入的时候有序链表是个不错的选择.
 */
public class SortedLinkedList {

    // 链表头部
    private Node first;
    // 长度
    private int size;

    public SortedLinkedList() {
        super();
    }

    // 首部插入新的节点
    public Node insertFirst(Integer value) {
        Node node = new Node(value);

        // 查找位置,即找到前面一个节点和后面一个节点
        Node pre = null;//插入位置前面节点
        Node current = first;//插入位置后面节点
        while (current != null && current.getValue()<value) {
            pre = current;
            current=current.next;
        }
        //最小的,插在第一个位置
        if(pre == null){
            first = node;
        }else{
            pre.next = node;
        }
        //新插入的节点不管怎么next都指向当前节点
        node.next = current;
        // 长度+1
        size++;
        return node;
    }

    // 获取指定位置节点
    public Node get(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("链表为空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node node = first;
        while (index-- > 0) {
            node = node.getNext();
        }
        return node;
    }

    // 删除指定位置节点
    public Node remove(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("链表为空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        // 待删除节点
        Node removeNode = null;
        // 待删除节点的上个节点
        Node pre = null;
        if (index == 0) {
            // 没有上个节点
            pre = null;
            removeNode = first;
            first = removeNode.next;
        } else {
            pre = this.get(index - 1);
            // 已通过长度验证pre.next存在
            removeNode = pre.next;
            pre.next = removeNode.next;
        }
        if (--size <= 0) {
            first = null;
        }
        return removeNode;
    }

    // 判断linkList是否为空
    public boolean isEmpty() {
        return first == null;
    }

    // 获取链表长度
    public int getSize() {
        return size;
    }

    @Override
    public String toString() {
        if (first == null) {
            return "SortedLinkedList ";
        }
        return "SortedLinkedList [" + first.toString() + "]";
    }

    // 节点类
    class Node {
        private int value;
        private Node next;

        public Node() {
            super();
        }

        public Node(int value) {
            super();
            this.value = value;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node [value=" + value + ", next=" + next + "]";
        }

    }

    // 测试
    public static void main(String[] args) {
        SortedLinkedList sortedLinkedList = new SortedLinkedList();
        sortedLinkedList.insertFirst(4);
        sortedLinkedList.insertFirst(2);
        sortedLinkedList.insertFirst(3);
        sortedLinkedList.insertFirst(5);
        System.out.println(sortedLinkedList);
    }
}

双向链表

image
image
image

package cn.zlz.structure;

/**
 * 双向链表,注意画图来看
 * 注意:双向链表需要初始化一个header头,但是这个header头不属于链表的一个元素
 */
public class DbLinkedList<V> {

    // 链表头部
    private Node header;
    // 长度
    private int size;

    public DbLinkedList() {
        super();
        //创建表头
        this.header = new Node(null, null, null);
        //表头自循环
        this.header.next = this.header;
        this.header.pre = this.header;
    }

    // 首部添加新的节点
    public Node<V> insert(int index,V value) {
        if (index > size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node<V> current = null ;
        if(size == 0){
            current = this.header;
        }else{
            current = get(index);
        }
        Node<V> node = new Node<V>(value,current.pre,current);
        node.pre.next = node;
        node.next.pre = node;
        // 长度+1
        size++;
        return node;
    }
    public Node<V> insertFirst(int index,V value) {
        return this.insert(0, value);
    }
    public Node<V> insertLast(int index,V value) {
        //面向对象
        Node<V> node = new Node<V>(value,this.header.pre,this.header);
        node.pre.next = node;
        node.next.pre = node;
        // 长度+1
        size++;
        return node;
    }
    // 首部添加新的节点
    //注意:双向链表中的元素不包括header
    public Node<V> get(int index) {
        if (size==0 || index > size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node<V> node = null;
        //如果是后半从后往前找
        if(index>(size)/2){
            System.out.println("从后往前找");
            //header不属于链表,所以z最后一个是插入中的一个。
            node = this.header.pre;
            int round = size-index;
            while (round-->=0) {
                node = node.pre;
            }
        }else{//从前往后找
            System.out.println("从前往后找");
            //header不属于链表,所以第一个是header的next,插入的时候对0单独处理了,执行get的时候至少已经插入一条
            node = this.header.next;
            while (index-->0) {
                node = node.next;
            }
        }
        return node;
    }

    public Node<V> remove(int index){
        if (size==0 || index > size-1) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node<V> toDelNode = this.get(index);
        toDelNode.pre.next = toDelNode.next;
        toDelNode.next.pre = toDelNode.pre;
        size--;
        return toDelNode;
    }

    // 获取链表长度
    public int getSize() {
        return size;
    }

    // 判断linkList是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    public Node getHeader() {
        return header;
    }

    public void setHeader(Node header) {
        this.header = header;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        Node header = this.getHeader();
        Node next = header.getNext();
        stringBuilder.append(header.getPre().getValue()+":"+header.getValue()+":"+header.getNext().getValue());
        while(next!=header){
            stringBuilder.append("   ");
            stringBuilder.append(next.getPre().getValue()+":"+next.getValue()+":"+next.getNext().getValue());
            next = next.next;
        }
        return stringBuilder.toString();
    }

    // 节点类
    class Node<V> {
        private V value;// 值
        private Node pre;// 前一个节点
        private Node next;// 后一个节点

        public Node() {
            super();
        }

        public Node(V value, Node pre, Node next) {
            super();
            this.value = value;
            this.pre = pre;
            this.next = next;
        }

        public Node(V value) {
            super();
            this.value = value;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }

        public Node getPre() {
            return pre;
        }

        public void setPre(Node pre) {
            this.pre = pre;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node [value=" + value + ", pre=" + pre + ", next=" + next + "]";
        }

    }

    // 测试
    public static void main(String[] args) {
        DbLinkedList<String> dbLinkedList = new DbLinkedList<String>();
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(0,"a");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(1,"b");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(2,"b");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(1,"c");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(4,"d");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(0,"e");
        System.out.println(dbLinkedList.toString());
        System.out.println(dbLinkedList.get(3).getValue());
//      dbLinkedList.insertFirst("f");
        System.out.println(dbLinkedList.toString());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值