IO进程及相关函数

news2024/7/6 19:09:15

什么是环境变量

http://t.csdnimg.cn/nPrMu

进程:是程序执行的一次执行过程,是动态,涉及到资源分配,包含创建、调度、执行
程序:存放在磁盘空间上的一个二进制文件,是指令集合,是静态的,没有执行的过程

进程内存三个段:正文、数据、堆栈
进程分类:交互进程、守护进程、批处理进程
进程状态:

进程是资源分配的最小单位,线程是cpu调度的最小单位
创建进程:pid_t pid = fork();
退出进程:exit(0) 刷新缓存区 
        _exit(0) 不刷新缓存区
回收进程资源:
    wait(NULL)父进程使用

一、进程概念

程序:编译好的可执行二进制文件,存放在磁盘上的指令和数据的有效集合,是静态的,没有任何执行的概念。a.out

进程:独立的可调度的任务,是执行一个程序所分配资源的总称,是程序的一次执行过程,是动态的,包括创建、调度、执行和消亡。./a.out按下回车的那一刻开始。

二、进程和程序的区别

程序:编译好的可执行的二进制文件

存放在磁盘上的指令和数据的有序集合(文件)

   程序是静态的,没有任何执行的概念

 进程:一个独立的可调度的任务

  执行一个程序所分配的资源的总称

  进程是程序的一次执行过程

  进程是动态的,包括创建、调度、执行和消亡

三、进程包含三个段:

  1. 系统会为每一个进程分配0-4g的虚拟空间,0-3g(用户空间)是每个进程所独有的,3g-4g(内核空间)是所有进程共有的。

2.CPU调度进程时会给进程分配时间片(几毫秒~十几毫秒),当时间片用完后,cpu再进行其他进程的调度,实现进程的轮转,从而实现多任务的操作

1)“数据段”存放的是全局变量、常数,static修饰的变量等。

2)“正文段”存放的是程序中的代码

3)“堆栈段”存放的是函数的返回地址、函数的参数以及程序中的局部变量,malloc开辟的内存空间。

3.进程的内存管理(如内存管理图)

1. 每个进程都分配4G虚拟内存空间

2. 0G~3G 是用户空间-属于进程私有空间, 3G~4G 是内核空间-所有进程公用空间

3. 3G~4G 是所有进程共享的

     (mmu:内存管理单元,虚拟机只有mmu能操作物理地址,管理用户使用的物理地址其他用户将不能在获取使用)

代码段、数据段、bss段、只读数据段、堆段、栈段(都占用自己的虚拟地址并映射相应的物理地址)

4.进程是程序执行和资源管理的最小单位。

    包含的的资源有:物理内存、文件描述符、虚拟地址 0G~4G、CPU时间片、进程号 (PID唯一标识一个进程)

五、进程的类型:

1)交互进程:交互进程既可以在前台运行,也可以在后台运行。该类进程经常与用户进行交互,需要等待用户的输入,当接收到用户的输入后,该类进程会立刻响应。

2)批处理进程:该类进程不属于某个终端,它被提交到一个队列中以便顺序执行

3)守护进程:该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束。 

六、进程的运行状态:

1)  运行态:此时进程或者正在运行,或者准备运行。

2)  等待态:此时进程在等待一个事件的发生或某种系统资源。

可中断:处在这种状态下的进程可以被信号中断,接收到信号或被显示地唤醒呼叫,唤醒之后,进程将转变为运行态。

不可中断:它不会处理信号,只有在它所等待的事件发生时,进程才被显示的唤醒

3)停止态:此时进程被中止。

4)死亡态:这是一个已终止的进程,但还在进程向量数组中占有一个task_struct结构。

5)僵尸态(TASK_ZOMBIE):Z 

当进程已经终止运行,但还占用系统资源,要避免僵尸态的产生

D    uninterruptible sleep (usually IO)(不可中断的等待态)
R    running or runnable (on run queue)(运行态)
S    interruptible sleep (可中断的等待态)
T    stopped, either by a job control signal or because it is
            being traced.(停止态)
X    dead (should never be seen)(死亡态)
Z    defunct ("zombie") process, terminated but not reaped by its
            parent.(僵尸态)

For BSD formats and when the stat keyword is used, additional
characters may be displayed:(对于BSD格式,当使用stat关键字时,可能会显示额外的字符:
   <    high-priority (not nice to other users)(高优先级)
   N    low-priority (nice to other users)(低优先级)
   s    is a session leader(会话组组长)
	       多个进程可以组成一个组,多个组可以组成一个会话。
		   多个会话可以组成一个会话组。
   l    is multi-threaded (线程)
   +    is in the foreground process group.(前台)
			空:表示后台  

七、进程状态切换图

进程创建后,进程进入就绪态,当CPU调度到此进程时进入运行态,当时间片用完时,此进程会进入就绪态,如果此进程正在执行一些IO操作(阻塞操作)会进入阻塞态,完成IO操作(阻塞结束)后又可进入就绪态,等待CPU的调度,当进程运行结束即进入结束态。

Ctrl+z:将前台运行的进程暂停同时放到后台

bg 数字(这里的数字为你按Ctrl+Z的时候前面中括号里面的数字):将后台暂停的进程在后台跑起来。

fg 数字(这里的数字为你按Ctrl+Z的时候前面中括号里面的数字) :将后台运行的进程拉到前台运行     

jobs:查看后台所有的进程

  • 八、创建进程函数:

1、fork 创建一个子进程

 #include <unistd.h>
 pid_t fork(void);
 功能:创建一个子进程
 参数:无
 返回值:
    成功:在父进程中:返回子进程的进程号(PID) >0
         在子进程中:返回值为0
    失败:-1并设置errno,进程创建失败
父进程 PPID 子进程 PID

子进程PID可以是除1(ROOT进程)以外任何PID号

父子进程执行顺序是随机

#include<stdio.h>
#include<unistd.h>
int main(int argc, char const *argv[])
{
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork err");
        return -1;
    }
    else if(pid == 0)
    {
        printf("this is child.\n");
    }
    else
    {
        printf("this is father.\n");
    }
    
    return 0;
}

2、fork创建子进程的特点:

1.fork创建一个子进程,父进程返回子进程的pid,进程中返回0.
   如果父进程退出,子进程没有退出,子进程会变成孤儿进程被init进程收养。
   如果子进程退出,父进程没有退出,父进程没有回收子进程资源,子进程会变成僵尸进程。
2.fork创建的子进程几乎拷贝了父进程所有的内容(三个段:堆栈、数据、代码,没有被拷贝的内容:pid、 ppid、cpu等),fork之前的代码被复制并不会被执行,fork之后的代码被复制并执行。
3.fork创建进程一旦成功,进程之间的空间就相会独立。各自分配0-4G的虚拟内存空间。
4.fork创建进程之前打开的文件可以通过复制拿到同一个文件描述符操作同一个文件(同一个文件指针)。

写时拷贝

由于之前的fork完整地拷贝了父进程的整个地址空间,因此执行速度是比较慢的。为了提高效率,Unix系统设计者创建了现代unix版的fork。现代unix版的fork也创建新进程,但不产生父进程的副本。它通过允许父子进程可访问相同物理内存从而伪装了对进程地址空间的真实拷贝,当子进程需要改变内存中数据时才拷贝父进程。这就是著名的"写操作时拷贝"(copy-on-write)技术 

特点验证:(ps -ef查看父子进程)

1)子进程几乎拷贝了父进程的全部内容。包括代码、数据、缓冲区、系统数据段中的pc值、栈中的数据、父进程中打开的文件等;但它们的PID、PPID是不同的。

2)父子进程有独立的地址空间,互不影响;当在相应的进程中改变全局变量、静态变量,都互不影响.

3)fork之前代码会被复制,但是不会重新执行一遍;fork之后的代码,会被复制并且分别执行一遍。

4)若父进程先结束,子进程成为孤儿进程,被init进程收养,子进程变成后台进程。

init进程PPID为1(因为显示孤儿进程所以存在图像处理所以孤儿进程父进程PPID不为1)

5)若子进程先结束,父进程如果没有及时回收,子进程变成僵尸进程(要避免僵尸进程产生)

6)fork父子进程哪个先执行没有顺序,vfork:先执行完子进程再执行父进程

7)fork创建进程之前打开的文件可以通过复制拿到同一个文件描述符操作同一个文件(同一个文件指针)。也能操作文件内同一个指针。

  • 九、进程退出函数 exit  _exit

#include <stdlib.h>
   void exit(int status);
    功能:退出进程
    参数:status:退出进程的状态,exit(0):正常退出,非零状态码表示异常退出
    返回值:无
一旦调用了 exit() 函数,程序将立即终止,之后的代码将不再执行。

 #include <unistd.h>
   void _exit(int status);
    功能:退出进程
	 参数:status:退出进程的状态
	 返回值:无

    exit退出进程会刷新缓存区,_exit退出进程不刷新缓存区

十、回收进程资源 wait  waitpid

1、wait
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
功能:阻塞等待子进程退出回收子进程资源 (父进程中使用)
    阻塞父进程,等待子进程结束
参数:
    ①status作为一个整形值,用来保存子进程退出时的状态;
    ②如果status为NULL,表示忽略子进程退出时的状态;
    ③如果status不为空,wait函数会将子进程退出的状态存入status中,另外,子进程退出时的状态可以通过linux中的特定的宏(macro)来进一步测定退出状态
返回值:	  
    成功:退出进程的进程号
    失败:-1

练习:   1. 通过父子进程完成文件io对文件的拷贝cp,父进程从文件开始到文件的一半开始拷贝,子进程从文件的一半到文件末尾。 

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <strings.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
    if (argc < 2)
    {
        printf("input err");
        return -1;
    }
    int fd = open(argv[1], O_RDONLY);
    if (fd < 0)
    {
        perror("open err");
    }
    int fd2 = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0777);
    if (fd < 0)
    {
        perror("open err");
    }
    char buf[32] = "";
    int ret;
    int num = lseek(fd, 0, SEEK_END);
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork err");
        return -1;
    }
    else if (pid == 0) //子进程复制后一半
    {
        lseek(fd,num/2,SEEK_SET);
        lseek(fd2,num/2,SEEK_SET);
        while (ret = read(fd, buf, 1))
        {
            write(fd2, buf, ret);
        }
        exit(-1);
    }
    else //父进程
    {
        wait(NULL);//阻塞等待子进程退出回收子进程资源
        lseek(fd,0,SEEK_SET);
        lseek(fd2,0,SEEK_SET);
        int n=num/2;
        // for(int i=num/2;i>0;i--)//读一个写一个
        // {
        //     read(fd, buf, 1);
        //     write(fd2, buf, 1);
        // }
        while (n)
        {
            if(n>sizeof(buf))
            {
                ret = read(fd,buf,sizeof(buf));
            }
            else
            {
                ret = read(fd,buf,n);
            }
            write(fd2,buf,ret);
            n=n-ret;
        }
        exit(0);
    }
    close(fd);
    close(fd2);
    return 0;
}

#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
功能:回收子进程资源
参数:
    pid:>0     指定子进程进程号
         =-1   任意子进程
         =0    等待其组ID等于调用进程的组ID的任一子进程
         <-1   等待其组ID等于pid的绝对值的任一子进程
    status:子进程退出状态
    options:0:阻塞
        	   WNOHANG:非阻塞
返回值:正常:结束的子进程的进程号
      当使用选项WNOHANG且没有子进程结束时:0
      出错:-1
二者关系:wait(NULL);==waitpid(-1,NULL,0);
子进程状态发生改变,会给父进程发送一个信号叫SIGCHLD信号

十一、获取进程pid和父进程ppid(getpid,getppid)

永远会成功的函数:
       #include <sys/types.h>
       #include <unistd.h>
       pid_t getpid(void);
   功能:获取当前进程的进程号


       #include <sys/types.h>
       #include <unistd.h>
       pid_t getppid(void); 
   功能:获取当前进程的父进程号

十二、交互进程 bg fg

进程命令:
    ps --
    ps -aux   查看进程相关信息
    ps -ef    查看进程的父进程
    ps -ajx   查看进程父进程id、组id、会话id、会话组id
              多个进程组成一个组
			    多个组组成一个会话
			    多个会话组成一个会话组     
     top   动态显示进程状态
	  nice  / renice
     kill   --》kill -l 查看有哪些信号
	  kill -num  PID 
ctrl +z 暂停进程
前后台进程切换的命令:
     查看终端有那些作业:用jobs命令
	 
    bg  将挂起的进程在后台执行
		bg 编号  [1]作业号
		bg $作业号
	fg  把后台运行的进程放到前台运行
		fg 编号
    ./a.out &  将a.out在后台运行起来
   给后台的作业发送信号:
      kill -num %作业号

Ctrl+z:将前台运行的进程暂停同时放到后台

bg 数字(这里的数字为你按Ctrl+Z的时候前面中括号里面的数字):将后台暂停的进程在后台跑起来。

fg 数字(这里的数字为你按Ctrl+Z的时候前面中括号里面的数字) :将后台运行的进程拉到前台运行     

jobs:查看后台所有的进程

十三、守护进程创建步骤

  1. 特点

守护进程是后台进程;生命周期比较长,从系统启动时开启,系统关闭时结束;它是脱离控制终端且周期执行的进程。

2.步骤

1) 创建子进程,父进程退出

让子进程变成孤儿进程,成为后台进程;fork()

2) 在子进程中创建新会话

让子进程成为会话组组长,为了让子进程完全脱离终端;setsid()

会话组(班长)--》进程组(组长)

3) 改变进程运行路径为根目录

原因进程运行的路径不能被删除或卸载;chdir("/")

4) 重设文件权限掩码

目的:增大进程创建文件时权限,提高灵活性;umask(0)

mode &(~umask)想要相与之后的结果最大,最大为自己设置的mode值,任意一个数与全为1的数相与,能得到本身,所以就要求(~umask)最大777,那(umask)最小000

5) 关闭文件描述符

将不需要的文件关闭;close()

1.创建一个子进程,让父进程退出
    目的:让子进程变成孤儿进程,被Init 进程收养,变成后台进程
    fork();
2.设置进程为会话组组长
    多个进程组成一个组,多个组组成一个会话,多个会话组成一个会话组
    目的:脱离终端
    setsid();
3.修改程序的执行路径到根目录
    chdir();
4.重设权限掩码 umask 0022
    umask();
5.关闭文件(释放多余文件资源)
    close();
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork err");
        return -1;
    }
    else if (pid == 0)
    {
        setsid(); //设置会话组组长
        chdir("/");//修改程序的执行路径到根目录
        umask(0022); //0777 &(0022)==0755,重设权限掩码 umask
        for (int i = 0; i < 3; i++)
        {
            close(i);
        }
        int fd = open("./a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0777);

        while (1)
        {
            sleep(1);
            write(fd, "hello world\n", 12);
        }
    }
    else
    {
        exit(0);
    }
    return 0;
}

十四、exec函数族

在一个进程中执行另外的进程

    man 3  exec

1.概念:

exec函数族提供了一种在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段。在执行完之后,原调用进程的内容除了进程号外,其他全部都被替换了。

2.何时使用exec?

     1)当进程认为自己不能再为系统和用户做出任何贡献了时就可以调用exec函数,让自己执行新的程序

     2)如果某个进程想同时执行另一个程序,它就可以调用fork函数创建子进程,然后在子进程中调用任何一个exec函数。这样看起来就好像通过执行应用程序而产生了一个新进程一样

#include <unistd.h>
int execl(const char *path, const char *arg, ...
                       /* (char  *) NULL */);
int execlp(const char *file, const char *arg, ...
                       /* (char  *) NULL */);
int execle(const char *path, const char *arg, ...
                       /*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);

l : list列表,参数要以列表形式,展现出来。

p : path路径,从系统环境变量中去找可执行文件

v : 向量数组,将列表的参数装到数组中去。

e :  函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环 境。envp也是一个以NULL结尾的字符串数组指针

3.使用区别:

    1)可执行文件查找方式

无p:指定完整的文件目录路径,

有p:只给出文件名,系统会自动从环境变量“$PATH”所包含的路径中进行查找。

    2)参数表传递方式

有l:表示逐个列举的方式;

有v:表示将所有参数构造成指针数组传递,其语法为char *const argv[]

    3)环境变量的使用

exec函数族可以默认使用系统的环境变量,也可以传入指定的环境变量。

这里,以“e”(Enviromen)结尾的两个函数execle、execve就可以在envp[]中传递

   当前进程所使用的环境变量,一般为NULL即可

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

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

相关文章

MacOS系统Chrome开发者模式下载在线视频

操作流程 # step1. 进入开发者模式 command option i # step2. 在搜索栏中搜索 getHttpVideoInfo.do?关键词 # step3. 在Preview的Json界面中找到video&#xff0c;然后选择不同resolution & duration的视频片段&#xff1b; # step4. 选择合适的video::chapters, 选择…

【鸿蒙软件开发】ArkTS基础组件之Marquee(文字跑马灯)、QRCode(二维码生成)

文章目录 前言一、Marquee组件1.1 子组件1.2 创建Marquee组件参数 1.3 属性1.4 事件1.5 示例代码 二、QRCode2.1 子组件2.2 接口2.3 参数2.4 属性2.5 事件2.6 示例代码 总结 前言 Marquee组件&#xff1a;跑马灯组件&#xff0c;用于滚动展示一段单行文本&#xff0c;仅当文本…

python+requests接口自动化测试框架

1、首先&#xff0c;我们先来理一下思路。 正常的接口测试流程是什么&#xff1f; 脑海里的反应是不是这样的&#xff1a; 确定测试接口的工具 —> 配置需要的接口参数 —> 进行测试 —> 检查测试结果&#xff08;有的需要数据库辅助&#xff09; —> 生成测试报…

算法通关村第三关-白银挑战双指针思想

大家好我是苏麟 , 今天带来算法第三关 . 本期大纲 元素奇偶移动专题 元素奇偶移动专题 描述 : 给你一个整数数组 nums&#xff0c;将 nums 中的的所有偶数元素移动到数组的前面&#xff0c;后跟所有奇数元素。 返回满足此条件的 任一数组 作为答案。 题目 : LeetCode 905.…

成人自考-英语二-连词

感谢内容提供者&#xff1a;金牛区吴迪软件开发工作室 接上一篇&#xff1a;成人自考-英语二-形容词 文章目录 一、连词分类1.并列连词-连接词与词、句与句&#xff08;1&#xff09;词 并列连词 词&#xff08;2&#xff09;句子1 并列连词 句子2 2.从属连词-连接从句&…

私有化部署企业IM即时通讯app,群聊多样化管控

随着企业内部沟通和协作的重要性不断增长&#xff0c;私有化部署企业即时通讯&#xff08;IM&#xff09;app成为了企业保护内部信息安全的一种重要手段。在这个领域&#xff0c;安全专属的移动数字化平台WorkPlus&#xff0c;支持私有化部署&#xff0c;涵盖即时通讯和办公应用…

保姆级认识AVL树【C++】(精讲:AVL Insert)

目录 前言 一&#xff0c;概念 二&#xff0c;定义 三&#xff0c;insert 1. 插入情况 情况一&#xff1a; 情况二&#xff1a; 情况三&#xff1a; 2. 旋转方法 法一&#xff1a;左单旋法 法二&#xff1a;右单旋法 法三&#xff1a;先左后右双旋法 法四&#xf…

67 内网安全-域横向smbwmi明文或hash传递

#知识点1: windows2012以上版本默认关闭wdigest&#xff0c;攻击者无法从内存中获取明文密码windows2012以下版本如安装KB2871997补丁&#xff0c;同样也会导致无法获取明文密码针对以上情况&#xff0c;我们提供了4种方式解决此类问题 1.利用哈希hash传递(pth&#xff0c;ptk等…

递归为什么这么难?一篇文章带你了解递归

递归为什么这么难&#xff1f;一篇文章带你了解递归 美国计算机科学家——彼得多伊奇(L Peter Deutsch)在《程序员修炼之道》(The Pragmatic Programmer)一书中提到“To Iterate is Human, to Recurse, Divine”——我理解的这句话为&#xff1a;人理解迭代&#xff0c;神理解…

电脑下载视频号视频:微信视频号如何下载到电脑桌面上?

很多人做视频的时候需要将视频号的视频下载到电脑上&#xff0c;该如何操作呢&#xff1f;接下来我们通过电脑下载视频号视频希望对大家有所帮助。 方法一&#xff1a;使用在线视频下载网站 有一些在线视频下载网站可以帮助你从视频号上下载视频到电脑。你只需将视频的链接复制…

三个禁止使用U盘的方案

三个禁止使用U盘的方案 安企神U盘管理系统下载使用 U盘是一种小型便携式的存储设备&#xff0c;可以方便地传输和存储各种类型的数据&#xff0c;但也因此带来了一些安全隐患。在一些特殊的场合&#xff0c;如公司、商业场地等&#xff0c;为了保护内部数据被盗取外泄&#x…

怎么才能写好宣传软文?媒介盒子为你揭秘

数字化时代改变了企业的宣传方式&#xff0c;软文成为企业宣传的主要方式&#xff0c;但是企业真的会写宣传软文吗&#xff1f;为什么宣传软文不起效果&#xff1f;下面媒介盒子先和大家分享宣传软文的写作技巧 一、为什么要宣传 企业为什么需要宣传&#xff0c;主要有三类情况…

JS实现商品SKU

<!DOCTYPE html> <html> <head><title>商品SKU</title><link rel"stylesheet" href"element/css/element.css"><style>*{ margin:0; padding:0px; box-sizing: border-box; }ul,li{ list-style-type: none;}bod…

Python武器库开发-高级特性篇(八)

高级特性篇(八) 高阶函数 Python作为一门高级编程语言&#xff0c;拥有着强大的函数式编程能力。其中高阶函数就是Python函数式编程的重要组成部分。在Python中&#xff0c;函数可以被当作变量一样进行操作&#xff0c;包括作为参数传递给其他函数&#xff0c;或者作为返回值…

DBSCAN算法c++实现

首先计算出距离每个点e以内的点&#xff0c;如果个数>minPts,则找出它的直接密度可达和间接可达的点&#xff0c;用visited标记点是否已经在簇中&#xff0c;循环直到最后一个点。 #include <fstream> #include <vector> #include <iostream> #include &…

Leetcode.树形DP

目录 543.二叉树的直径 124.二叉树中的最大路径和 2246.相邻字符不同的最长路径 543.二叉树的直径 用递归来写 考虑 树形DP 维护以当前节点为根节点的最大值&#xff0c;同时返回给父节点经过当前节点的最大链的长度&#xff0c;这有个trick 当遍历到空节点的时候返回-1 递归…

mq消费并发排队及幂等机制实现

一&#xff0c;解决什么问题及实现方案 主要为了解决并发访问排队执行及重复下发保证幂等的问题 实现技术方案 如何实现并发访问时&#xff0c;请求排队执行方法。Redssion 如何实现MQ重复下发时&#xff0c;保证幂等。redis 先插入一个分布式锁的话题&#xff0c;如下&am…

LeetCode 740.删除并获得点数---->打家劫舍

前言&#xff1a;简单写写自己对这道题的拙见&#xff0c;如有意见或者建议可以联系笔者owo 首先&#xff0c;看看完整题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;你可以对它进行一些操作。 每次操作中&#xff0c;选择任意一个 nums[i] &#xff0c;删除它并获…

归并排序(java)

大家好我是苏麟 , 今天说说归并排序 . 归并排序 递归 正式学习归并排序之前&#xff0c;我们得先学习一下递归算法。 定义&#xff1a; 定义方法时&#xff0c;在方法内部调用方法本身&#xff0c;称之为递归. public void show(){System.out.println("aaaa")…

SEACALL海外呼叫中心系统的优势包括

SEACALL海外呼叫中心系统的优势包括 封卡封号问题解决 海外呼叫中心系统通过API开放平台能力&#xff0c;定制电话营销系统&#xff0c;提供多项功能如自动拨打、智能应答、真人语音交互等&#xff0c;帮助企业克服员工离职率高、客户资源流失严重等挑战。 - 高级管理者操控 …