Java实现数据结构---链表

链表定义

链表(Linked list)是一种在物理上不连续、非顺序的数据结构,由若干个节点(Node)组成。链表中元素的逻辑顺序是通过链表中的指针链接次序实现的。
主要具有以下特点:

  • 相邻两个数据元素之间有指针连接
  • 最后一个元素的后续指针为NULL(双端链表,循环链表除外)。
  • 链表与数组比较相比较,链表的空间能够按需分配,没有内存空间的浪费(但是元素间相连接的指针需要一些额外的开销)。
  • 链表中会有至少两个部分:数据项,以及引用指针
  • 链表可以在常数时间内扩展(时间复杂度O(1))。
  • 链表在访问某个元素时开销比较大(时间复杂度O(N))。

存储原理

链表在内存中的存储方式是随机存储(链式存储)的, 链表的每一个节点分布在内存的不同位置, 依靠next指针关联起来。
在这里插入图片描述

单向链表

单向链表包含多个结点,每个结点有一个指向后续元素的next指针,表中的最后一个结点的next指针值为NULL,标识链表的结束。具体模型如下:
在这里插入图片描述
单项链表的结点类:

package com.xxliao.datastructure.linerar_list.linked_list.single;

/**
 * @author xxliao
 * @description: 单向链表节点类
 * @date 2024/5/28 12:31
 */
public class Node {
    
    //存储数据
    private Object data;

    //下个节点
    public Node next;

    //构造
    public Node(Object data) {
        this.data = data;
    }

    //toString查看输出
    public String toString() {
        return "Node [data=" + data + ", next=" + next + "]";
    }
}

单向链表实现:

package com.xxliao.datastructure.linerar_list.linked_list.single;

/**
 * @author xxliao
 * @description: 单向链表
 * @date 2024/5/28 12:32
 */

public class SingleLinkedList {

    //表头结点
    private Node head;

    //链表长度
    private int size;

    //构造,使表头节点为null
    public SingleLinkedList() {
        head = null;
        size = 0;
    }

    //是否为空,判断表头是否为空
    public boolean isEmpty() {
        return head == null;
    }

    //在开始位置添加
    public void addFirst(Object data) {
        //创建新节点
        Node addNode = new Node(data);
        //使新节点的next指向链表的表头
        addNode.next = head;
        //表头指向新节点
        head = addNode;
        //长度加1
        size++;
    }

    //从表头开始删除
    public Object deleteFirst() {
        Node temp = head;
        head = head.next;
        size--;
        return temp.data;
    }

    //在末尾位置添加
    public void addLast(Object data) {
        //创建新节点
        Node addNode = new Node(data);
        //当前节点
        Node current = head;
        //循环找出最末节点
        while(current.next != null) {
            current = current.next;
        }
        //最末节点指向新节点
        current.next = addNode;
        size++;
    }

    //查看链表的所有元素
    public void display() {
        //当前节点
        Node current = head;
        //循环找出最末节点
        while(current.next != null) {
            System.out.println(current.toString());
            current = current.next;
        }
    }

    //判断某元素是否在链表中
    public boolean contain(Object data) {
        //当前节点
        Node current = head;
        if(data == null) {
            //循环找出最末节点
            while(current.next != null) {
                if(current.data == null) {
                    return true;
                }
                current = current.next;
            }
        }else {
            //循环找出最末节点
            while(current.next != null) {
                if(data.equals(current.data)) {
                    return true;
                }
                current = current.next;
            }
        }
        return false;
    }

    //删除链表中的某元素
    public Object delete(Object data) {
        //当前节点
        Node current = head;
        //前一个节点
        Node pred = head;
        if(data == null) {
            //循环找出最末节点
            while(current.data != null) {
                if(current.next == null) {
                    return null;
                }
                pred = current;
                current = current.next;
            }
        }else {
            //循环找出最末节点
            while(!data.equals(current.data)) {
                if(current.next == null) {
                    return null;
                }
                pred = current;
                current = current.next;
            }
        }

        if(current == head) {
            deleteFirst();
        }else {
            pred.next = current.next;
        }
        size--;
        return current.data;
    }
}

双端链表

双端链表在单向链表的实现上多了一个成员变量(last)记录表尾节点,因此双端链表的特点是可以快速的找到表头表尾,在尾部插入以及删除元素时效率将会有很大的提高。双端链表模型如下:
在这里插入图片描述
双端链表节点类:

	 package com.xxliao.datastructure.linerar_list.linked_list.doubly_end;

/**
 * @author xxliao
 * @description: 双端链表节点类
 * @date 2024/5/28 12:46
 */
public class Node {

    //存储数据
    public Object data;

    //下个节点
    public Node next;

    //构造
    public Node(Object data) {
        this.data = data;
    }

    //toString查看输出
    public String toString() {
        return "Node [data=" + data + ", next=" + next + "]";
    }
}

双端链表实现:

	package com.xxliao.datastructure.linerar_list.linked_list.doubly_end;

/**
 * @author xxliao
 * @description: 双端链表实现类
 * @date 2024/5/28 12:47
 */

public class DoublyEndLinkedList {

    //表头节点
    private Node head;
    //表尾节点
    private Node tail;
    //链表长度
    private int size;

    //构造,使表头节点为null
    public DoublyEndLinkedList() {
        head = null;
        tail = null;
        size = 0;
    }

    //是否为空,判断表头是否为空
    public boolean isEmpty() {
        return head == null;
    }

    //在开始位置添加
    public void addFirst(Object data) {
        //创建新节点
        Node addNode = new Node(data);
        //使新节点的next指向链表的表头
        addNode.next = head;
        //表头指向新节点
        head = addNode;
        //长度加1
        size++;
    }

    //从表头开始删除
    public Object deleteFirst() {
        if(isEmpty()) {
            return null;
        }
        Node temp = head;
        head = head.next;
        size--;
        return temp.data;
    }

    //在末尾位置添加
    public void addLast(Object data) {
        Node addNode = new Node(data);
        if(isEmpty()) {
            //空链表,first,last均为addNode
            head = addNode;
        }else {
            tail.next = addNode;
        }
        //最末节点指向新节点
        tail = addNode;
        size++;
    }

    //查看链表的所有元素
    public void display() {
        //当前节点
        Node current = head;
        //循环找出最末节点
        while(current.next != null) {
            System.out.println(current.toString());
            current = current.next;
        }
    }

    //判断某元素是否在链表中
    public boolean contain(Object data) {
        //当前节点
        Node current = head;
        if(data == null) {
            //循环找出最末节点
            while(current.next != null) {
                if(current.data == null) {
                    return true;
                }
                current = current.next;
            }
        }else {
            //循环找出最末节点
            while(current.next != null) {
                if(data.equals(current.data)) {
                    return true;
                }
                current = current.next;
            }
        }
        return false;
    }
}

双向链表

双向链表的每个节点均有一个前驱节点记录指向上一节点,有一个后驱节点指向下一节点,表尾节点后驱节点为NULL。因为双向链表节点间相互指引,那么在查找过程中可以双向遍历。
在这里插入图片描述
Java代码,链表节点声明如下:

package com.xxliao.datastructure.linerar_list.linked_list.doubly;

/**
 * @author xxliao
 * @description: 双向链表的节点类实现
 * @date 2024/5/28 12:54
 */

public class Node {
    //数据
    public Object data;
    //前驱结点
    public Node pre;
    //后驱结点
    public Node next;

    //构造方法
    public Node(Object data) {
        this.data = data;
    }

    //toString
    @Override
    public String toString() {
        return "DLLNode [data=" + data + ", pre=" + pre + ", next=" + next + "]";
    }
}

Java代码,双向链表(这里采用双向双端链表)的实现如下:

	package com.xxliao.datastructure.linerar_list.linked_list.doubly;

/**
 * @author xxliao
 * @description: 双向双端链表的实现类
 * @date 2024/5/28 12:55
 */

public class DoublyLinkedList {
    // 表头节点
    private Node head;
    // 表尾节点
    private Node tail;
    // 链表长度
    private int size;

    // 构造方法,使表头、表尾节点为null
    public DoublyLinkedList() {
        head = null;
        tail = null;
        size = 0;
    }

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

    // 从表头添加
    public void addFirst(Object data) {
        Node newNode = new Node(data);
        if (isEmpty()) {
            // 空链表,表头表尾都是新结点
            tail = newNode;
        } else {
            // 不是空链表,将新结点添加在first的前驱结点上
            head.pre = newNode;
        }
        // 新结点的后驱结点指向原来的first结点(原来链表表头),双向指定
        newNode.next = head;
        // 新结点作为表头节点
        head = newNode;
        size++;
    }

    // 从表头删除
    public Object deleteFirst() {
        Node deleteNode = head;
        if (head.next == null) {
            // 只有一个元素,last置为null
            tail = null;
        } else {
            // 将原表头结点的后驱结点(将作为新的表头结点)的前驱结点置为null,
            head.next.pre = null;
        }
        head = head.next;
        size--;
        return deleteNode.data;
    }

    // 从表尾添加
    public void addLast(Object data) {
        Node newNode = new Node(data);
        if (isEmpty()) {
            // 空链表,表头表尾都是新结点
            head = newNode;
        } else {
            // 不是空链表,将新结点添加在last的后驱结点上
            tail.next = newNode;
        }
        // 新结点的前驱结点指向原来的last结点(原来链表表尾)
        newNode.pre = tail;
        // 新结点作为表尾节点
        tail = newNode;
        size++;
    }

    // 从表尾删除
    public Object deleteLast() {
        Node deleteNode = tail;
        if (head.next == null) {
            // 只有一个元素,first置为null
            head = null;
        } else {
            // 将原表尾结点的前驱结点(将作为新的表尾结点)的后驱结点置为null,
            tail.pre.next = null;
        }
        tail = tail.pre;
        size--;
        return deleteNode.data;
    }

    // 添加在某元素后面
    public boolean addAfter(Object d, Object data) {
        // 当前节点
        Node current = head;
        while (!d.equals(current.data)) {
            // 不相等,继续查找
            if (current.next == null) {
                // 没有找到
                return false;
            }
        }
        Node newNode = new Node(data);
        if (current == tail) {
            // 表尾添加
            addLast(data);
        } else {
            // 中间添加
            newNode.next = current.next;
            current.next.pre = newNode;
        }
        current.next = newNode;
        newNode.pre = current;
        size++;
        return true;
    }

    //判断链表是否包含某元素
    public boolean contain(Object data) {
        //当前节点
        Node current = head;
        if(data == null) {
            // 遍历,查找是否有元素相同存在
            while(current.next != null) {
                if(current.data == null) {
                    return true;
                }
            }
        }else {
            // 遍历,查找是否有元素相同存在
            while(current.next != null) {
                if(data.equals(current.data)) {
                    return true;
                }
            }
        }
        return false;
    }
}

完整代码

https://github.com/xxliao100/datastructure_algorithms.git

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑车上酒吧

帮到了您,有闲钱,再打赏哦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值