当前位置: 代码网 > it编程>软件设计>数据结构 > 【数据结构】LinkedList与链表

【数据结构】LinkedList与链表

2024年07月28日 数据结构 我要评论
LinkedList与链表主要内容

目录

1.前言

2.链表

2.1链表的概念及结构

2.2 链表的实现

2.2.1mysinglelinkedlist类

2.2.2自定义异常类

2.2.3主程序代码

3.linkedlist的使用

3.1概念

 3.2 linkedlist的构造

3.3linkedlist的其他常用方法介绍

3.4linkedlist的遍历

4.arraylist和linkedlist的区别

5.总结


1.前言

在上一篇文章中,我们讲到arraylist不适合做任意位置插入和删除比较多的场景,因此java集合中又引入了linkedlist,即链表结构,通过链表来处理上述场景的问题。

2.链表

2.1链表的概念及结构

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

linkedlist = linked + list = 链表 + 列表 = 链表列表

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

1. 单向或者双向2. 带头或者不带头

3. 循环或者非循环

 虽然有这么多的链表的结构,但我们主要掌握以下两种:

  1. 无头单向非循环链表结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。
  2. 无头双向链表:在java的集合框架库中linkedlist底层实现就是无头双向循环链表。

2.2 链表的实现

2.2.1mysinglelinkedlist类

public class mysinglelinkedlist {
//设置内部类定义链表的结构
    static class listnode {
        public int val;
        public listnode next;

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

    public listnode head;//代表链表的头结点

    //创建链表
    public void creatlist() {
        listnode listnode1 = new listnode(12);
        listnode listnode2 = new listnode(23);
        listnode listnode3 = new listnode(34);
        listnode listnode4 = new listnode(45);
        listnode listnode5 = new listnode(56);

        listnode1.next = listnode2;
        listnode2.next = listnode3;
        listnode3.next = listnode4;
        listnode4.next = listnode5;
        this.head = listnode1;
    }
    //打印链表
    public void display() {
        listnode cur = head;
        while (cur != null) {
            system.out.print(cur.val + " ");
            cur = cur.next;
        }
        system.out.println();
    }

    //获取链表的长度
    public int size() {
        int count = 0;
        listnode cur = head;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

    //头插法
    public void addfirst(int val) {
        listnode node = new listnode(val);
        node.next = head;
        head = node;
    }

    //尾插法
    public void addlast(int val) {
        listnode node = new listnode(val);
        listnode cur = head;
        if (head == null) {
            head = node;
            return;
        }
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = node;
    }

    //在任意位置插入val
    public void addindex(int index, int val) {
        //1. 判断index的合法性
        try {
            checkindex(index);
        } catch (indexnotlegalexception e) {
            e.printstacktrace();
        }
        //2. index==0 || index ==size()
        if (index == 0) {
            addfirst(val);
            return;
        }
        if (index == size()) {
            addlast(val);
            return;
        }
        //3. 找到index的前一个位置
        listnode cur = findindexsubone(val);
        //4. 进行连接
        listnode node = new listnode(val);
        node.next = cur.next;
        cur.next = node;
    }

    private listnode findindexsubone(int index) {
        int count = 0;
        listnode cur = head;
        while (count != index - 1) {
            cur = cur.next;
            count++;
        }
        return cur;
    }

    private void checkindex(int index) throws indexnotlegalexception {
        if (index < 0 || index > size()) {
            throw new indexnotlegalexception("index不合法");
        }
    }

    //查找是否包含关键字val是否在单链表中
    public boolean contains(int val) {
        listnode cur = head;
        while (cur != null) {
            if (cur.val == val) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    //删除第一次出现关键字为val的节点
    public void remove(int val) {
        if (head == null) {
            return;
        }
        if (head.val == val) {
            head = head.next;
            return;
        }
        //1.找到当前需要删除值的节点的前一个
        listnode cur = head;
        while (cur.next != null) {
            if (cur.next.val == val) {
                listnode del = cur.next;
                cur.next = del.next;
                return;
            }
            cur = cur.next;
        }
    }

    //删除所有关键字为val的节点
    public void removeallkey(int val) {
        //1. 判断头结点为空
        if (head == null) {
            return;
        }
        //2. 定义prev和cur
        listnode prev = head;
        listnode cur = head.next;
        //3. 开始判断并且删除
        while (cur != null) {
            if (cur.val == val) {
                prev.next = cur.next;
                //cur=cur.next;
            } else {
                prev = cur;//prev = prev.next
                //cur=cur.next;
            }
            cur = cur.next;
        }
        //4. 处理头节点
        if (head.val == val) {
            head = head.next;
        }
    }

    //清空链表
    public void clear() {
        //head=null;
        listnode cur = head;
        while (cur != null) {
            listnode curn = cur.next;
            //cur.val =null;
            cur.next = null;
            cur = curn;
        }
        head = null;
    }
}

2.2.2自定义异常类

public class indexnotlegalexception extends runtimeexception {
    public indexnotlegalexception() {

    }

    public indexnotlegalexception(string msg) {
        super(msg);
    }
}

2.2.3主程序代码

public class test {
        public static void main(string[] args) {
            mysinglelinkedlist mysinglelinkedlist = new mysinglelinkedlist();
            mysinglelinkedlist.creatlist();
            mysinglelinkedlist.display();
            //头插法
            system.out.println("头插法");
            mysinglelinkedlist.addfirst(1);
            mysinglelinkedlist.addfirst(2);
            mysinglelinkedlist.addfirst(3);
            mysinglelinkedlist.display();
            //尾插法
            system.out.println("尾插法");
            mysinglelinkedlist.addlast(8);
            mysinglelinkedlist.addlast(9);
            mysinglelinkedlist.addlast(10);
            mysinglelinkedlist.display();
            //查找元素
            boolean a=mysinglelinkedlist.contains(10);
            system.out.println(a);
            //删除数据为12的元素
            mysinglelinkedlist.remove(12);
            mysinglelinkedlist.display();
            //删除所有数据为3的元素
            mysinglelinkedlist.removeallkey(3);
            mysinglelinkedlist.display();
            //求size的长度
            int size=mysinglelinkedlist.size();
            system.out.println(size);
            //清空链表
            mysinglelinkedlist.clear();
            mysinglelinkedlist.display();
        }

    public static void main1(string[] args) {
        mysinglelinkedlist mysinglelinkedlist = new mysinglelinkedlist();
        //mysinglelinkedlist.creatlist();
        mysinglelinkedlist.addfirst(1);
        mysinglelinkedlist.addfirst(2);
        mysinglelinkedlist.addlast(5);
        mysinglelinkedlist.addindex(0, 2);
        //mysinglelinkedlist.remove(2);
        mysinglelinkedlist.removeallkey(2);
        mysinglelinkedlist.display();
        system.out.println(mysinglelinkedlist.size());
        system.out.println(mysinglelinkedlist.contains(5));
    }
}

运行结果如下:

3.linkedlist的使用

3.1概念

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

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

 tips:

 3.2 linkedlist的构造

方法解释
linkedlist()无参构造
public linkedlist(collection<? extends e> c)使用其他集合容器中元素构造list

 举个例子:

import java.util.linkedlist;
import java.util.list;

public class test {
    public static void main(string[] args) {
        list<integer> list1 = new linkedlist<>();
        list1.add(10);
        list1.add(20);
        list1.add(30);

        list<string> list2 = new java.util.arraylist<>();
        list2.add("java");
        list2.add("c++");
        list2.add("python");


        //使用arraylist构造linklisted
        list<string> list3 = new linkedlist<>(list2);
        system.out.println(list1);
        system.out.println(list2);
        system.out.println(list3);
    }
}

运行结果如下: 

3.3linkedlist的其他常用方法介绍

方法解释
boolean add(e e)尾插 e
void add(int index, e element)将 e 插入到 index 位置
boolean addall(collection<? extends e> 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

 举个例子:

import java.util.linkedlist;
import java.util.list;

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);
        system.out.println(list);
        //返回链表长度
        system.out.println(list.size());
        system.out.println();

        //从起始位置插入0
        list.add(0, 0);
        system.out.println(list);
        system.out.println();

        //删除指定位置的元素
        list.remove(1);
        system.out.println(list);
        //删除第一个元素
        list.removefirst();
        //删除最后一个元素
        list.removelast();
        system.out.println(list);
        system.out.println();

        //检查元素是否存在,若存在返回true,否则返回false
        if (!list.contains(3)) {
            system.out.println("元素不存在");
        }
        system.out.println();

        //从前往后找到第一个指定元素值的位置
        system.out.println(list.indexof(1));
        //从后往前找到第一个指定元素值的位置
        system.out.println(list.lastindexof(2));
        system.out.println();

        //获取指定位置元素
        int elem = list.get(0);
        system.out.println(elem);
        system.out.println();

        //将指定位置元素改成指定元素
        system.out.println(list);
        list.set(0, 100);
        system.out.println(list);
        system.out.println();

        //sublist(from,to): 用list中[from,to)之间的元素构造一个新的linkedlist返回
        list<integer> newlist = list.sublist(0, 2);
        system.out.println(list);
        system.out.println(newlist);
        system.out.println();

        //将list中的元素清空
        list.clear();
        system.out.println(list);
        system.out.println(list.size());
    }
}

 运行结果如下:

3.4linkedlist的遍历

import java.util.linkedlist;
import java.util.list;
import java.util.listiterator;

public class test {
    public static void main(string[] args) {
        linkedlist<integer> list = new linkedlist<>();
        list.add(10);   // add(elem): 表示尾插
        list.add(20);
        list.add(30);
        list.add(40);
        system.out.println(list);

        // foreach遍历
        for (int e : list) {
            system.out.print(e + " ");
        }
        system.out.println();

        // 使用迭代器遍历---正向遍历
        listiterator<integer> it = list.listiterator();
        while (it.hasnext()) {
            system.out.print(it.next() + " ");
        }
        system.out.println();

        //使用反向迭代器---反向遍历
        listiterator<integer> it1 = list.listiterator(list.size());
        while (it1.hasprevious()) {
            system.out.print(it1.previous() + " ");
        }
        system.out.println();
    }
}

运行结果如下:

4.arraylistlinkedlist的区别

不同点

arraylist

linkedlist

存储空间上

物理上一定连续

逻辑上连续,但物理上不一定连续

随机访问

支持:o(1)

不支持:o(n)

头插

需要搬移元素,效率低o(n)

只需修改引用的指向,时间复杂度为o(1)

插入

空间不够时需要扩容

没有容量的概念

应用场景

元素高效存储+频繁访问

任意位置插入和删除频繁

5.总结

以上就是本次分享链表的内容和操作链表的方法,我们要根据不同的应用场景要求,选择合适的arraylist或linkedlist,将会大大地提高学习工作效率。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com