文章目录

  • 前言
  • 一、什么是链表?
  • 二、代码实现
  • 总结



前言

链表是数据结构中十分简单的一种,一般有单向链表,双向链表,循环链表等,今天就使用节点来实现一个简单的单项链表类。
在下一期会实现双向链表以及循环链表的数据结构。


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是链表?

单向链表是一种线性表,实际上是由节点(Node)组成的,一个链表拥有不定数量的节点。其数据在内存中存储是不连续的,它存储的数据分散在内存中,每个结点只能也只有它能知道下一个结点的存储位置。由N各节点(Node)组成单向链表,每一个Node记录本Node的数据及下一个Node。向外暴露的只有一个头节点(Head),我们对链表的所有操作,都是直接或者间接地通过其头节点来进行的。链表在进行循环遍历时效率不高,但是插入和删除时优势明显。下图是原理图:

java 简单的单向链表 java单向链表有哪些_单向链表


上图中最左边的节点即为头结点(Head),但是添加节点的顺序是从右向左的,添加的新节点会被作为新节点。最先添加的节点对下一节点的引用可以为空。引用是引用下一个节点而非下一个节点的对象。因为有着不断的引用,所以头节点就可以操作所有节点了。

下图描述了单向链表存储情况。存储是分散的,每一个节点只要记录下一节点,就把所有数据串了起来,形成了一个单向链表

java 简单的单向链表 java单向链表有哪些_链表_02


节点(Node)是由一个需要储存的对象及对下一个节点的引用组成的。也就是说,节点拥有两个成员:储存的对象、对下一个节点的引用。下面图是具体的说明:

java 简单的单向链表 java单向链表有哪些_java 简单的单向链表_03

二、代码实现

首先新建一个节点类,设置存储数值的单元和存储下一个节点位置的单元:

public class Node {
	Object data;//存储节点数据
    Node next;//指向下一节点
}

设置一个接口,用来存放单项链表里的添加删除等抽象功能:

public interface Linkedfunction {

    public Node get(int p);

    public void Insert(int p, Object data);

    public void delete(int p);

    public void clean();

    public int size();

}

接着使用一个类来继承接口,并重写接口内的抽象方法。

public class SingleLinked implements Linkedfunction {
    private Node head;// 头节点
    private int length;// 链表长度
    /*
     * 初始化链表
     */

    public SingleLinked() {
        head = null;
        length = 0;
    }

    /*
     * 清空链表
     */
    public void clean() {
        head = null;
        length = 0;
    }

    /*
     * 获取链表第p个节点
     */
    public Node get(int p) {
        Node current = head;
        if (p > 0 && p <= length) {
            for (int i = 0; i < p - 1; i++) {
                current = current.next;
            }
            return current;
        }
        return null;

    }

    /*
     * 插入节点头插法
     */
    public void headInsert(Object data) {
        Node n = new Node();
        n.data = data;
        n.next = head;
        head = n;
        length++;

    }

    /*
     * 插入节点在p节点
     */
    public void Insert(int p, Object data) {
        Node current = head;
        Node n = new Node();
        n.data = data;
        if (p > 0 && p <= length + 1) {

            for (int i = 0; i < p - 2; i++) {

                current = current.next;
            }

            n.next = current.next;
            current.next = n;
            length++;

        }

    }

    /*
     * 删除第p个节点
     */
    public void delete(int p) {
        Node current = head;

        // 遍历链表直到p节点的前一节点
        if (p > 0 && p <= length) {
            if (p == 1) {// 若删除的是头节点
                head = current.next;
                length--;
                return;
            } else {
                for (int i = 1; i <= p; i++) {

                    if (i == p - 1) {
                        current.next = current.next.next;
                        length--;
                    } else {
                        current = current.next;
                    }

                }
            }

        }
    }

    /*
     * 打印链表
     */
    public void print() {
        Node current = head;
        for (int i = 0; i < length-1; i++) {
            System.out.print(current.data + "->");
            current = current.next;
        }
        System.out.print(current.data);
        System.out.println();
    }

    @Override
    public int size() {

        return this.length;
    }

}

最后新建一个test类,用来测试一下所写的单向链表的各个功能是否可以完美呈现。

public class test {
	public static void main(String[] args) {
        SingleLinked sl = new SingleLinked();
        System.out.println("实例化一个列表");
        sl.headInsert("a1");
        sl.headInsert("a2");
        sl.headInsert("a3");
        sl.headInsert("a4");
        sl.print();
        System.out.println("删除第四项");
        sl.delete(4);
        sl.print();
        System.out.println("输出第三项");
        System.out.println(sl.get(3).data);
        System.out.println("在第四项插入新元素");
        sl.Insert(4, "a5");
        sl.print();
        System.out.println("在第二项插入新元素");
        sl.Insert(2, "a6");
        sl.print();

    }
}

运行结果如下:

java 简单的单向链表 java单向链表有哪些_单向链表_04


总结


原理:
此次实现的链表为单向链表,插入新数据的方法为头插法。链表存储是在程序运行过程中动态分配空间,相邻元素可以随意存放。所占内存空间分为两部分,一部分存储结点值,另一部分存放下一个节点的地址。
优点
1)插入和删除速度快,只需要改变当前节点存储的下一个结点的位置就行。
2)没有空间限制,存储元素的个数无上限,基本只与内存空间大小有关。
缺点
1)存取某个元素速度慢。
2)占用额外的空间来存储下一个结点的位置,不连续存放,浪费空间,空间碎片多。
3)查找速度慢。因为查找某个元素的时候,需要遍历链表,一个一个去查找。
时间复杂度:查找:O(n),插入/删除:O(1)