java实现单向链表和优化

1.链表的时间复杂度分析

查询元素时间复杂度

链表是不支持随机访问的,在链表中只有从头节点开始一个一个往下找,找到查询的元素为止,比如链表的长度为n,最好的情况是头节点就是需要找的元素,那么就是一个时间单元1*unit_time,,最坏的情况是最后一个节点是需要找的元素,那么就是n*unit_time,那么平均时间复杂度就是n/2*unit_time;根据大O推导出,时间复杂度为O(n);

删除元素时间复杂度

在链表中删除元素非常简单,链表中的每个节点都有一个指向下个节点的指针,我们只需要找到删除节点B的前一个节点A,把B的指针指向A的下一个节点C,比如:原来是A->B->C,删除后是A->C,非常简单,时间复杂度就是O(1).

2.代码演示

关于代码演示,做下说明,我们关注的是数据结构的特点以及基本实现,至于数据结构中稍微复杂一点的操作,这里不做演示,可以自己研究,花点时间,都是没问题的,这里基本就演示两个操作,添加和删除。

2.1最原始的实现

public class YLink<E> {
    private Node head;
    private int size;

    /**
     * 内部类,用来封装链表中每个节点的属性
     */
    private class Node{
        /**
         * 链表中每个节点的值
         */
        private E e;
        /**
         * 指向链表中下个节点的指针
         */
        private Node next;

        private Node(E e, Node next) {
            this.e = e;
            this.next = next;
        }
    }

    public int size() {
        return size;
    }

    /**
     * 向链表中的头部添加新节点
     * @param e
     */
    public void add(E e) {
        if (head == null) {
            head = new Node(e, null);
        } else {
            head = new Node(e,head);
        }
        size++;
    }

    /**
     * 删除指定元素
     * @param e
     */
    public void remove(E e) {
        if (head.e.equals(e)) {
            head = head.next;
        } else {
            Node temp = head;
            while (temp.next != null) {
                if (e.equals(temp.next.e)) {
                    temp.next = temp.next.next;
                    break;
                }
                temp = temp.next;
            }
        }
        size--;
    }

    @Override
    public String toString() {
        StringBuilder sbr = new StringBuilder();
        Node temp = head;
        while (temp != null) {
            sbr.append(temp.e).append("->");
            temp = temp.next;
        }
        String s = sbr.toString();
        String result = s.substring(0, s.lastIndexOf("->"));
        return result;
    }

}

说明:在上面代码中,可以发现,在添加和删除的时候,需要对头节点做一个特殊判断,感觉不是很爽,有没有办法去掉这个判断,让代码逻辑更简洁呢,答案当然是有的,我们可以增加一个虚拟节点,这个节点不存储元素,只是让代码实现更加方便。如下:

public class YLinkWithHead<E> {
    /**
     * 虚拟头节点,不存储实际元素
     */
    private Node head;
    private int size;

    public YLinkWithHead() {
        head = new Node(null, null);
        size = 0;
    }

    /**
     * 内部类,用来封装链表中每个节点的属性
     */
    private class Node{
        /**
         * 链表中每个节点的值
         */
        private E e;
        /**
         * 指向链表中下个节点的指针
         */
        private Node next;

        private Node(E e, Node next) {
            this.e = e;
            this.next = next;
        }
    }

    public int size() {
        return size;
    }

    /**
     * 向链表中的头部添加新节点
     * @param e
     */
    public void add(E e) {
        //一行代码搞定节点添加
        head.next = new Node(e, head.next);
        size++;
    }

    /**
     * 删除指定元素
     *
     * @param e
     */
    public void remove(E e) {
        Node temp = head;
        while (temp.next != null) {
            if (e.equals(temp.next.e)) {
                temp.next = temp.next.next;
                break;
            }
            temp = temp.next;
        }
        size--;
    }

    @Override
    public String toString() {
        StringBuilder sbr = new StringBuilder();
        Node temp = head.next;
        while (temp != null) {
            sbr.append(temp.e).append("->");
            temp = temp.next;
        }
        String s = sbr.toString();
        String result = s.substring(0, s.lastIndexOf("->"));
        return result;
    }
}

说明:在上述代码中,add(E e)这个方法只需要一行代码就实现了,非常简单明了,之所以能这样实现,是因为我们在初始化链表的时候初始花了虚拟头节点,让它不为null,后面添加的元素都是在虚拟头节点的后面,唯一需要注意的是,在遍历的时候,需要从虚拟头节点的下个节点开始,整体感觉爽多了,哈哈。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值