[C语言]指针进阶详解

news2024/7/4 5:44:07

指针是C语言的精髓所以内容可能会比较多,需要我们认真学习


目录

1、字符指针

2、指针数组

3、数组指针

3.1数组指针的定义

3.2&数组名vs数组名

3.3数组指针的使用 

4、数组传参和指针传参

4.1一维数组传参

4.2二维数组传参

4.3一级指针传参

4.4二级指针传参

5、函数指针

6、函数指针数组

7、指向函数指针数组的指针

8、回调函数

8.1回调函数定义

8.2qsort库函数的用法

1、字符指针

在指针的类型中我们知道一种指针类型为字符指针char*

一般使用:

int main()

{

  char ch='w';

  char* pc=&ch;//*表示pc是指针,char表示pc指向的对象ch他的类型是char

  return 0;

}

#include<stdio.h>
int main()
{
  char* pc="abcdef";
  printf("%s\n",pc);
  return 0;
}

看这样一个代码的运行结果:

 这里需要注意pc里面放的并不是整个字符串,而是a的地址,非要放在pc(4字节)中是放不下的,而打印的是字符串(%s),我们只要知道首字符a的地址就能向后访问得到整个字符串的地址在char* 前面加上const会更加好一些。看这样一道题:

#include<stdio.h>
int main()
{
	const char* p1 = "abcdef";
	const char* p2 = "abcdef";

	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	if (p1 == p2)
		printf("p1==p2\n");
	else
		printf("p1!=p2");
	if (arr1 == arr2)
		printf("arr1==arr2");
	else
		printf("arr1!=arr2");
	return 0;
}

 这说明p1和p2指向同一个字符a,字符串abcdef是常量字符串,放在内存中的只读内存区,不能改变它的值,没有必要存在多份,只在内存中存一份,所以p1和p2都指向a的地址,p1就等于p2.而arr1和arr2不相等,是因为arr1[ ]和arr2[ ]是两个独立的数组,,每一个都在内存中开辟了一份独立的空间,所以地址肯定是不相同的。

2、指针数组

顾名思义指针数组就是存放指针的数组(本质是一个数组)

int* arr1[10];//整型指针的数组

char* arr2[10];//一级字符指针的数组

char **arr[5];//二级字符指针的数组 

#include<stdio.h>
int main()
{
	int arr1[] = { 1,2,3,4 };
	int arr2[] = { 2,3,4,5 };
	int arr3[] = { 3,4,5,6 };
	int* arr[3] = { arr1,arr2,arr3 };//每个数组的首元素地址,每个元素的类型是int*

	int i = 0;//代表arr的每个元素的下标
	for (i = 0; i < 3; i++)
	{
		int j = 0;//j代表的是arr1、arr2、arr3中每个元素的下标
		for (j = 0; j < 4; j++)
		{
			printf("%d ", *(arr[i] + j));//arr[i]代表各个数组的数组名,即每个数组的首元素地址,加上j并解引用就拿到了所有元素
            //因为*(p+i)等价于arr[i],所以有可以写成这样的形式
            //printf("%d ",*(*(arr+i)+j));或者
            //printf("%d ",arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

用了一个指针数组把三个一维数组关联起来了,模拟实现二维数组,但本质上并不是二维数组,因为这三个数组在内存中并不是连续存放的但二维数组在内存中是连续存放的。

3、数组指针

3.1数组指针的定义

数组指针的本质是指针。

整型指针:int* p;能够指向整形数据的指针

浮点型指针:float* p;能够指向浮点型数据的指针

所以说数组指针就是能够指向数组的指针。比如:

int (*p)[10];(*p)代表p是指针,指向的是整型数组中的10个元素,每个元素是int类型。

注意:[ ]的优先级要高于*号,因此必须加上()来保证p先和*相结合。

3.2&数组名vs数组名

对于下面的数组:

int arr[10];

arr和&arr的区别:

我们知道arr是数组名,数组名表示数组首元素的地址。那么&arr表示的是什么?

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr);
	return 0;
}
//数组名通常表示的是数组首元素的地址,但有两个例外:
//1.sizeof(数组名),这里的数组名表示的是整个数组
//2.&数组名,这里的数组名依然表示的是整个数组,所以&arr取出的是整个数组的地址

这里我们会发现运行结果显示,三个地址是完全相同的,但是&arr的步长和arr的步长是不同的,arr+1(类型是int*)跳过4个字节,但&arr+1跳过28(16进制)字节,即40字节。那么应该怎么存放整个数组的地址呢?

存放数组首元素的地址:int *p=arr;

存放整个数组的地址:int (*p)[10];(数组指针用来存放整个数组的地址)。它的类型为int (*)[10]。

3.3数组指针的使用 

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int(*p)[10] = &arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(*p + i));//因为p指向的是整个数组,(不包含数组大小),*p表示的是整个数组的内容(数组名)即首元素地址
		//也可以这样说:*p表示从p所指向的内存地址开始的数组内存的布局。这通常被理解为该数组本身,实际上它只是一个别名或引用,指向已经存在的数组
		//简单理解就是如果int* p=arr,那*p就是找到arr的内容,如果int (*p)arr[10]=&arr,则*p就是找到*&arr即arr(数组名)
	}
	return 0;
}

这样用我们会感到相当别扭,很不舒服,所以很不建议这样用! 建议大家用在二维数组上。

#include<stdio.h>
void print1(int arr[3][5], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			printf("%d ",arr[i][j]);
		}
		printf("\n");
	}
}
void print2(int (*p)[5], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			printf("%d ",*(*(p+i)+j));//p相当于是第一行的地址,解引用相当于首元素地址
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	print1(arr, 3, 5);
	print2(arr, 3, 5);//传过去的是二维数组的首元素地址,那二维数组的首元素地址是什么呢?
	//其实是二维数组的第一行,所以传过去的其实是数组内容为5个整型的一维数组的地址
	return 0;
}

int (*parr[10])[5];parr先和[5]配对说明是个数组数组的类型是int (*)[5]是个数组指针。所以parr就是存放数组指针的数组 。

4、数组传参和指针传参

写代码时难免会把数组或指针传给函数,那么函数的参数该如何设计呢?

4.1一维数组传参

#include<stdio.h>
void test1(int arr1[]) {

}
void test1(int arr1[10]) {

}
void test1(int* arr1) {

}
void test2(int *arr2[10]) { 

} //10可以省略
void test2(int** arr2) {

}
int main()
{
    int arr1[10] = { 0 };
    int* arr2[10] = { 0 };
    test1(arr1);
    test2(arr2);
    return 0;
}

4.2二维数组传参

#include<stdio.h>
void test(int arr[3][5]) {

}
void test(int arr[][5]) {

}//二维数组传参,函数的形参设计只能省略行,因为对于一个二维数组,可以不知道有多少行,但是必须知道一行有多少个元素
void test(int (*p)[5]) {

}//二维数组传参传的是第一行元素的地址,需要拿一个数组指针才能接收
int main()
{
    int arr[3][5] = {0};
    test(arr);
    return 0;
}

4.3一级指针传参

#include<stdio.h>
void print(int* p, int sz)
{
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%d ", *(p + i));
    }
}
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int* p = arr;
    int sz = sizeof(arr) / sizeof(arr[0]);
    print(p, sz);//p是一级指针变量
    return 0;
}

4.4二级指针传参

#include<stdio.h>
void print(int** ptr)
{
    printf("%d\n", **ptr);
}
int main()
{
    int n = 10;
    int* p = &n;
    int** pp = &p;
    print(&p);
    return 0;
}

当函数的参数为二级指针的时候,可以接收什么参数?

可以说指向一级指针的变量,也可以是指向一级指针的数组,二级指针变量本身

5、函数指针

指向函数的指针就叫做函数指针,用来存放函数的地址

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	printf("%p\n", &Add);
	return 0;
}

 由此可见打印出来的值就是Add函数的地址。对于函数来说,&函数名和函数名都是函数的地址

那怎么用指针把函数地址存起来呢?

拿此例子来说:int (*pf)(int,int)=&Add;

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int (*pf)(int, int) = &Add;
	int ret = (*pf)(2, 3);//解引用就相当于找到了这个函数,*是可以省略的
	printf("%d\n", ret);
	return 0;
}

 int main()
{
    (*(void(*) () )0)();//把0强制转换成函数指针类型(我们可以认为0就是一个地址),解引用调用这个函数,但什么参数都没有传,所以本质上是一次函数调用,调用的是0作为地址处的函数

    void(* signal(int,void(*)(int) ) )(int);

    //signal与括号先结合是函数名,其中void(*)(int)是函数指针类型,去掉

    signal(int,void(*)(int) )我们会发现剩下部分也是返回也是一个函数返回类型。也就是说这个代码是一次函数声明。声明的signal函数第一个参数的类型是int,第二个参数的类型是函数指针。该函数指针指向的函数参数是int,返回类型是void;而signal函数的返回类型也是一个函数指针,该函数指针指向的参数是int,返回类型也是void。
    return 0;
}

函数指针的用途:(写一个计算器能够实现简单的加法、减法、除法、乘法)

#include<stdio.h>
void menu()
{
	printf("*******************\n");
	printf("****1.add 2.sub****\n");
	printf("****3.mul 4.div****\n");
	printf("****   0.exit  ****\n");
	printf("*******************\n");
}
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mul(int x, int y)
{
	return x * y;
}
int div(int x, int y)
{
	return x / y;
}
//回调函数
void calc(int (*p)(int, int))
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入两个操作数:>\n");
	scanf("%d%d", &x, &y);
	ret = (*p)(x, y);
	printf("%d\n", ret);
}
int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			calc(add);
			break;
		case 2:
			calc(sub);
			break;
		case 3:
			calc(mul);
			break;
		case 4:
			calc(div);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误请重新选择:>\n");
			break;
		}
	} while (input);
	return 0;
}

6、函数指针数组

把存放函数的地址存到一个数组中,那么这个数组就叫做函数指针数组,如何定义函数指针数组?

int add(int x, int y)
{
    return x + y;
}
int sub(int x, int y)
{
    return x - y;
}
int mul(int x, int y)
{
    return x * y;
}
int div(int x, int y)
{
    return x / y;
}

int main( )

{

    int (*arr[4])(int,int)={add,sub,mul,div};//arr先于[4]结合表明本质是个数组,数组每个元素的类型为int (*)(int,int)即函数指针类型

    int i = 0;
   for (i = 0; i < 4; i++)
   {
      int ret = arr[i](8, 4);
      printf("%d ", ret);
    }

    return 0;

}

有什么用途呢?以上面模拟计算机为例,我们还可以对代码进行简化,并且增加计算机功能时也相对比较容易,极大简化了修改功能时的工作量。

#include<stdio.h>
void menu()
{
	printf("*******************\n");
	printf("****1.add 2.sub****\n");
	printf("****3.mul 4.div****\n");
	printf("****   0.exit  ****\n");
    printf("*******************\n");
}
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mul(int x, int y)
{
	return x * y;
}
int div(int x, int y)
{
	return x / y;
}
int main()
{
	int x = 0;
	int y = 0;
	int input = 0;
	int ret = 0;
    //转移表
	int (*pfarr[5])(int, int) = { 0,add,sub,mul,div };//之所以第一个元素放0,是为了,与为了调用时和菜单选项对应起来,比如输入下标为1是调用的是add函数
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		if (input == 0)
		{
			printf("退出程序\n");
		}
		else if (input >= 1 && input <= 4)
		{
			printf("请输入两个操作数:>\n");
			scanf("%d%d", &x, &y);
			ret = pfarr[input](x, y);
			printf("%d\n", ret);
		}
		else
		{
			printf("选择错误请重新选择\n");
		}
	} while (input);
	return 0;
}

这个代码现在就变得清爽了许多,非常的简洁。 

7、指向函数指针数组的指针

指向函数指针数组的指针本质上就是一个指针,指针指向一个数组,数组里面的元素都是函数指针

int main()
{
    int (*pfarr[5])(int, int) = { 0,add,sub,mul,div };
    int (*(*ppfarr)[5])(int,int) = &pfarr;
    return 0;
}

但用的相对并不多,以后会详细介绍 

8、回调函数

8.1回调函数定义

回调函数就是通过函数指针调用的函数。如果把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方式直接调用,而是在特定的事件或条件发生时有另外的一方的调用的,用于对该事件或条件进行响应。

8.2qsort库函数的用法

qsort是C标准库<stdlib.h>中的一个函数,用于对数组进行快速排序。它接受一个指向要排序的数组的指针、数组中元素的数量、每个元素的大小(字节为单位)以及一个比较函数作为参数。

//qsort的声明

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

base:指向要排序的数组的第一个元素的指针(数据的起始位置)

nmemb:数组中元素的数量

size:数组中每个元素的大小

compar:一个指向比较函数的指针,该函数用于确定元素的排序顺序 

比较函数应该接受两个只想要比较的元素的指针,并返回一个整型,表示他们的相对顺序。如果第一个元素排在第二个元素之前返回负数(第一个数小于第二个数),反之返回整数,相等则返回0.

qsort具体要怎么用呢?现在我们对整型数组arr[10]={10,9,8,7,6,5,4,3,2,1}排成升序之前我们学过冒泡排序的思想,现在我们换种方法来实现

void print(int arr[],int sz)//打印数组内容
{
	int i = 0;
	for (i = 0;i < sz;i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
//比较两个整型元素,e1指向一个整数,e2也指向一个整数
int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);//强制类型转换成int*类型
}//如果我们像排成降序只需要把e1改成e2,把e2改成e1,逻辑相反
int main()
{
	int arr[10] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print(arr, sz);
	return 0;
}
//void* 是无具体类型的指针,不能解引用操作,也不能加减整数

qsort不仅仅可以排序整型数据也可以排结构体数据,也可以排字符数据

我们来看对结构体数据排序的实例:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Stu
{
	char name[20];
	int age;

};
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);//e1是指针变量
	//strcmp函数如果第一个字符串比第二个大返回正数,小于返回负数,否则返回0
}
int main()
{
	struct Stu s[] = { {"张三",15},{"李四",16},{"王五",18}};
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("name=%s age=%d\n",(s+i)->name,(s+i)->age);//s虽然本身不是指针,是数组名,但会"退化为"指向第一个元素的指针。这是为了与期望接受指针的函数(qsort)兼容
		//也可以用s[i].name,s[i].age的形式来访问结构体成员
	}
	return 0;
}
}

 

 

 

 

 

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

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

相关文章

如何使用SSH密钥克隆仓库

1.创建SSH Key 在用户目录下查看有没有.ssh目录。如果有且该.ssh目录下有id_rsa&#xff08;私钥&#xff09;&#xff0c;和id_rse_pub(公钥)这俩文件&#xff0c;那么这一步就可以跳过。否则使用以下指令创建SSH Key ssh-keygen -t rsa -C "xxxqq.com" "xx…

【C语言】详解预处理

、 最好的时光&#xff0c;在路上;最好的生活&#xff0c;在别处。独自上路去看看这个世界&#xff0c;你终将与最好的自己相遇。&#x1f493;&#x1f493;&#x1f493; 目录 •✨说在前面 &#x1f34b;预定义符号 &#x1f34b; #define • &#x1f330;1.#define定义常…

解决HTTP 403 Forbidden错误:禁止访问目录索引问题的解决方法

解决HTTP 403 Forbidden错误&#xff1a;禁止访问目录索引问题的解决方法 过去有人曾对我说&#xff0c;“一个人爱上小溪&#xff0c;是因为没有见过大海。”而如今我终于可以说&#xff0c;“我已见过银河&#xff0c;但我仍只爱你一颗星。” 在Web开发和服务器管理中&#x…

3-qt综合实例-贪吃蛇的游戏程序

引言&#xff1a; 如题&#xff0c;本次实践课程主要讲解贪吃蛇游戏程序。 qt贪吃蛇项目内容&#xff1a; 一、功能需求 二、界面设计 各组件使用&#xff1a; 对象名 类 说明 Widget QWidge 主窗体 btnRank QPushButton 排行榜-按钮 groupBox QGroupBox 难…

C/C++开发,opencv-ml库学习,ml模块代码实现研究

目录 一、opencv-ml模块 1.1 ml简介 1.2 StatModel基类及通用函数 1.3 ml模块各算法基本应用 二、ml模块的实现原理 2.1 cv::ml::StatModel的train函数实现原理 2.2 cv::ml::StatModel的predict函数实现原理 2.3 cv::ml::StatModel的save函数和load函数 一、opencv-ml模…

Nginx(搭建高可用集群)

文章目录 1.基本介绍1.在微服务架构中的位置2.配置前提3.主从模式架构图 2.启动主Nginx和两个Tomcat1.启动linux的tomcat2.启动win的tomcat3.启动主Nginx&#xff0c;进入安装目录 ./sbin/nginx -c nginx.conf4.windows访问 http://look.sunxiansheng.cn:7777/search/cal.jsp 3…

力扣 647. 回文子串

题目来源&#xff1a;https://leetcode.cn/problems/palindromic-substrings/description/ C题解1&#xff1a;暴力解法。不断地移动窗口&#xff0c;判断是不是回文串。 class Solution { public:int countSubstrings(string s) {int len s.size();int res 0;for(int i 0;…

【机器学习-21】集成学习---Bagging之随机森林(RF)

【机器学习】集成学习---Bagging之随机森林&#xff08;RF&#xff09; 一、引言1. 简要介绍集成学习的概念及其在机器学习领域的重要性。2. 引出随机森林作为Bagging算法的一个典型应用。 二、随机森林原理1. Bagging算法的基本思想2. 随机森林的构造3. 随机森林的工作机制 三…

Samsung三星NP930XCJ-K01CN笔记本原厂Win10系统安装包下载

三星SAMSUNG笔记本电脑原装出厂Windows10预装OEM系统&#xff0c;恢复开箱状态自带系统 链接&#xff1a;https://pan.baidu.com/s/1Y3576Tsp8MtDxIpJGDucbA?pwdt0ox 提取码&#xff1a;t0ox 三星原装W10系统自带声卡,网卡,显卡,指纹,蓝牙等所有驱动、三星出厂主题专用壁纸…

vivado 在硬件中调试串行 I/O 设计-属性窗口

只要在“硬件 (Hardware) ”窗口中选中 GT 或 COMMON 块、在“链接 (Link) ”窗口中选中链接 &#xff0c; 或者在“扫描 (Scan)”窗口中选中扫描 &#xff0c; 那么就会在“ Properties ”窗口中显示该对象的属性。对于 GT 和 COMMON &#xff0c; 包括这些对象的所有属性、…

未雨绸缪:25岁Python程序员如何规划职业生涯,避免35岁职业危机?

一、程序员如何避免中年危机&#xff1f; 为了避免在35岁时被淘汰&#xff0c;程序员在25岁时可以采取一系列策略来规划自己的职业发展和提升技能。以下是我给大家整理的一些建议&#xff1a; 1. 持续学习 科技行业更新换代迅速&#xff0c;程序员需要保持对新技术和工具的敏…

揭秘大模型应用如何成为当红顶流?

Kimi广告神话背后的关键词战略 如果你生活在中国&#xff0c;你可能不认识ChatGPT&#xff0c;但你一定知道Kimi。无论是学生党还是打工人&#xff0c;都无法避开Kimi的广告。 刘同学在B站上搜教学视频时&#xff0c;弹出了一则软广&#xff0c;上面写着&#xff1a;“作业有…

SQL 基础 | BETWEEN 的常见用法

在SQL中&#xff0c;BETWEEN是一个操作符&#xff0c;用于选取介于两个值之间的数据。 它包含这两个边界值。BETWEEN操作符常用于WHERE子句中&#xff0c;以便选取某个范围内的值。 以下是BETWEEN的一些常见用法&#xff1a; 选取介于两个值之间的值&#xff1a; 使用 BETWEEN来…

批处理优化

1.4、总结 Key的最佳实践 固定格式&#xff1a;[业务名]:[数据名]:[id]足够简短&#xff1a;不超过44字节不包含特殊字符 Value的最佳实践&#xff1a; 合理的拆分数据&#xff0c;拒绝BigKey选择合适数据结构Hash结构的entry数量不要超过1000设置合理的超时时间 2、批处理优…

​【收录 Hello 算法】第 3 章 数据结构

第 3 章 数据结构 Abstract 数据结构如同一副稳固而多样的框架。 它为数据的有序组织提供了蓝图&#xff0c;算法得以在此基础上生动起来。 本章内容 3.1 数据结构分类3.2 基本数据类型3.3 数字编码 *3.4 字符编码 *3.5 小结

课时115:sed命令_进阶实践_高阶用法2

2.2.4 高阶用法2 学习目标 这一节&#xff0c;我们从 暂存实践、其他实践、小结 三个方面来学习。 暂存实践 简介 我们可以在缓存空间和暂存空间中进行数据的简单读取&#xff0c;还可以对数据进行一些复杂性的编辑操作常见的高阶命令P 打印模式空间开端至\n内容&#xff0…

Unable to find assembler. Install ‘yasm‘ or ‘nasm.‘ To build without

Unable to find assembler. Install yasm or nasm. To build without 一、概述二、解决办法 一、概述 系统&#xff1a;Ubuntu 22.04 在编译一个项目的时候提示我汇编器有一个问题&#xff0c;一个ysam 或者 nasm未安装 二、解决办法 sudo apt install yasm

银行智能化数据安全分类分级实践分享

文章目录 前言一、数据安全智能分类分级平台建设背景二、数据安全分类分级建设思路和实践1、做标签– 数据安全标签体系2、打标签– 鹰眼智能打标平台 3.03、用标签– 全行统一“数据安全打标签结果”服务提供前言 随着国家对数据安全的高度重视,以及相关法律法规的出台,数据…

【Leetcode每日一题】 分治 - 排序数组(难度⭐⭐)(69)

1. 题目解析 题目链接&#xff1a;912. 排序数组 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 归并排序&#xff08;Merge Sort&#xff09;是一种采用“分而治之”&#xff08;Divide and Conquer&#xff09;策略…

HNU-人工智能-实验3-贝叶斯分类器

人工智能-实验3 计科210x 甘晴void 【感悟】本实验值得自己完成一遍 文章目录 人工智能-实验3一、实验目的二、实验平台三、实验内容3.0 基础知识3.1 条件概率&#xff08;选择题&#xff09;3.2 贝叶斯公式&#xff08;选择题&#xff09;3.3 朴素贝叶斯分类算法流程3.3.1 算…