【数据结构】Java实现单链表

目录

1. ArrayList的缺陷

2. 链表

2.1 链表的概念及结构

2.2 接口的实现

3. 动手实现单链表

3.1 重写SeqList接口方法

3.2 在当前链表头部添加节点(头插)

3.3  在 第index位置添加节点(任意位置)

3.4 在当前链表尾部添加节点(尾插)

3.5  删除第index个节点

3.6 检验index是否合法

3.7 删除第一个值element的节点

3.8 删除所有值element的节点

3.9 修改第index个节点的值为element

3.10 获取第index个节点的值

3.11 判断链表中是否存在element

3.12  获取element在链表中的位置

3.13 打印链表

4. SingleLinkedList整体实现

4.1 SingleLinkedList类

4.2 Test类

4.3 测试结果


1. ArrayList的缺陷

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

2. 链表

2.1 链表的概念及结构

链表是一种 物理存储结构上非连续 存储结构,数据元素的 逻辑顺序 是通过链表中的 引用链接 次序实现的 。
实际中链表的结构非常多样,以下情况组合起来就有6 种链表结构:
(1)  单向或者双向

(2) 带头或者不带头

(3)循环或者非循环

虽然有这么多的链表的结构,但是我们重点掌握两种 :
无头单向非循环链表 结构简单 ,一般不会单独用来存数据。实际中更多是作为 其他数据结构的子结构 ,如哈希桶、图的邻接表等等。
无头双向链表 :在 Java 的集合框架库中 LinkedList 底层实现就是无头双向循环链表。

2.2 接口的实现

使用泛型更好的接收不同数据类型(一个顺序表只能接受一种类型!)

public interface SeqList<E> {
    //    尾插
    void add(E element);
    //    将 element 插入到 index 位置
    void add(int index,E element);
 
    //    删除 index 位置元素<返回删除的值
    E removeByIndex(int index);
    //    删除第一个值element的元素
    void removeByValue(E element);
    //    删除所有值element的元素
    void removeAllValue(E element);
 
    //    将下标 index 位置元素设置为 element,返回替换前的值
    E set(int index,E element);
    E get(int index);
    //    判断 o 是否在其中
    boolean contains(E element);
    int indexOf(E element);
    int size();
    void clear();
 
}

3. 动手实现单链表

实现没有头节点的单链表

3.1 重写SeqList接口方法

public class SingleLinkedList<E> implements SeqList<E> {

    private Node head;//头节点

    private int size; // 节点个数,保存的元素个数

    //类的定义,内部类,对外部完全隐藏
    private class Node {
        E val;//保存的元素
        Node next;//下节车厢的位置
        Node(E val) {
            this.val = val;
        }
    }
    public void addFrist(E val){ }
    @Override
    public void add(E element) { }
    @Override
    public void add(int index, E element) { }
    @Override
    public E removeByIndex(int index) { }
    @Override
    public void removeByValue(E element) { }
    @Override
    public void removeAllValue(E element) { }
    @Override
    public E set(int index, E element) { }
    public boolean rangeCheck(int index){ }
    @Override
    public E get(int index) { }
    @Override
    public boolean contains(E element) { }
    @Override
    public int indexOf(E element) { }
    @Override
    public int size() { }
    @Override
    public void clear() { }
    @Override
    public String toString() { }
}

3.2 在当前链表头部添加节点(头插)

无论链表中是否包含节点,头插法都是这相同的代码处理~

public void addFrist(E val){
        // 要插入一个元素,首先要产生一个新节点
        Node node = new Node(val);
        // 将当前节点插入到链表中
        node.next = head;
        // 更新head的引用,指向当前的新节点
        head = node;
        size ++;
    }

    public void add(E element) {
        add(size,element);
    }

思考一下,①和②的代码顺序能换吗?

先执行2再执行1,原来的链表就丢了,head指向新节点,最终链表中只剩下新节点了~

3.3  在 第index位置添加节点(任意位置)

(1)判断index是否合法

(2)判断没有前驱,没有就是头插

(3)寻找index位置的前驱节点(单链表的核心操作就是在寻找前驱节点!)

(4)先将新节点和原先位置节点连接

(5)再更改原先prev的引用

public void add(int index, E element) {
        // 1.base case,边界判断
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("add index illegal!");
        }
        // 2.判断没有前驱的情况
        if (index == 0) {
            addFrist(element);
            return;
        }
        // 3.确实是中间位置的插入,寻找待插入位置的前驱!
        Node prev = head;
        for (int i = 0; i < index - 1; i++) {
            prev = prev.next;
        }
        // prev走到待插入位置的前驱
        Node node = new Node(element);
        node.next = prev.next;
        prev.next = node;
        size ++;
    }

3.4 在当前链表尾部添加节点(尾插)

第一种方法

(1)走到当前链表的最后

(2)让最后节点的next指向这个新添加的节点

第二种方法

调用add()方法,index等于size就是在链表末尾插入了

    public void addLast(E val){
        Node prev = head;
        while (prev.next != null){
            prev = prev.next;
        }
        Node node = new Node(val);
        prev.next = node;
    }


    //尾插2
    @Override
    public void add(E element) {
        add(size,element);
    }

3.5  删除第index个节点

(1)判断index是否合法(链表为空则index不合法)

(2)判断没有前驱,没有就是头节点删除

(3)寻找index位置的前驱节点

(4)将前驱节点和原先位置的下一个节点连接

public E removeByIndex(int index) {
        // 1.base case
        if (!rangeCheck(index)) {
            throw new IllegalArgumentException("remove index illegal!");
        }
        // 2.判断头节点的删除问题
        if (index == 0) {
            Node node = head;
            head = head.next;
            node.next = null;
            size --;
            return node.val;
        }
        // 3.现在确实是中间位置的删除
        Node prev = head;
        for (int i = 0; i < index - 1; i++) {
            prev = prev.next;
        }
        Node node = prev.next;
        prev.next = node.next;
        node.next = null;
        size --;
        return node.val;
    }

3.6 检验index是否合法

public boolean rangeCheck(int index){
        if (index < 0 || index >= size) {
            return false;
        }
        return true;
    }

3.7 删除第一个值element的节点

(1)判断链表是否为空

(2)判断头节点是否是待删除的节点,是的话删除完就方法返回

(3)寻找element节点的前驱节点(凡是用到引用的位置,一定要保证这个引用不为空)

(4)将前驱节点和原先位置的下一个节点连接

这里的图和3.5 中的图一致

 public void removeByValue(E element) {
        // 1.base case
        if (head == null) {
            return;
        }
        // 2.判断头节点恰好是待删除的节点
        if (head.val.equals(element)) {
            head = head.next;
            size --;
            return;
        }
        // 3.此时头节点不为空其一定不是待删除的结点
        Node prev = head;
        while (prev.next != null) {
            if (prev.next.val.equals(element)) {
                // prev走到了待删除节点的前驱位置
                prev.next = prev.next.next;
                size --;
                return;
            }
            prev = prev.next;
        }
        // 4.链表中没有待删除的节点
        System.out.println("当前链表中不存在值为" + element + "的节点");
    }

3.8 删除所有值element的节点

(1)判断链表是否为空

(2)判断头节点是否是待删除的节点

(3)判断链表是否已经删除完,删除完就返回

(4)寻找element节点的前驱节点(凡是用到引用的位置,一定要保证这个引用不为空)

(5)将前驱节点和原先位置的下一个节点连接

(6)如果下一个节点不是待删除的节点,prev指向下一个节点

(7)循环执行步骤(5)、(6)直到链表走完(prev.next != null)

 

 

public void removeAllValue(E element) {
        // 1.base case
        if(head == null) {
            return;
        }
        // 2.若头节点就是待删除的节点且出现连续的待删除节点
        while (head != null && head.val.equals(element)) {
            head = head.next;
            size --;
        }
        if (head == null) {
            // 整个链表已经删除完了
            return;
        }
        // 3.头节点一定不是待删除的节点且链表不为空!
        // prev一定指向的不是待删除的结点~
        Node prev = head;
        while (prev.next != null) {
            if (prev.next.val.equals(element)) {
                // 此时prev就是待删除节点的前驱
                prev.next = prev.next.next;
                size --;
            }else {
                // 只有后继节点不是待删除的结点才能移动prev引用!
                prev = prev.next;
            }
        }
    }

3.9 修改第index个节点的值为element

(1)判断index是否合法

(2)寻找index位置的节点

(3)将节点的val修改为element

public E set(int index, E element) {
//        1.索引的合法性校验
        if(!rangeCheck(index)){
            throw new IllegalArgumentException("set index illegal!");
        }
        // 从前向后遍历走到index对应的元素
        Node x = head;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        // 此时x就落在了待修改的节点位置
        E oldVal = x.val;
        x.val = element;
        return oldVal;
    }
    public boolean rangeCheck(int index){
        if (index < 0 || index >= size) {
            return false;
        }
        return true;
    }

3.10 获取第index个节点的值

public E get(int index) {
        if(!rangeCheck(index)){
            throw new IllegalArgumentException("get index illegal!");
        }
        Node x = head;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        return x.val;
    }

3.11 判断链表中是否存在element

 public boolean contains(E element) {
        Node cur = head;
        while (cur.next != null){
            if (cur.val.equals(element)){
                return true;
            }
        }
        return false;
    }

3.12  获取element在链表中的位置

public int indexOf(E element) {
        int count = 0;
        Node cur = head;
        while (cur.next != null){
            if (cur.val.equals(element)){
                return count;
            }
            count++;
            cur = cur.next;
        }
        return -1;
    }

3.13 打印链表

public String toString() {
        StringBuilder sb = new StringBuilder();
        // 从当前链表的第一个节点开始向后遍历,直到走到尾结点为止
        // 第一个节点head
        for(Node x = head;x != null;x = x.next){
            sb.append(x.val);
            sb.append("->");
            if(x.next == null){
                // 此时temp走到了尾结点
                sb.append("NULL");
            }
        }
        return sb.toString();
    }

3.14  获取链表长度以及清空链表

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

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

4. SingleLinkedList整体实现

4.1 SingleLinkedList类

public class SingleLinkedList<E> implements SeqList<E> {

    private Node head;//头节点

    private int size; // 车厢节点个数,保存的元素个数

    //车厢类的定义,车厢作为火车的内部类,对外部完全隐藏
    private class Node {
        E val;//保存的元素
        Node next;//下节车厢的位置
        Node(E val) {
            this.val = val;
        }
    }
    //  ------------------------------------------------

//    头插,在当前链表头部添加元素  head在移动
    public void addFrist(E val){
        // 要插入一个元素,首先要产生一个新节点
        Node node = new Node(val);
        // 将当前节点插入到链表中
        node.next = head;
        // 更新head的引用,指向当前的新节点
        head = node;
        size ++;
    }


    @Override
    public void add(E element) {
        add(size,element);
    }

    @Override
    public void add(int index, E element) {
        // 1.base case,边界判断
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("add index illegal!");
        }
        // 2.判断没有前驱的情况
        if (index == 0) {
            addFrist(element);
            return;
        }
        // 3.确实是中间位置的插入,寻找待插入位置的前驱!
        Node prev = head;
        for (int i = 0; i < index - 1; i++) {
            prev = prev.next;
        }
        // prev走到待插入位置的前驱
        Node node = new Node(element);
        node.next = prev.next;
        prev.next = node;
        size ++;
    }

    @Override
    public E removeByIndex(int index) {
        // 1.base case
        if (!rangeCheck(index)) {
            throw new IllegalArgumentException("remove index illegal!");
        }
        // 2.判断头节点的删除问题
        if (index == 0) {
            Node node = head;
            head = head.next;
            node.next = null;
            size --;
            return node.val;
        }
        // 3.现在确实是中间位置的删除
        Node prev = head;
        for (int i = 0; i < index - 1; i++) {
            prev = prev.next;
        }
        Node node = prev.next;
        prev.next = node.next;
        node.next = null;
        size --;
        return node.val;
    }

    @Override
    public void removeByValue(E element) {
        // 1.base case
        if (head == null) {
            return;
        }
        // 2.判断头节点恰好是待删除的节点
        if (head.val.equals(element)) {
            head = head.next;
            size --;
            return;
        }
        // 3.此时头节点不为空其一定不是待删除的结点
        Node prev = head;
        while (prev.next != null) {
            if (prev.next.val.equals(element)) {
                // prev走到了待删除节点的前驱位置
                prev.next = prev.next.next;
                size --;
                return;
            }
            prev = prev.next;
        }
        // 4.链表中没有待删除的节点
        System.out.println("当前链表中不存在值为" + element + "的节点");
    }

    @Override
    public void removeAllValue(E element) {
        // 1.base case
        if(head == null) {
            return;
        }
        // 2.若头节点就是待删除的节点且出现连续的待删除节点
        while (head != null && head.val.equals(element)) {
            head = head.next;
            size --;
        }
        if (head == null) {
            // 整个链表已经删除完了
            return;
        }
        // 3.头节点一定不是待删除的节点且链表不为空!
        // prev一定指向的不是待删除的结点~
        Node prev = head;
        while (prev.next != null) {
            if (prev.next.val.equals(element)) {
                // 此时prev就是待删除节点的前驱
                prev.next = prev.next.next;
                size --;
            }else {
                // 只有后继节点不是待删除的结点才能移动prev引用!
                prev = prev.next;
            }
        }
    }

//    修改
    @Override
    public E set(int index, E element) {
//        1.索引的合法性校验
        if(!rangeCheck(index)){
            throw new IllegalArgumentException("set index illegal!");
        }
        // 从前向后遍历走到index对应的元素
        Node x = head;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        // 此时x就落在了待修改的节点位置
        E oldVal = x.val;
        x.val = element;
        return oldVal;
    }
    public boolean rangeCheck(int index){
        if (index < 0 || index >= size) {
            return false;
        }
        return true;
    }

    @Override
    public E get(int index) {
        if(!rangeCheck(index)){
            throw new IllegalArgumentException("get index illegal!");
        }
        Node x = head;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        return x.val;
    }

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

    @Override
    public int indexOf(E element) {
        int count = 0;
        Node cur = head;
        while (cur.next != null){
            if (cur.val.equals(element)){
                return count;
            }
            count++;
            cur = cur.next;
        }
        return -1;

    }

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

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

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        // 从当前链表的第一个节点开始向后遍历,直到走到尾结点为止
        // 第一个节点head
        for(Node x = head;x != null;x = x.next){
            sb.append(x.val);
            sb.append("->");
            if(x.next == null){
                // 此时temp走到了尾结点
                sb.append("NULL");
            }
        }
        return sb.toString();
    }
}

4.2 Test类

public class SingleLinkedTest {
    public static void main(String[] args) {
        SingleLinkedList<Integer> list = new SingleLinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(9);
        list.add(10);
        list.add(10);
        list.add(6);
        list.add(10);
        list.add(5);
        list.add(7);
        list.add(10);
        list.add(10);

        System.out.println(list);
        System.out.println("------------添加测试-----------");
        System.out.println("从链表尾部添加99");
        list.add(99);
        System.out.println("添加index为2,element为88");
        list.add(2,88);
        System.out.println(list);
        System.out.println("-----------删除测试------------");
        System.out.println("删除index为0");
        list.removeByIndex(0);
        System.out.println("删除元素为6");
        list.removeByValue(6);
        System.out.println("删除所有10");
        list.removeAllValue(10);
        System.out.println(list);
        System.out.println("-----------其他------------");
        System.out.println("查看是否包含10这个元素");
        System.out.println(list.contains(10));
        System.out.println("修改index为3,element为19");
        list.set(3,19);
        System.out.println("获取index为3的元素");
        System.out.println(list.get(3));
        System.out.println(list);
        System.out.println("获取element为88的index");
        System.out.println(list.indexOf(88));
        System.out.println("获取顺序表长度");
        System.out.println(list.size());
        System.out.println("清空顺序表");
        list.clear();
        System.out.println(list + "...");
    }
}

4.3 测试结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/1408.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode每日一题】——165.比较版本号

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 双指针 二【题目难度】 中等 三【题目编号】 165.比较版本号 四【题目描述】 给你两个版本号…

Vector的扩容机制

到需要扩容的时候&#xff0c;Vector会根据需要的大小&#xff0c;创建一个新数组&#xff0c;然后把旧数组的元素复制进新数组。 我们可以看到&#xff0c;扩容后&#xff0c;其实是一个新数组&#xff0c;内部元素的地址已经改变了。所以扩容之后&#xff0c;原先的迭代器会…

idea中使用maven进行多模块打包部署时jar包中无依赖的问题(示例:jar包才5k,且无法正常启动)

引言 模块关系&#xff1a; A&#xff1a;代表父工程B&#xff1a;代表WEB模块&#xff0c;主加载类所在模块S&#xff1a;业务处理模块D&#xff1a;数据处理模块E&#xff1a;基础模块 依赖关系如下&#xff1a; D依赖ES依赖EB依赖D&#xff0c;B依赖S 第一次进行maven多模块…

2.机器学习笔记第二周

梯度下降&#xff1a; 就是最优选择算法的图形化表示&#xff1a;一个站在山顶的人&#xff0c;每秒走绝对小的一步&#xff0c;他朝着什么方向移动可以最快到达山脚。 接下来是梯度运算的数学解法&#xff1a; &#xff1a;是赋值的意思&#xff0c;a&#xff1a;b就是a无论…

openssh 9.0p1版本和openssl1.1.1o版本部署实操

【准备】 获取openssh 9.0p1版本软件包和openssl1.1.1o版本 如果设备可以连外网&#xff0c;直接从服务器上wget获取 wget --no-check-certificate https://www.openssl.org/source/openssl-1.1.1o.tar.gz wget http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openss…

多重背包的单调队列优化

邮专学子周末早起迎寒风细雨所作............. 周末也别想休息&#xff01;&#xff01;&#xff01;耐心看完&#xff0c;必定有收获哦&#x1f970;&#x1f42f;多重背包与其他背包相比的最大区别点就是&#xff0c;每个物品的数量是有限的。下面我们来看看多重背包的更新特…

java项目发布到Linux

参考&#xff1a;https://betheme.net/a/2751593.html?actiononClick java项目发布到Linux环境简单流程步骤&#xff1a; 一、首先打包成jar包&#xff0c;有两种方式 1、maven打包 打开idea项目。在右侧找到maven &#xff0c;有需要打包的项目&#xff0c;确定需要发布的…

考研数二第五讲 无穷小阶数问题的求解

无穷小阶数问题的求解 在考研复习中&#xff0c;关于无穷小阶数的问题是比较多的&#xff0c;从最基本的确定无穷小阶数问题&#xff0c;到无穷小之间的阶数 比较问题&#xff0c;都是属于比较常见的类型。此外&#xff0c;还有一些其他的切入点的题目&#xff0c;值得多多注意…

10.0自定义SystemUI下拉状态栏和通知栏视图(六)之监听系统通知

1.前言 在进行rom产品定制化开发中,在10.0中针对systemui下拉状态栏和通知栏的定制UI的工作开发中,原生系统的下拉状态栏和通知栏的视图UI在产品开发中会不太满足功能, 所以根据产品需要来自定义SystemUI的下拉状态栏和通知栏功能,首选实现的就是下拉通知栏左滑删除通知的部…

你是真的“C”——结构体中鲜有人知的“秘密”

你是真的“C”——结构体中的精髓剖析【内存对齐】 【位段】 &#x1f60e;前言&#x1f64c;结构体内存对齐&#xff1a;&#x1f60a;结构体内存对齐存在的意思是什么&#xff1f;&#x1f618;内存对齐例子详细剖析&#xff1a;&#x1f618;结构体中的位段&#xff1a;&…

模拟实现STL容器之vector

文章目录前言1.大体思路2.具体代码实现1.类模板的创建2.构造函数1.无参构造2.拷贝构造 迭代器构造和给定n个val值构造以及析构函数3.空间扩容1.reserve2.resize4.操作符重载1.[ ]重载2.赋值运算符重载5.数据增加和删除1.尾插2.任意位置插入3.任意位置删除4.尾删6.一些其他接口3…

HTTP协议详解(上)

目录 前言&#xff1a; 认识URL HTTP协议方法 通过Fiddler抓包 GET和POST之间典型区别 header详解 HTTP响应状态码 常见状态码解释 状态码分类 HTTP协议报文格式 小结&#xff1a; 前言&#xff1a; HTTP协议属于应用层协议&#xff0c;称为超文本传输协议&#xff…

Canvas百战成神-圆(1)

Canvas百战成神-圆 初始化容器 <canvas id"canvas"></canvas>canvas{border: 1px solid black; }让页面占满屏幕 *{margin: 0;padding: 0; } html,body{width: 100%;height: 100%;overflow: hidden; } ::-webkit-scrollbar{display: none; }初始化画笔…

一天吃透TCP面试八股文

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

Activity工作流(三):Service服务

3. Service服务 所有的Service都通过流程引擎获得。 3.1 RepositoryService 仓库服务是存储相关的服务&#xff0c;一般用来部署流程文件&#xff0c;获取流程文件&#xff08;bpmn和图片&#xff09;&#xff0c;查询流程定义信息等操作&#xff0c;是引擎中的一个重要的服务。…

SpringCloud笔记(Hoxton)——Netflix之Ribbon负载均衡

Ribbon使用 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具&#xff0c;简单的说&#xff0c;Ribbon是Netflix 发布的开源项目&#xff0c;主要功能是提供客户端软件的负载均衡算法&#xff0c;将Netflix的中间层服务连接在一起。Ribbon客户端组件提供…

好久没写过Qt了,写个Qt回味一下信号与槽

界面效果界面类.h#include <QtWidgets/qmainwindow.h>#include <QtWidgets/qwidget.h>#include <QtWidgets/qplaintextedit.h>#include <QtWidgets/qboxlayout.h>#include <QtWidgets/qlineedit.h>#include <QtWidgets/qpushbutton.h>//#p…

海思SD3403/SS928V100开发(7)mcp2515-SPI转CAN驱动开发

1. 前言 需求: 需要一路can进行收发 分析: 根据目前使用较多的方案是使用主控端SPI接口 接入MCP2515芯片进行CAN协议转换 硬件: MCP2515->SPI2->SS928 2. Uboot开发 2.1 pinmux复用配置 2.1.1 修改uboot参数表 路径: osdrv/tools/pc/uboot_tools/ SS928V100…

Linux用户和权限 —— 操作演示

Linux用户和权限——操作演示认知root用户用户、用户组管理查看权限控制修改权限控制- chmod修改权限控制- chownLinux系列&#xff1a; Linux基本命令 —— 操作演示 认知root用户 root用户(超级管理员) 无论是Windows、MacOS、Linux均采用多用户的管理模式进行权限管理。…

【5G RRC】NR测量事件介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…
最新文章