双向无头非循环链表的简单实现及介绍

前言

欢迎大家阅读小奥奇的新作,听说上一篇我们留下了一点点 " 简单的题目 " ,我们在本篇要干什么呢,请看本篇任务!

本篇任务概述:

1、解决 " 简单的遗留题目 "

2、 LInkedList(双向)的使用

3、简单的自我模拟 LinkedList 的实现

4、ArrayList 和 LinkedList 的区别


一、解决 " 简单的遗留题目 "

1.1 反转一个单链表

java 复制代码
public ListNode reverseList(ListNode head) {
        if(head==null){
            return null;
        }
        ListNode cur=head;
        while(cur.next!=null){
            ListNode lim=cur.next;
            cur.next=lim.next;
            lim.next=head;
            head=lim;
        }
        return head;
    }

解题思路如下:

主要使用头插法 (前篇讲到过),从第二个节点开始,先判断head 是否为空,若为空则返回null ,否则令cur = head ,使用 while 遍历链表,当 cur.next 不为空时,初始化下一个节点,使 lim = cur.next ,接着使当前节点的下一个结点 cur.next 设置为下一个节点的下一个节点lim.next ,再使下一个节点的下一个节点 lim.next 指向头节点head ,将头节点设置为lim即可

1.2 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点

java 复制代码
class Solution {
    public ListNode middleNode(ListNode head) {
        if(head==null||head.next==null){
            return head;
        }
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        }
        return slow;
    }
}

解题思路如下:

先判断头节点是否为空或是否只含一个节点,定义两个指针:快指针 fast 和慢指针slow ,使用while( fast!= null && fast.next != null ) 遍历链表,使快指针fast 一次走两个节点,慢指针 slow 一次走一个节点,当快指针 fast 为空或其下一节点为空时,结束循环,此时slow所在位置即为中间节点

1.3 链表的回文结构

java 复制代码
class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head==null){
            return true;
        }
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        }
        ListNode cur=slow;
        while(cur.next!=null){
            ListNode lim=cur.next;
            cur.next=lim.next;
            lim.next=slow;
            slow=lim;
        }
        while(head!=slow){
            if(head.val!=slow.val){
                return false;
            }
            if(head.next==slow){
                return true;
            }
            head=head.next;
            slow=slow.next;
        }
        return true;
    }
}

解题思路如下:

判断链表是否为空,如何和上题一样,找到中间节点,接着从中间节点出进行逆置,然后用while遍历链表,当遍历的过程有不相等之处,即该链表不存在回文结构,否则存在回文结构

题目都解决完毕,若有不明白或错误之处,请大家在评论区提出,相信大家做完收获满满,第三题难道相对大啦点,但是和前两题联系紧密,接下来我们将介绍LinkedList 的使用


二、LinkedList(双向)的使用

2.1 什么是LinkedList?

LinkedList 的官方文档https://docs.oracle.com/javase/8/docs/api/java/util/LinkedList.html LinkedList的底层是双向链表结构,由于链表没有将元素储存在连续的空间,而是储存在单独的节点中,用引用将各个节点连接起来,所以在任意位置插入或删除元素都比较方便。

2.2 LinkedList的使用

2.3 LinkedList的构造


三、简单的自我模拟 LinkedList的实现

代码如下:(大家自行观看,我就不解释啦)

java 复制代码
public class LinkedList implements IList{
    static class ListNode{
        private int val;
        private ListNode prev;
        private ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }
    private ListNode head;
    private ListNode last;
    public void addFirst(int data) {
        ListNode node=new ListNode(data);
        if(head==null){
            head=last=node;
        }else {
            node.prev = null;
            node.next = head;
            head.prev = node;
            head = node;
        }
    }
    public void addLast(int data) {
        ListNode node = new ListNode(data);
        if (head == null) {
            head = last = node;
        }else {
            last.next = node;
            node.prev = last;
            last=last.next;
        }
    }
    private void checki(int index) throws Illegalindex{
        if(index<0||index>size()){
            throw new Illegalindex("输入的索引不合法!!!");
        }
    }
    public void addIndex(int index, int data) throws Illegalindex{
        try{
            checki(index);
            ListNode node=new ListNode(data);
            if(index==0){
                addFirst(data);
                return;
            }
            if(index==size()){
                addLast(data);
                return;
            }
            ListNode cur=head;
            while(index!=0){
                cur=cur.next;
                index--;
            }
            node.next=cur;
            node.prev=cur.prev;
            cur.prev.next=node;
            cur.prev=node;
        }catch(Illegalindex e){
            System.out.println("增加的位置不合法!!!");
            e.printStackTrace();;
        }
    }
    public void remove(int key) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    head = head.next;
                    if (head != null) {
                        head.prev = null;
                    }
                } else {
                    cur.prev.next = cur.next;
                    if (cur.next == null) {
                        last = last.prev;
                    } else {
                        cur.next.prev = cur.prev;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }
    public void removeAllKey(int key) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    head = head.next;
                    if (head != null) {
                        head.prev = null;
                    }
                } else {
                    cur.prev.next = cur.next;
                    if (cur.next == null) {
                        last = last.prev;
                    } else {
                        cur.next.prev = cur.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }
    public int size() {
        ListNode cur=head;
        int len=0;
        while(cur!=null){
            len++;
            cur=cur.next;
        }
        return len;
    }

    public void clear() {
        ListNode cur=head;
        while(cur!=null){
            ListNode curn=cur.next;
            cur.next=null;
            cur.prev=null;
            cur=curn;
        }
        head=last=null;
    }
    public boolean contains(int toFind) {
        ListNode cur=head;
        while(cur!=null){
            if(cur.val==toFind){
                return true;
            }
        }
        return false;
    }
    public void display() {
        ListNode cur=head;
        for (int i = 0; i < size(); i++) {
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }
}

上述代码实现了 IList接口,以及抛出了自定义异常,前面文章都有涉及并讲解。


四、ArrayListLinkedList的区别

ArrayListLinkedListJava中的两种不同的集合实现方式。下面是它们之间的区别:

1. 内部实现:

ArrayList是基于数组实现的,LinkedList是基于双向链表实现的。

2. 插入和删除操作的效率:

ArrayList 在尾部插入和删除元素的效率较高,时间复杂度为O(1) ,而在中间插入和删除元素的效率较低,因为需要移动其他元素,时间复杂度为O(n) 。而LinkedList 在任意位置插入和删除元素的效率都较高,时间复杂度为O(1)

3. 随机访问的效率:

ArrayList 支持随机访问操作,即可以通过索引快速访问任意位置的元素,时间复杂度为O(1) 。而 LinkedList 则不支持随机访问,需要从头或尾开始遍历链表,时间复杂度为O(n)

4. 内存消耗:

ArrayList需要连续的内存空间来存储元素,所以在元素较多时可能会占用较大的内存空间。而LinkedList不需要连续的内存空间,它只需要为每个元素存储指向前后节点的引用,所以在元素较多时可能会占用较小的内存空间。

根据具体的使用场景,选择 ArrayList 还是LinkedList 会有不同的优劣势。如果需要频繁的随机访问和对尾部的增删操作较多,可以选择 ArrayList ;如果需要频繁的在任意位置插入和删除操作,可以选择LinkedList


相关推荐
wheeldown3 小时前
【数据结构】选择排序
数据结构·算法·排序算法
躺不平的理查德7 小时前
数据结构-链表【chapter1】【c语言版】
c语言·开发语言·数据结构·链表·visual studio
阿洵Rain7 小时前
【C++】哈希
数据结构·c++·算法·list·哈希算法
Leo.yuan7 小时前
39页PDF | 华为数据架构建设交流材料(限免下载)
数据结构·华为
半夜不咋不困7 小时前
单链表OJ题(3):合并两个有序链表、链表分割、链表的回文结构
数据结构·链表
忘梓.8 小时前
排序的秘密(1)——排序简介以及插入排序
数据结构·c++·算法·排序算法
y_m_h11 小时前
leetcode912.排序数组的题解
数据结构·算法
1 9 J11 小时前
数据结构 C/C++(实验三:队列)
c语言·数据结构·c++·算法
921正在学习编程11 小时前
数据结构之二叉树前序,中序,后序习题分析(递归图)
c语言·数据结构·算法·二叉树
毕竟秋山澪11 小时前
岛屿数量 广搜版BFS C#
数据结构·算法·宽度优先