首页 > 编程语言 >Java————链表

Java————链表

时间:2024-07-25 10:28:41浏览次数:10  
标签:Node head Java cur int next 链表 public

目录

前言:

1.链表的概念

2.链表的结构

2.1带头的和不带头的

2.2单向和双向

2.3循环和非循环

3.链表的实现

3.1双向不带头不循环链表:

3.2单向不带头不循环链表:

4.LinkedList的使用

4.1什么是LinkedList

4.2LinkedList的使用

5.LinkedList的遍历

5.1foreach遍历

5.2使用迭代器遍历---正向遍历

5.3使用迭代器遍历---反向遍历


前言:

由于顺序表底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。因此:java 集合中又引入了LinkedList,即链表结构。

1.链表的概念

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。(物理上是非连续的,逻辑上是连续的)

注意:

1.链式结构在逻辑上是连续的,在物理上不一定是连续的

2.现实中的节点一般都是从堆上申请出来的

3.从堆上申请的空间,是按照一定的策划来分配的,两次申请的空间可能连续,也可能不连续

2.链表的结构

链表有2的3次方种结构:

总的可以分为三类:带头的和不带头的,单向的和双向的,循环和不循环的

2.1带头的和不带头的

上面是单向不循环的带头和不带头的两个链表

注意:

1.带头链表的第一个节点叫做哨兵位,这个节点不存储有效内容

2.每一个节点的next引用指向下一个节点

2.2单向和双向

2.3循环和非循环

虽然总的链表有8种结构,但需要重点掌握的只有两种:

1.无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。

2.无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

3.链表的实现

3.1双向不带头不循环链表:

IList:

package OneList;

public interface IList {

//头插法
        public void addFirst(int data);
 //尾插法
         public void addLast(int data);
 //任意位置插入,第一个数据节点为0号下标
         public void addIndex(int index,int data);
 //查找是否包含关键字key是否在单链表当中
         public boolean contains(int key);
 //删除第一次出现关键字为key的节点
         public void remove(int key);
 //删除所有值为key的节点
         public void removeAllKey(int key);
 //得到单链表的长度
         public int size();
//清空链表
 public void clear();
//打印链表
         public void display();
}

方法的实现:

package OneList;

public class MyList implements IList{
    static class Node{
        Node prv;
        Node next;
        int x;
        public Node(int x) {
            this.x = x;
        }
    }

    private int size=0;
    private Node head=null;
    private Node tail=null;

    @Override
    public void addFirst(int data) {
        Node node=new Node(data);
if (head==null){
    head=node;
    tail=node;
}else {
    node.next=head;
    head.prv=node;
    head=node;
}
size++;
    }

    @Override
    public void addLast(int data) {
        Node node=new Node(data);
        if (head==null){
            head=node;
            tail=node;
        }else {
        node.prv=tail;
        tail.next=node;
        tail=node;
        }
        size++;
    }

    @Override
    public void addIndex(int index, int data) {
        Node node=new Node(data);
if (index<0||index>size){
    return ;
}
if (index==0){
    addFirst(data);
}
else if (index==size){
    addLast(data);
}else {
    Node cur=head;
    while (index>1){
        cur=cur.next;
        index--;
    }
    Node t=cur.next;
    node.next=t;
    t.prv=node;
    cur.next=node;
    node.prv=cur;
    size++;
}
    }

    @Override
    public boolean contains(int key) {
        if (head==null){
            return false;
        }
        Node cur=head;
        while (cur!=null){
            if(cur.x==key){
                return true;
            }
            cur=cur.next;
        }
        return  false;
    }

    @Override
    public void remove(int key) {
        if (head==null){
            return;
        }

        if (head.x==key){
            head=head.next;
            head.prv=null;
            size--;
        }
        Node cur=head;
        while (cur.next!=null){
            if(cur.x==key){
                cur.prv.next=cur.next;
                cur.next.prv=cur.prv;
                size--;
                return;
            }
            cur=cur.next;
        }
        if (cur.x==key){
            tail=tail.prv;
            tail.next=null;
            size--;
        }
    }

    @Override
    public void removeAllKey(int key) {
if (head==null){
    return;
}
Node cur=head;
while (cur!=null){
    if(cur.x==key&&cur==head){
        head=head.next;
        cur=cur.next;
        head.prv=null;
        size--;
    } else if (cur.x==key&&cur==tail) {
        tail=tail.prv;
        tail.next=null;
        size--;
    }else if (cur.x==key){
        cur.prv.next=cur.next;
        cur.next.prv=cur.prv;
        cur=cur.next;
        size--;
    }else {
        cur=cur.next;
    }
}


    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public void clear() {
Node cur=head;
Node next=cur.next;
while (next!=null){
    cur=null;
    cur=next;
    next=next.next;
}
cur=null;
head=null;
tail=null;
    }

    @Override
    public void display() {
if (head==null){
    return;
}
Node cur=head;
while (cur!=null){
    System.out.print(cur.x+" ");
    cur=cur.next;
}
        System.out.println();
    }
}

3.2单向不带头不循环链表:

IList:

package List;

public interface IList {
  //头插法
         public void addFirst(int data);
 //尾插法
         public void addLast(int data);
 //任意位置插入,第一个数据节点为0号下标
         public void addIndex(int index,int data);
 //查找是否包含关键字key是否在单链表当中
         public boolean contains(int key);
 //删除第一次出现关键字为key的节点
         public void remove(int key);
 //删除所有值为key的节点
         public void removeAllKey(int key);
 //得到单链表的长度
         public int size();
         //打印链表
 public void display();
 //清空链表
 public void clear();


    }

MyList:

package List;

import java.awt.*;

public class MyList implements IList{

    static class Node{
        int val;
        Node next;

        public Node(int val) {
            this.val = val;
        }
    }

    private int size=0;
    private Node head=null;


    @Override
    public void addFirst(int data) {
        Node node=new Node(data);
        if (head==null){
            head=node;
        }else {
            node.next=head;
            head=node;
        }
        size++;
    }

    @Override
    public void addLast(int data) {
Node node=new Node(data);
if (head==null){
    head=node;
}else {
    Node cur=head;
    while (cur.next!=null){
        cur=cur.next;
    }
    cur.next=node;
}
size++;
    }

    @Override
    public void addIndex(int index, int data) {
if (index<0||index>size){
    return;
}
Node node=new Node(data);
if (index==0){
    addFirst(data);
}
else if (index==size){
    addLast(data);
}else {
    Node cur=head;
    while (index>1){
        cur=cur.next;
        index--;
    }
    node.next=cur.next;
    cur.next=node;
    size++;
}



    }

    @Override
    public boolean contains(int key) {
        if (head==null){
            return false;
        }
        Node cur=head;
        while (cur!=null){
            if (cur.val==key){
                return true;
            }
            cur=cur.next;
        }
        return false;
    }

    @Override
    public void remove(int key) {
        if (head == null) {
            return;
        }
        Node cur = head;
        if (head.val == key) {
            head = head.next;
            size--;
            return;
        }
        while (cur.next != null) {
            if (cur.next.val == key) {
                cur.next = cur.next.next;
                size--;
                return;
            }
            cur = cur.next;
        }
        if (cur.val==key){
            cur=null;
            size--;
        }
    }
    @Override
    public void removeAllKey(int key) {
        if (head==null){
            return;
        }
while(head.val==key){
    head=head.next;
    size--;
}
        Node cur=head;
Node next=head.next;
while (next.next!=null){
    if (next.val==key){
        cur.next=next.next;
        next=next.next;
        size--;
    }else {
        next=next.next;
    cur=cur.next;
    }
}
if (next.val==key){
    cur.next=null;
    size--;
}

    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public void display() {
Node cur=head;
while (cur!=null){
    System.out.print(cur.val+" ");
    cur=cur.next;
}
        System.out.println();
    }

    @Override
    public void clear() {
        Node cur=head;
        Node next=cur.next;
        while (next!=null){
            cur=null;
            cur=next;
            next=next.next;
        }
        cur=null;
        head=null;
    }
}

4.LinkedList的使用

4.1什么是LinkedList

LinkedList的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

在集合框架中,LinkedList也实现了List接口,具体如下:

说明:

1. LinkedList实现了List接口

2. LinkedList的底层使用了双向链表

3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问

4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)

5. LinkedList比较适合任意位置插入的场景

4.2LinkedList的使用

构造方法:

LinkedList()无参构造
public LinkedList(Collection c)使用其他集合容器中元素构造List
public static void main(String[] args) {
    // 构造一个空的LinkedList
    List<Integer> list1 = new LinkedList<>();
    
    List<String> list2 = new java.util.ArrayList<>();
    list2.add("JavaSE");
    list2.add("JavaWeb");
    list2.add("JavaEE");
    // 使用ArrayList构造LinkedList
    List<String> list3 = new LinkedList<>(list2);
}

LinkedList的其他常用方法:

boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List subList(int fromIndex, int toIndex)截取部分 list

 方法练习使用:

package Test;

import java.util.LinkedList;

public class Test {
    public static void main(String[] args) {
        LinkedList<Integer>list=new LinkedList<>();
        //尾插
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println(list);
        //指定位置插入
list.add(0,0);
        System.out.println(list);
        list.add(list.size(), 6);
        System.out.println(list);
        list.add(5,6);
        System.out.println(list);
        //头插
        list.addFirst(-1);
        System.out.println(list);
        //尾插
        list.addLast(100);
        System.out.println(list);
        System.out.println("========================================");
        //判断元素是否存在
        System.out.println(list.contains(1));
        //获取下标元素
        System.out.println(list.get(1));
        //获取第一个元素
        System.out.println(list.getFirst());
//获取最后一个元素
        System.out.println(list.getLast());
        //修改指定位置的元素
        list.set(4,99999);
        System.out.println(list);
        //返回第一次出现元素的下标
        System.out.println(list.indexOf(100));
//返回最后一次出现元素的下标
        System.out.println(list.lastIndexOf(2));
//截取指定区间的元素(左闭右开)
        System.out.println(list.subList(1, 4));
    }

}

5.LinkedList的遍历

5.1foreach遍历

      for (int x:list) {
            System.out.print(x+" ");
        }

5.2使用迭代器遍历---正向遍历

    ListIterator<Integer>lit= list.listIterator();
        while (lit.hasNext()){
            System.out.print(lit.next()+" ");
        }

5.3使用迭代器遍历---反向遍历

   ListIterator<Integer>it= list.listIterator();
        while (it.hasPrevious()){
            System.out.print(it.previous()+" ");
        }

标签:Node,head,Java,cur,int,next,链表,public
From: https://blog.csdn.net/2301_80251684/article/details/140659035

相关文章

  • 都4202年了为什么大厂程序员还在用java8?
    Java8新特性文章目录Java8新特性接口的默认方法(DefaultMethodsforInterfaces)Lambda表达式(Lambdaexpressions)函数式接口(FunctionalInterfaces)方法和构造函数引用(MethodandConstructorReferences)Lambda表达式作用域(LambdaScopes)访问局部变量访问字......
  • @Slf4j注解 - javaweb日志记录
    1.引言在现代的JavaWeb开发中,日志记录是一个非常重要的组成部分。良好的日志记录可以帮助开发者快速定位问题、监控系统运行状态以及进行性能调优。@Slf4j注解是Lombok库提供的一个便捷工具,用于简化日志记录的代码编写。本文将详细讲解@Slf4j注解的相关内容,包括其概念、......
  • 【React】箭头函数:现代 JavaScript 的高效编程方式
    文章目录一、箭头函数的基本语法二、箭头函数的特性三、在React中的常见用法四、最佳实践在现代JavaScript中,箭头函数(ArrowFunctions)是一种简洁的函数表达方式,并且在React开发中非常常见。箭头函数不仅简化了函数的语法,还带来了与普通函数不同的行为特性。本......
  • Java面向对象-04
    1.多态:多种形态向上造型/自动类型转换:超类型的引用指向派生类的对象能点出来什么,看引用的类型向下转型/强制类型转换,成功的条件只有如下两种:引用所指向的对象,就是该类型引用所指向的对象,实现了该接口或继承了该类强转时若不符合如上条件,则发生ClassCastException类......
  • Java中的多态性(Polymorphism)
    Java中的多态性(Polymorphism)是面向对象编程(OOP)中的一个核心概念,它允许同一个接口或方法在不同对象上具有不同的实现方式。多态性极大地提高了代码的灵活性和可扩展性,使得程序能够以一种统一的方式处理不同类型的对象。以下是对Java中多态性的详细解释,包括其定义、实现方式、......
  • javaWeb_JSP
    首先要对项目的pom.xml进行添加依赖点击查看代码<dependencies><!--Servlet依赖--><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version>&l......
  • TestNG详解,Java自动化用例管理利器!
    TestNG是开源自动化测试工具,覆盖多类型测试:单元测试,功能测试,集成测试,它的功能非常强大支持多种类型的单元测试(异常测试,超时测试,依赖测试….)支持参数化 &提供了丰富的测试用例组织方式(Suite,Test,Method)生成测试报告,并支持测试报告扩展(Allure,ReportNG)......
  • 双向链表<数据结构 C版>
    目录关于链表的分类 双向链表结构体初始化尾插头插打印判断是否为空尾删头删查找指定位置之后的插入指定位置的删除销毁关于链表的分类根据链表的三大特性,单向or双向、带头or不带头、循环or不循环,可将链表分为2*2*2,8种链表,前面我们已经实现了单链表,即:不带头......
  • JavaScript的数组方法
    JavaScript中的数组是高阶的、灵活的数据结构,提供了许多内置方法来操作数组。以下是一些常用的数组方法:1.数组的添加、删除和替换方法:push(...items):向数组末尾添加一个或多个元素,并返回新的长度。pop():移除数组的最后一个元素,并返回被移除的元素。unshift(...items):向数组......
  • 深入理解 Java17 新特性:Sealed Classes
    0关键总结JavaSE15在2020年9月发布,预览功能引入“封闭类”(JEP360)封闭类是一种限制哪些其他类或接口可扩展它的类或接口类似枚举,封闭类在领域模型中捕获替代方案,允许程序员和编译器推理其穷尽性封闭类对于创建安全的层次结构也很有用,通过解耦可访问性和可扩展性,允许库开......