Java实现单链表、多链表

写在前面

如果让你保存多个对象,你第一时间想到的肯定是数组,但是如果让你保存多个任意对象呢?这时我们会想到用Object型的数组来解决。
Object[] data = new Object[3];
但是数组是一个长度固定的线性结构,在实际开发中,不论我们的内容不足或过多,都有可能造成空间的浪费,所以我们可以使用一个链表来动态存储数据,就像火车车厢的设计,长度不固定,有多少数据就保存多少数据。

单链表:
class Node {
    //节点中数据
    private Object data;
    //指向下一个节点
    private Node next;

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

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Node getNext() {
        return next;
    }

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

public class SingleLinkedList {
    public static void main(String[] args) {
        Node head = new Node("火车头");
        Node first = new Node("1号车厢");
        Node second = new Node("2号车厢");
        Node last = new Node("火车尾");
        head.setNext(first);
        first.setNext(second);
        second.setNext(last);
        printLink(head);
    }

    public static void printLink(Node node) {
        if (node != null) {
            System.out.println(node.getData());
            node = node.getNext();
            printLink(node);
        }
    }
}

思考:链表和数组的区别

  • 数组是由下标索引和data组成,链表是由data和指向下一个节点的next组成
  • 数组静态分配内存,链表动态分配内存
  • 数组在内存中连续,链表不连续
  • 数组元素在栈区,链表元素在堆区
  • 数组随机访问性强(时间复杂度:O(1)),查找速度快,但是插入删除效率低(时间复杂度:O(n));
     链表插入删除速度快(时间复杂度:O(1)),但是不能随即查找(时间复杂度:O(n)),必须从第一个开始遍历,查找效率低。

在实际开发中,我们用的更多的是双向链表。那么双向链表与单向链表的区别又是啥呢?其实双向链表只是在查找前一个节点的时候进行了优化,时间复杂度变为了O(1)。

双向链表:

在单链表里,挂载在客户端实现,类比生活中坐火车,我们只是乘坐,而不需要把火车的车厢连在一起,那么如何解决呢?
在双向链表里有一个新的类Link:负责节点之间的动态挂载,Node负责节点内容的设置,真实保存内容,ILink表示如果Link类的结构发生了变化,就需要更改客户端代码,为了避免这种情况,就让用户直接使用ILink接口。
在这里插入图片描述

interface ILink {
    /**
     * 链表增加节点操作
     *
     * @param data 节点内容
     * @return
     */
    boolean add(Object data);

    /**
     * 删除指定内容节点
     *
     * @param data
     * @return
     */
    boolean remove(Object data);

    /**
     * 判断指定内容节点在链表中是否存在
     *
     * @param data 要判断的内容
     * @return 返回指定的索引
     */
    int contains(Object data);

    /**
     * 根据指定下标修改节点内容
     *
     * @param index   索引下标
     * @param newData 替换后的内容
     * @return 替换之前的内容
     */
    Object set(int index, Object newData);

    /**
     * 根据指定下标返回节点内容
     *
     * @param index
     * @return
     */
    Object get(int index);

    /**
     * 链表清空
     */
    void clear();

    /**
     * 将链表转为数组
     *
     * @return 返回所有节点内容
     */
    Object[] toArray();

    /**
     * 链表长度
     *
     * @return
     */
    int size();

    /**
     * 遍历链表
     */
    void printLink();
}

class LinkImpl implements ILink {

    private Node head;
    private Node last;
    private int size;

    /**
     * 用户并不知道Node类的存在,封装为内部类
     * 真正的火车车厢,负责数据存储
     * 内外部类随便访问私有属性
     */
    private class Node {
        private Node prev;
        private Object data;
        private Node next;

        public Node(Node prev, Object data, Node next) {
            this.prev = prev;
            this.data = data;
            this.next = next;
        }
    }

    public boolean add(Object data) {
        //尾插
        Node temp = this.last;
        Node newNode = new Node(temp, data, null);
        this.last = newNode;
        if (this.head == null) {
            this.head = newNode;
        } else {
            temp.next = newNode;
        }
        this.size++;
        return true;
    }

    public boolean remove(Object data) {
        if (data==null){
            for (Node temp=head;temp!=null;temp=temp.next){
                if(temp.data==null){
                    unLink(temp);
                    return true;
                }
            }
        }else {
            for (Node temp=head;temp!=null;temp=temp.next){
                if (temp.data.equals(data)){
                    unLink(temp);
                    return true;
                }
            }
        }
        return false;
    }

    public int contains(Object data) {
        //传进来的data可能为空,不能用equals()进行比较
        if (data==null){
            int i=0;
            for (Node temp=this.head;temp!=null;temp=temp.next){
                if (temp.data==null){
                    return i;
                }
                i++;
            }
        }else {
            int i=0;
            for (Node temp=this.head;temp!=null;temp=temp.next){
                if (temp.data.equals(data)){
                    return i;
                }
                i++;
            }
        }
        return -1;
    }

    public Object set(int index, Object newData) {
        if (!isLinkedIndex(index)){
            return null;
        }
        Node node = node(index);
        Object elementData = node.data;
        node.data=newData;
        return elementData;
    }

    public Object get(int index) {
        if(!isLinkedIndex(index)){
            return null;
        }
        return node(index).data;
    }

    public void clear() {
        for (Node temp = head; temp != null; ) {
            temp.data = null;
            Node node = temp.next;
            temp = temp.prev = temp.next = null;
            temp = node;
            this.size--;
        }
    }

    public Object[] toArray() {
        Object[] result = new Object[size];
        int i = 0;
        for (Node temp = head; temp != null; temp = temp.next) {
            result[i++] = temp.data;
        }
        return result;
    }

    public int size() {
        return this.size;
    }

    public void printLink() {
        Object[] data = this.toArray();
        for (Object temp : data) {
            System.out.println(temp);
        }
    }

    //根据指定索引取得具体的节点
    private Node node(int index) {
        //从前往后查找
        if(index<(size>>1)){
            Node temp = this.head;
            for(int i=0;i<index;i++){
                temp=temp.next;
            }
            return temp;
        }
        Node temp=this.last;
        for(int i=size-1;i>index;i--){
            temp=temp.prev;
        }
        return temp;
    }

    /**
     * 判断指定索引是否合法
     */
    private boolean isLinkedIndex(int index){
        return index>=0 && index<size;
    }

    /**
     * 删除节点
     */
    private Object unLink(Node x){
        Object elementData = x.data;
        Node prev = x.prev;
        Node next = x.next;
        if(prev==null){
            this.head=next;
        }else {
            prev.next=next;
            x.prev=null;
        }
        if(next==null){
            this.last=prev;
        }else {
            next.prev=prev;
            x.next=null;
        }
        x.data = null;
        this.size--;
        return elementData;
    }
}

public class DoubleLinkedList {
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("火车头");
        link.add("1号车厢");
        link.add("2号车厢");
        link.add("3号车厢");
        link.add("车厢尾");

        System.out.println(link.contains("2号车厢"));
        System.out.println(link.contains("哈哈哈"));

        System.out.println(link.get(2));

        System.out.println(link.set(1,"未知车厢"));
        System.out.println("————————————");
        link.printLink();
        System.out.println("————————————");

        link.add(null);
        System.out.println(link.remove("2号车厢"));
        System.out.println(link.remove(null));
//        link.clear();
//        System.out.println("车厢已清空!");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值