单链表

一、单链表

单链表是一种链式存储结构,即物理存储单元上是非连续、非顺序性的,数据元素的逻辑是通过链表中的指针实现的,链表由一系列的结点组成,结点的构成包括一个数据域和指针域,指针域存放后继结点的存储地址,结点可以在运行时动态生成。

  • 首先定义单链表,用内部类来实现Entry结点类的创建

为了体现Java语言的封装性,将其基本属性均设置为私有,可以通过相应get()方法返回需要的属性值;

class Link<T> {
    class Entry<T> { //定义结点类
        private T data;
        private Entry<T> next;

        public Entry() { //构造函数(头节点)
            this.data = null;
            this.next = null;
        }

        public Entry(T value) { //构造函数(数据节点)
            this.data = value;
            this.next = null;
        }
        //得到结点数据
        public T getData() {
            return this.data;
        }
    }

    private int size; //链表长度
    private Entry<T> head; //头节点

    public Link() {
        this.head = new Entry<>();
    }
}

然后实现单链表相关的方法

1、某些方法涉及到传入位置参数,要对其参数进行基本的合法性校验

判断索引合法性

    //判断索引合法性
    public boolean checkRange(int index) {
        if (index < 0 || index > getSize() ) {
            //throw new RuntimeException("非法参数");
            return false;
        }
        return true;
    }

2、头插法

注意:

  • 应该保证能找到后面的数据结点,先使待插入结点(entry)的指针域保存头结点(head)后面的数据节点的地址,然后再让头结点指向待插入结点,size++;
  • 不能直接让head.next指向entry,这样会使后面的数据节点全部丢失!

在这里插入图片描述

    //添加元素:头插法
    public void insertHead(T value) {
        Entry<T> entry = new Entry<>(value);
        entry.next = this.head.next;
        this.head.next = entry;
        size++;
    }

3、尾插法

注意:

  • 首先要使当前结点cursor遍历到尾结点;
  • 再使尾结点指向待插入结点,size++;
    在这里插入图片描述
    //添加元素:尾插法
    public void insertTail(T value) {
        Entry<T> entry = new Entry<>(value);
        Entry<T> cursor = this.head;
        while (cursor.next != null) { //遍历到尾结点
            cursor = cursor.next;
        }
        cursor.next = entry;
        size++;
    }

4、任意位置插入

注意:

  • 判断插入位置的合法性;
  • 若pos参数合法,先使cursor遍历到插入位置的前一个结点,然后再将entry插入进来,size++;
  • 类似于头插法,先让entry指向cursor.next,然后让cursor指向entry;
    在这里插入图片描述
    //任意位置插入元素
    public void insertPos(int pos,T value) {
        if (!checkRange(pos)) {
            return;
        }
        int count = 0;
        Entry<T> cursor = this.head;
        while (count < pos-1) {
            count++;
            cursor = cursor.next;
        }
        Entry<T> entry = new Entry<>(value);
        entry.next = cursor.next;
        cursor.next = entry;
        size++;

    }

5、删除值为value的结点(只删除第一个匹配到的结点)

注意:

  • 定义cursor遍历链表,定义previous为cursor的前驱结点;若cursor.data不等于value,则cursor = cur.next,previous = previous.next;
  • 当cursor.data == value时,说明cursor是需要删除的结点;
  • 让previous指向cursor的下一个结点,即完成了cursor结点的删除,size- -;

在这里插入图片描述

    public boolean remove(T value) {
        Entry<T> previous = this.head;
        Entry<T> cursor = this.head.next;
        while (cursor != null) {
            if (cursor.data != value) {
                previous = previous.next;
                cursor = cursor.next;
            } else {
                previous.next = cursor.next;
                size--;
                return true;
            }
        }
        return false;
    }

6、删除任意位置结点

注意:

  • 对pos参数进行合法性校验;
  • 若pos合法,让cursor遍历到pos的前一个结点;
  • 让cursor指向pos位置的下一个结点,即cursor.next = cursor.next.next,size- -;

在这里插入图片描述

       //删除指定位置结点
    public boolean remove(int pos) {
        if (checkRange(pos)) {
            int count = 0;
            Entry<T> cursor = this.head;
            while (count < pos-1) {
                cursor = cursor.next;
                count++;
            }
            cursor.next = cursor.next.next;
            size--;
            return true;
        }
        return false;
    }

7、得到链表长度

  • 可以通过返回size的值来获取链表长度;
    //得到链表长度
    public int getSize() {
        return this.size;
    }
  • 若没有定义size属性,也可以通过遍历链表获得链表长度;
    public int getLength() {
        Entry<T> cursor = this.head.next;
        int count = 0;
        while (cursor != null) {
            count++;
            cursor = cursor.next;
        }
        return count;
    }

8、打印链表元素

  • 写一个show()方法打印链表元素
    //打印链表所有数据
    public void show() {
        Entry<T> cursor = this.head.next;
        while (cursor != null) {
            System.out.print(cursor.data + " ");
            cursor = cursor.next;
        }
        System.out.println();
    }

  • 重写toString()方法
	@Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        Entry<T> cursor = this.head.next;
        while (cursor != null) {
            buffer.append(cursor.getData() + " ");
            cursor = cursor.next;
        }
        return buffer.toString();
    }

在写面试题的时候经常会碰到链表相关的题目,这里整理一些典型的例题,点击单链表相关面试真题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值