数据结构 - 2(顺序表10000字详解)

news2024/11/19 16:28:42

一:List

1.1 什么是List

在集合框架中,List是一个接口,继承自Collection。
在这里插入图片描述
Collection也是一个接口,该接口中规范了后序容器中常用的一些方法,具体如下所示:
在这里插入图片描述

Iterable也是一个接口,Iterable接口表示实现该接口的类是可以逐个元素进行遍历的,

站在数据结构的角度来看,List就是一个线性表,即n个具有相同类型元素的有限序列,在该序列上可以执行增删改查以及变量等操作。

List中常用的方法如下所示:

方法解释
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 < E> subList(int fromIndex, int toIndex)截取部分 list

1.2 List的使用

注意:List是个接口,并不能直接用来实例化。

如果要使用,必须去实例化List的实现类。在集合框架中,ArrayList和LinkedList都实现了List接口。

使用实例如下:

List<String> arrayList = new ArrayList<>(); // 使用ArrayList实现
List<Integer> linkedList = new LinkedList<>(); // 使用LinkedList实现

//添加元素
arrayList.add("Apple");
arrayList.add("Banana");
arrayList.add("Orange");

//添加元素
linkedList.add(10);
linkedList.add(20);
linkedList.add(30);

我们通过向上转型,分别调用了ArrayList和LinkedList中的add重写方法,这两个方法在ArrayList和LinkedList中都有自己的实现方式

二: ArrayList的使用

2.1 什么是线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列…

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

比如说:
在这里插入图片描述
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

2.2ArrayList简介

在这里插入图片描述
【说明】

  1. ArrayList是以泛型方式实现的,使用时必须要先实例化,并指定一下泛型参数
  2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
  4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
  5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者
    CopyOnWriteArrayList
  6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

2.3 ArrayList的使用

方法解释
ArrayList()无参构造
ArrayList(Collection<? extends E> c)利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity)指定顺序表初始容量

ArrayList(Collection<? extends E> c) 是一个构造函数,它接受一个实现了 Collection 接口的对象 c。这个构造函数会将 c 中的所有元素添加到新创建的 ArrayList 中。

通常情况下,ArrayList 是按照元素的添加顺序来存储的,而 ArrayList(Collection<? extends E> c) 可以方便地将另一个集合的元素全部添加到当前的 ArrayList 中。

例如,假设有一个 List 对象 list,可以使用如下代码创建一个新的 ArrayList,并将 list 中的所有元素添加到新的 ArrayList 中:

ArrayList<String> arrayList = new ArrayList<>(list);

在上述代码中,ArrayList<String> arrayList 是一个新创建的 ArrayList 对象,它包含了 list 中的所有元素。

注意:ArrayList(Collection<? extends E> c) 的泛型参数要与 ArrayList 的泛型参数类型一致或构成子类父类的关系,即它们需要是相同类型或者是其子类型。

2.4 ArrayList的常用方法

方法解释
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< E > subList(int fromIndex, int toIndex)截取部分 list

使用实例:

public static void main(String[] args) {
  List<String> list = new ArrayList<>();
  list.add("JavaSE");
  list.add("JavaWeb");
  list.add("JavaEE");
  list.add("JVM");
  list.add("测试课程");
  System.out.println(list);
 
  // 获取list中有效元素个数
  System.out.println(list.size());
 
  // 获取和设置index位置上的元素,注意index必须介于[0, size)间
  System.out.println(list.get(1));
  list.set(1, "JavaWEB");
  System.out.println(list.get(1));
 
  // 在list的index位置插入指定元素,index及后续的元素统一往后搬移一个位置
  list.add(1, "Java数据结构");
  System.out.println(list);
  
  // 删除指定元素,找到了就删除,该元素之后的元素统一往前搬移一个位置
  list.remove("JVM");
  System.out.println(list);
  
  // 删除list中index位置上的元素,注意index不要超过list中有效元素个数,否则会抛出下标越界异常
  list.remove(list.size()-1);
  System.out.println(list);
  
  // 检测list中是否包含指定元素,包含返回true,否则返回false
  if(list.contains("测试课程")){
    list.add("测试课程");
 }
 
  // 查找指定元素第一次出现的位置:indexOf从前往后找,lastIndexOf从后往前找
  list.add("JavaSE");
  System.out.println(list.indexOf("JavaSE"));
  System.out.println(list.lastIndexOf("JavaSE"));
 
  // 使用list中[0, 4)之间的元素构成一个新的SubList返回,但是和ArrayList共用一个elementData数组
  List<String> ret = list.subList(0, 4);
  System.out.println(ret);
 
  list.clear();
  System.out.println(list.size());
}

2.5 ArrayList的遍历

ArrayList 可以使用三方方式遍历:for循环+下标、foreach、使用迭代器

public static void main(String[] args) {
  List<Integer> list = new ArrayList<>();
  list.add(1);
  list.add(2);
  list.add(3);
  list.add(4);
  list.add(5);
  
  // 使用下标+for遍历
  for (int i = 0; i < list.size(); i++) {
    System.out.print(list.get(i) + " ");
 }
  System.out.println();
  
  // 借助foreach遍历
  for (Integer integer : list) {
    System.out.print(integer + " ");
 }
  System.out.println();

  //迭代器遍历
  Iterator<Integer> it = list.listIterator();
  while(it.hasNext()){
    System.out.print(it.next() + " ");
 }
  System.out.println();
}

下面我们讲解一下使用迭代器遍历的方式

迭代器是用于遍历集合(如列表、数组等)中的元素的一种接口。它提供了一种统一的方式来访问和处理集合中的元素,而不需要暴露集合的内部实现细节。

迭代器有以下几个主要的方法:

  • hasNext(): 检查迭代器中是否还有下一个元素,如果有则返回 true,否则返回 false
  • next(): 返回迭代器的下一个元素,并将迭代器的位置向后移动。
  • remove(): 从迭代器指向的集合中移除迭代器返回的最后一个元素。

使用迭代器,你可以按顺序访问集合中的每一个元素,而不需要知道集合的内部结构或者索引。这样可以提供更灵活和独立的遍历方式。

在这段代码中,Iterator<Integer> it = list.listIterator(); 这行代码的作用是创建一个整数类型的迭代器 it,并将其初始化为列表的迭代器。这样我们就可以使用 it 来遍历并访问列表中的元素。

while(it.hasNext()){
    System.out.print(it.next() + " ");
 }

在上述示例中,it.hasNext() 检查迭代器中是否还有下一个元素,如果有,则执行循环内部代码。it.next() 返回迭代器的下一个元素,并将迭代器的位置向后移动。你可以在循环内部处理当前元素,例如打印出来。

迭代器是一次性的,即只能从头到尾进行一次遍历。如果需要重新遍历集合,你需要重新创建一个新的迭代器。

注意:

  1. ArrayList最长使用的遍历方式是:for循环+下标 以及 foreach
  2. 迭代器是设计模式的一种,后序容器接触多了再给大家铺垫

2.6ArrayList的扩容机制

ArrayList是一个动态类型的顺序表,当我们向 Java 的 ArrayList 中添加元素时,ArrayList 会自动扩容,以容纳更多的元素。ArrayList 的扩容机制如下:

  1. 初始容量:每个 ArrayList 对象都有一个初始容量。在创建 ArrayList 对象时,如果没有指定初始容量大小,则默认为10。这意味着初始时 ArrayList 可以容纳最多10个元素。

  2. 操作次数:当我们向 ArrayList 中添加新元素时,ArrayList 会根据当前存储的元素数量和内部数组的长度进行判断。每次添加元素的操作都会增加 ArrayList 的操作次数。

  3. 扩容策略:当 ArrayList 的操作次数达到其内部数组长度时,就会触发扩容操作。ArrayList 的默认扩容因子是1.5倍,即每次扩容后的容量为当前容量的1.5倍。

  4. 数组拷贝:扩容时,ArrayList 会创建一个新的数组,将原有元素拷贝到新数组中。这个过程涉及到数组的创建和数据的拷贝,所以在扩容操作时可能会对性能产生一定的影响。

需要注意的是,扩容是一个相对耗时的操作,因为它涉及到数据的拷贝和存储空间的重新分配。因此,在知道需要存储大量元素的情况下,为 ArrayList 显式指定一个初始容量,可以减少扩容操作的次数,提高性能。

ArrayList 的扩容策略是在底层数组容量不足时,将当前容量乘以一个扩容因子来进行扩容。默认情况下,ArrayList 的扩容因子是 1.5 倍。

注意:ArrayList 的扩容因子是可调的,可以通过构造函数来指定。我们可以使用 ArrayList(int initialCapacity, float loadFactor) 构造函数来同时指定初始容量和扩容因子。

三:模拟实现一个ArrayList

3.1方法框架

public class SeqList {
  private int[] array;
  private int size;
  
  // 默认构造方法
  SeqList(){  }
  
  // 将顺序表的底层容量设置为initcapacity
  SeqList(int initcapacity){  }
  
  // 新增元素,默认在数组最后新增
  public void add(int data) { }
  
  // 在 pos 位置新增元素
  public void add(int pos, int data) { }
  
  // 判定是否包含某个元素
  public boolean contains(int toFind) { return true; }
  
  // 查找某个元素对应的位置
  public int indexOf(int toFind) { return -1; }
  
  // 获取 pos 位置的元素
  public int get(int pos) { return -1; }
  
  // 给 pos 位置的元素设为 value
  public void set(int pos, int value) {  }
  
  //删除第一次出现的关键字key
  public void remove(int toRemove) {  }
  
  // 获取顺序表长度
  public int size() { return 0; }
  
  // 清空顺序表
  public void clear() {  }
 
  // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
  public void display() {  }
}

3.2 模拟实现ArrayList

 class MyArrayList {
  private int[] array;
  private int size;

  // 默认构造方法
  public MyArrayList() {
    // 初始化底层数组,初始容量为10
    array = new int[10];
    // 初始大小为0
    size = 0;
  }

  // 将顺序表的底层容量设置为initCapacity
  public MyArrayList(int initCapacity) {
    if (initCapacity < 0) {
      throw new IllegalArgumentException("容量不能小于0");
    }
    // 初始化底层数组,初始容量为initCapacity
    array = new int[initCapacity];
    // 初始大小为0
    size = 0;
  }

  // 在数组最后新增元素
  public void add(int data) {
    // 如果数组已满,则扩容
    if (size == array.length) {
      resize();
    }
    // 在数组末尾新增元素
    array[size] = data;
    // 更新大小
    size++;
  }

  // 在指定位置新增元素
  public void add(int pos, int data) {
    // 检查位置是否合法
    if (pos < 0 || pos > size) {
      throw new IndexOutOfBoundsException("索引超出范围");
    }
    // 如果数组已满,则扩容
    if (size == array.length) {
      resize();
    }
    // 将指定位置及其后面的元素后移一位
    for (int i = size - 1; i >= pos; i--) {
      array[i + 1] = array[i];
    }
    // 在指定位置插入元素
    array[pos] = data;
    // 更新大小
    size++;
  }

  // 判定是否包含某个元素
  public boolean contains(int toFind) {
    // 遍历数组查找元素
    for (int i = 0; i < size; i++) {
      if (array[i] == toFind) {
        return true;
      }
    }
    return false;
  }

  // 查找某个元素对应的位置
  public int indexOf(int toFind) {
    // 遍历数组查找元素
    for (int i = 0; i < size; i++) {
      if (array[i] == toFind) {
        return i;
      }
    }
    // 未找到元素,返回-1
    return -1;
  }

  // 获取指定位置的元素
  public int get(int pos) {
    // 检查位置是否合法
    if (pos < 0 || pos >= size) {
      throw new IndexOutOfBoundsException("索引超出范围");
    }
    // 返回指定位置的元素
    return array[pos];
  }

  // 设置指定位置的元素
  public void set(int pos, int value) {
    // 检查位置是否合法
    if (pos < 0 || pos >= size) {
      throw new IndexOutOfBoundsException("索引超出范围");
    }
    // 更新指定位置的元素
    array[pos] = value;
  }

  // 删除第一次出现的指定元素
  public void remove(int toRemove) {
    // 遍历数组查找要删除的元素
    for (int i = 0; i < size; i++) {
      if (array[i] == toRemove) {
        // 将要删除元素后面的元素前移一位
        for (int j = i + 1; j < size; j++) {
          array[j - 1] = array[j];
        }
        // 更新大小
        size--;
        return;
      }
    }
  }

  // 获取顺序表长度
  public int size() {
    return size;
  }

  // 清空顺序表
  public void clear() {
    // 将数组清空
    for (int i = 0; i < size; i++) {
      array[i] = 0;
    }
    // 大小置为0
    size = 0;
  }

  // 扩容数组
  private void resize() {
    // 创建新的数组,长度为当前容量的两倍
    int[] newArray = new int[array.length * 2];
    // 将原数组中的元素复制到新数组中
    for (int i = 0; i < size; i++) {
      newArray[i] = array[i];
    }
    // 更新底层数组
    array = newArray;
  }

  // 打印顺序表
  public void display() {
    // 遍历数组打印元素
    for (int i = 0; i < size; i++) {
      System.out.print(array[i] + " ");
    }
    System.out.println();
  }
}

这是一个自定义的MyArrayList类,模拟实现了一个动态数组。以下是每个功能的解释:

  • 构造方法:使用默认构造方法创建一个初始容量为10的数组,并将大小初始化为0。使用带有参数的构造方法可以设置初始容量。
  • add方法:在数组最后新增元素,如果数组已满,则扩容。
  • add方法(重载):在指定位置新增元素,如果数组已满,则扩容。为了将指定位置的元素后移,我们需要从后往前遍历数组。
  • contains方法:遍历数组查找是否包含某个元素,如果找到则返回true,否则返回false
  • indexOf方法:遍历数组查找某个元素对应的位置,如果找到则返回元素的索引,否则返回-1。
  • get方法:获取指定位置的元素,如果位置合法则返回元素,否则抛出IndexOutOfBoundsException异常。
  • set方法:设置指定位置的元素,如果位置合法则更新元素值,否则抛出IndexOutOfBoundsException异常。
  • remove方法:删除第一次出现的指定元素,将后面的元素前移一位,并更新大小。
  • size方法:获取顺序表的长度,即元素的个数。
  • clear方法:清空顺序表,将数组

3.3 测试功能

接着我们再写一个测试类,用于测试功能:

public class Main {
    public static void main(String[] args) {
        MyArrayList list = new MyArrayList();

        // 测试默认构造方法
        System.out.println("测试默认构造方法:");
        System.out.println("顺序表是否为空:" + (list.size() == 0));
        System.out.println("顺序表的大小:" + list.size());
        list.display();

        // 测试 add 方法
        System.out.println("\n测试 add 方法:");
        list.add(1);
        list.add(2);
        list.add(3);
        list.display();

        // 测试 add(pos, data) 方法
        System.out.println("\n测试 add(pos, data) 方法:");
        list.add(1, 5);
        list.display();

        // 测试 contains 方法
        System.out.println("\n测试 contains 方法:");
        System.out.println("顺序表中是否包含元素 2:" + list.contains(2));
        System.out.println("顺序表中是否包含元素 4:" + list.contains(4));

        // 测试 indexOf 方法
        System.out.println("\n测试 indexOf 方法:");
        System.out.println("元素 2 在顺序表中的位置:" + list.indexOf(2));
        System.out.println("元素 4 在顺序表中的位置:" + list.indexOf(4));

        // 测试 get 方法
        System.out.println("\n测试 get 方法:");
        System.out.println("位置 2 上的元素:" + list.get(2));

        // 测试 set 方法
        System.out.println("\n测试 set 方法:");
        list.set(1, 4);
        list.display();

        // 测试 remove 方法
        System.out.println("\n测试 remove 方法:");
        list.remove(2);
        list.display();

        // 测试 size 方法
        System.out.println("\n测试 size 方法:");
        System.out.println("顺序表的大小:" + list.size());

        // 测试 clear 方法
        System.out.println("\n测试 clear 方法:");
        list.clear();
        list.display();
        System.out.println("顺序表是否为空:" + (list.size() == 0));
    }
}
  • 运行结果如下:

    测试默认构造方法: 顺序表是否为空:true 顺序表的大小:0
    
    
    测试 add 方法: 1 2 3 
    
    测试 add(pos, data) 方法: 1 5 2 3 
    
    测试 contains 方法: 顺序表中是否包含元素 2:true 顺序表中是否包含元素 4:false
    
    测试 indexOf 方法: 元素 2 在顺序表中的位置:2 元素 4 在顺序表中的位置:-1
    
    测试 get 方法: 位置 2 上的元素:2
    
    测试 set 方法: 1 4 2 3 
    
    测试 remove 方法: 1 4 3 
    
    测试 size 方法: 顺序表的大小:3
    
    测试 clear 方法:
    
    顺序表是否为空:true
    

可见输出都符合我们的预期,说明我们模拟实现的ArrayList在功能上是完好的,并且没有什么缺陷。

四:ArrayList的问题及思考

  1. ArrayList底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继
    续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

所以应该使用 ArrayList 的场景包括:

  1. 需要频繁进行随机访问的场景。

不应该使用 ArrayList 的场景包括:

  1. 需要频繁进行插入和删除操作,并对性能要求较高的场景。

  2. 列表中的元素数量比较少,可能造成内存浪费的场景。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

security+JWT

securityJWT 添加依赖准备工作sqlUserInfoUserMapperUserService、UserServiceImpl 创建JwtUtils工具类&#xff0c;做token的生成和校验进入Security创建AccountDetailsServiceImpl&#xff0c;并且实现UserDetailsService编写登录操作 创建拦截器JWTAuthenticationFilter继承…

mac电影特效合成软件nuke15 完美激活版下载

Nuke 15是一款由英国The Foundry公司开发的专业的合成软件&#xff0c;被广泛用于电影、电视和广告制作中的后期合成和特效制作。 Mac软件下载&#xff1a;nuke15 完美激活版下载 Win软件下载&#xff1a;NUKE 13 中文激活版 Nuke 15拥有强大的功能和灵活性&#xff0c;可以帮助…

TartanVO: A Generalizable Learning-based VO 服务器复现(rtx3090 py3)

源码地址 代码地址&#xff1a;https://github.com/castacks/tartanvo/tree/python3 配环境 git clone https://github.com/castacks/tartanvo.git -b python3创建conda环境&#xff1a; conda create -n tartanvo python3.8安装pytorch conda install pytorch1.10.1 torc…

路由router

什么是路由? 一个路由就是一组映射关系&#xff08;key - value&#xff09;key 为路径&#xff0c;value 可能是 function 或 component 2、安装\引入\基础使用 只有vue-router3&#xff0c;才能应用于vue2&#xff1b;vue-router4可以应用于vue3中 这里我们安装vue-router3…

elementUI el-table+树形结构子节点选中后没有打勾?(element版本问题 已解决)

问题 1.不勾选父级CB111&#xff0c;直接去勾选子级&#xff08;ST2001…&#xff09;&#xff0c;子级选中后没有打勾显示 排查 一直以为是这个树形结构和表格不兼容产生的问题&#xff0c;到后来看官方demo都是可以勾选的&#xff0c;最后排查到了版本问题&#xff0c; 项…

电动滑板车UL2272认证测试项目和标准

平衡车ul2272认证标准于2016年2月正式公布&#xff0c;美国消费品安全协会(cpsc)宣布&#xff0c;所有平衡车(包括扭扭车)的制造商、进口商、经销商&#xff0c;其在美国本土生产、进口、销售的平衡车必须符合新的安全标准&#xff0c;包括ul2272平衡车电路系统认证标准。另外&…

flutter开发入门,windows环境安装,耗时一天解决各种bug,终于成功

首先说明要安装的环境&#xff1a;java8必须&#xff0c;android studio&#xff0c;chrome是开发安卓和web是必须的 java8的下载地址&#xff1a;https://www.java.com/en/download/、 java8蓝奏云下载地址&#xff1a;jre-8u381-windows-x64.exe - 蓝奏云 flutter国内环境…

lvgl 界面管理器

lv_scr_mgr lvgl 界面管理器 适配 lvgl 8.3 降低界面之间的耦合使用较小的内存&#xff0c;界面切换后会自动释放内存内存泄漏检测 使用方法 在lv_scr_mgr_port.h 中创建一个枚举&#xff0c;用于界面ID为每个界面创建一个页面管理器句柄将界面句柄添加到 lv_scr_mgr_por…

C++11新特性(lambda,可变参数模板,包装器,bind)

lambda表达式是什么&#xff1f;包装器又是什么&#xff1f;有什么作用&#xff1f;莫急&#xff0c;此篇文章将详细带你探讨它们的作用。很多同学在学习时害怕这些东西&#xff0c;其实都是方便使用的工具&#xff0c;很多情况下我们学这些新的东西觉得麻烦&#xff0c;累赘&a…

自学嵌入式多久才可以达到找工作的水平

自学嵌入式多久才可以达到找工作的水平 时间以及达到嵌入式工作水平所需的具体努力因人而异。但一般而言&#xff0c;自学嵌入式系统开发需要时间和毅力。以下是一些关键因素&#xff0c;影响着您能够在多久内达到找工作的水平&#xff1a;最近很多小伙伴找我&#xff0c;说想要…

YOLOv4 论文总结

贡献&#xff1a; 1.有效且强大的模型&#xff0c;常规GPU&#xff08;1080ti or 2080ti&#xff09;可得到实时、高质量的检测结果。 2.在训练中&#xff0c;验证 Bag-of-Freebies 和 Bag-of-Specials 方法 3.提出了两种数据增强手段&#xff0c;马赛克和自对抗训练&#x…

LeetCode【74】搜索二维矩阵

题目&#xff1a; 代码&#xff1a; public static boolean searchMatrix(int[][] matrix, int target) {int rows matrix.length;int columns matrix[0].length;// 先找到行&#xff0c;行为当前行第一列<target&#xff0c;当前行1行&#xff0c;第一列>targetfor…

详细教程:Postman 怎么调试 WebSocket

WebSocket 是一个支持双向通信的网络协议&#xff0c;它在实时性和效率方面具有很大的优势。Postman 是一个流行的 API 开发工具&#xff0c;它提供了许多功能来测试和调试 RESTful API 接口&#xff0c;最新的版本也支持 WebSocket 接口的调试。想要学习更多关于 Postman 的知…

Linux友人帐之环境变量

一、环境变量 1.1 环境变量的概念 1. 什么是环境变量&#xff1f; 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。 2. 为什么会有环境变量&#xff1f; 在Linux系统中&#xff0c;我们发现我们在执行一些指令时&#xff0c;比如…

10个打工人必备AI神器,升职加薪靠AI

HI&#xff0c;同学们&#xff0c;我是赤辰&#xff0c;本期是第18篇AI工具类教程&#xff0c;文章底部准备了粉丝福利&#xff0c;看完后可领取&#xff01;1. Runway&#xff08;文字转视频AI工具&#xff09; 只需要一句提示词就能精确生成你所想象的视频场景&#xff0c;还…

natapp内网穿透-将本地运行的程序/服务器通过公网IP供其它人访问

文章目录 1.几个基本概念1.1 局域网1.2 内网1.3 内网穿透1.4 Natapp 2.搭建内网穿透环境3.本地服务测试 1.几个基本概念 1.1 局域网 LAN&#xff08;Local Area Network&#xff0c;局域网&#xff09;是一个可连接住宅&#xff0c;学校&#xff0c;实验室&#xff0c;大学校…

百乐钢笔维修(官方售后,全流程)

文章目录 1 背景2 方法3 结果 1 背景 在给钢笔上墨的途中&#xff0c;不小心总成掉地上了&#xff0c;把笔尖摔弯了&#xff08;虽然还可以写字&#xff0c;但是非常的挂纸&#xff09;&#xff0c;笔身没有什么问题&#xff0c;就想着维修一下笔尖或者替换一下总成。 一般维…

Vulnhub系列靶机---Raven: 2

文章目录 信息收集主机发现端口扫描目录扫描用户枚举 漏洞发现漏洞利用UDF脚本MySQL提权SUID提权 靶机文档&#xff1a;Raven: 2 下载地址&#xff1a;Download (Mirror) 信息收集 靶机MAC地址&#xff1a;00:0C:29:15:7F:17 主机发现 sudo nmap -sn 192.168.8.0/24sudo arp…

操作系统中的(进程,线程)

操作系统是一个搞管理的软件&#xff0c;它对上给各个应用程序提供稳定的运行环境&#xff1b;对下管理各种硬件设备。 进程 一个操作系统由内核和配套的应用程序组成。而进程就是操作系统内核中众多关键概念中的一个。进程通俗一点来讲就是一个已经跑起来的程序。 每个进程…

【数据结构与算法】二叉树的镜像实现

需求分析&#xff1a; 将所有节点的左子树与右子树交换&#xff0c;以达到交换前与交换后成为镜像的效果。 如图&#xff1a; 实现代码&#xff1a; 先准备一个二叉树具有节点类&#xff0c;添加左右子节点的方法和层序遍历方法。 /*** author CC* version 1.0* since2023/10…