数据结构之单链表

1. 什么是线性表

  1. 线性表是最常用,最简单,也是一种最基本的数据结构。
  2. 线性表在计算机中可以使用顺序储存与链式储存两种存储结构来实现。

顺序表:顺序存储结构表示的线性表为顺序表
链表:链表是采用链式存储结构实现的,其中链表又有单链表双向链表循环链表之分。

2. 顺序表的局限

  1. 若要为顺序表扩容,则需要分配一个地址连续且更大的存储空间,并把原来所有的数据元素一并拷贝到新的存储空间中。如果数据量大则会非常耗时
  2. 因为顺序表要求逻辑上相邻的元素物理地址必须是相邻的,这就使得增删数据元素会引起一半的数据元素移动。

顺序表适用于“静态”线性表,即线性表形成后,就很少进行插入与删除操作
对于需要频繁执行插入与删除操作的”动态“线性表,通常采用链式存储结构。


3. 什么是链表

链式存储方式不需要逻辑上相邻的元素在物理上也相邻,它是一组地址任意的存储单元来存放数据元素的值。因此,链式存储结构没有顺序结构存储的局限性,但却失去了可随机读写的特点,在链式存储上只能顺序读取

4. 单链表

采用链式存储结构的线性表称为链表,链表的每个节点存放数据元素的数据和存放指向逻辑上相邻节点的指针。若一个节点中只包含一个指针,则该链表被称为单链表

5. 单链表概念图

在这里插入图片描述

  1. 头指针:第一个元素的存储地址
  2. 头节点:为了操作方便,头节点不存放数据,指针指向第一个节点
  3. 首节点:第一个节点
  4. 尾节点:链表中最后的一个节点

6. 单链表实现

6.1 节点类

由于链表是由多个节点连接组成的。因此需要先设计节点类

// setter getter ... 略
public class Node<T> {
    private T data;
    private Node<T> next;
}

6.2 链表

为了规范,习惯性定义一个接口并实现

public interface IList<T> {
    void add(T value);

    void remove(int i);

    T get(int i);

    void insert(int i, T value);

    int indexOf(T value);

    int length();

    void clear();

    boolean isEmpty();
}

6.3 实现链表

public class LinkList<T> implements IList<T> {

    private Node<T> headNode;

    private Node<T> lastNode;

    private int length;

    public LinkList() {
        this.headNode = new Node<>();
        this.lastNode = this.headNode;
    }

    @Override
    public void add(T value) {
        Node<T> nextNode = new Node<>(value);
        lastNode.setNext(nextNode);
        this.lastNode = nextNode;
        this.length++;
    }

    @Override
    public void remove(int i) {
        if (i < 0 || i >= this.length) {
            throw new IndexOutOfBoundsException();
        }

        int count = 0;
        Node<T> parent = this.headNode;
        while (count++ < i) {
            parent = parent.getNext();
        }
        parent.setNext(parent.getNext().getNext());

        this.length--;
    }

    @Override
    public T get(int i) {
        if (i < 0 || i >= this.length) {
            throw new IndexOutOfBoundsException();
        }
        int count = 0;
        Node<T> tmp = this.headNode;
        while ((tmp = tmp.getNext()) != null && count++ < i) ;
        return tmp.getData();
    }

    @Override
    public void insert(int i, T value) {
        if (i < 0 || i >= this.length) {
            throw new IndexOutOfBoundsException();
        }

        Node<T> node = new Node<>(value);

        Node<T> tmp = this.headNode;
        for (int j = 0; j < i; j++) {
            tmp = tmp.getNext();
        }
        node.setNext(tmp.getNext());
        tmp.setNext(node);

        this.length++;
    }

    @Override
    public int indexOf(T value) {
        Node<T> tmp = this.headNode;
        int index = -1;
        while ((tmp = tmp.getNext()) != null) {
            if (tmp.getData().equals(value)) {
                return ++index;
            }
            index++;
        }
        return -1;
    }

    @Override
    public int length() {
        return this.length;
    }

    @Override
    public void clear() {
        this.headNode = new Node<>();
        this.lastNode = this.headNode;
        this.length = 0;
    }

    @Override
    public boolean isEmpty() {
        return this.length == 0;
    }
}

6.4 测试链表

测试依赖:junit

public class LinkListTest {

    private final LinkList<Integer> linkList = new LinkList<>();

    @Before
    public void fill() {
        linkList.add(1);
        linkList.add(2);
        linkList.add(3);
        linkList.add(4);
        linkList.add(5);
    }

    @After
    public void show() {
        for (int i = 0; i < linkList.length(); i++) {
            System.out.printf("i = %d value = %s %n", i, linkList.get(i));
        }
    }

    @Test
    public void remove() {
        linkList.remove(0);
        linkList.remove(1);
    }

    @Test
    public void get() {
        System.out.println(linkList.get(1));
    }

    @Test
    public void isEmpty() {
        System.out.println(linkList.isEmpty());
    }

    @Test
    public void indexOf() {
        System.out.println(linkList.indexOf(2));
    }

    @Test
    public void insert() {
        linkList.insert(1, 99);
        linkList.insert(0, 100);
    }

    @Test
    public void clear() {
        linkList.clear();
    }

    @Test
    public void length() {
        System.out.println(linkList.length());
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值