【数据结构】顺序表的学习

news2025/1/16 19:04:31

前言:在之前我们学习了C语言的各种各样的语法,因此我们今天开始学习数据结构这一个模块,因此我们就从第一个部分来开始学习"顺序表"。

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:C程序设计谭浩强版本 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


目录

  • 顺序表
    • 动态顺序表
      • 顺序表的初始化
      • 顺序表的销毁
      • 顺序表的空间容量检查
      • 顺序表的打印
      • 顺序表的尾增
      • 顺序表的头增
      • 顺序表的头删
      • 顺序表的尾删
      • 顺序表的选择插入
      • 顺序表的删除数据
      • 顺序表数据的查找
    • 练习


顺序表

  1. 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
  2. 顺序表一般可以分为两个部分,静态顺序表(使用定长数组存储元素)和动态顺序表(使用动态开辟的数组存储)。
  3. 静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

动态顺序表

首先我们创建一个结构体,去实现数据的动态存储。
在这里插入图片描述

代码如下:

typedef int SLDataype;//定义整型,方便后面进行数据的更改

typedef struct SeqList //动态顺序表的开辟
{
	SLDataype* a;
	int size; //记录多少个有效数据
	int capacity; //记录空间有多大
}SL;


接下来我们就实现一个个接口来实现顺序表的基本功能

顺序表的初始化

顺序表的初始化十分简单,只需要将开辟的指针置为空指针,有效数据清零,空间容量清零即可。
代码如下:

void SLInit(SL* ps1)//顺序表的初始化
{
	assert(ps1);
	ps1->a = NULL;//将指针置为空指针
	ps1->size = 0;//数据清零
	ps1->capacity = 0;//容量清零
}


顺序表的销毁

同理,顺序表的销毁,只需要判断所开辟的空间是否已经是被释放了,和被置为空指针了,如果不是,就把所开辟的空间释放和数据清零即可。
代码如下:

void SLDestory(SL* ps1)//顺序表的销毁
{
	if (ps1->a != NULL)//判断该指针是否为空指针
	{
		free(ps1->a);//释放该指针所开辟的空间
		ps1->a = NULL;//置为空指针
		ps1->size = 0;//数据清零
		ps1->capacity = 0;//容量清0
	}
}


顺序表的空间容量检查

我们想要实现在所开辟的空间中,增加数据,就不可避免的需要去检查所开辟的空间的容量是否充足,如果不充足,我们就需要去增容,那该增加多少呢?增加太多,会导致空间的浪费,太少又会导致不断的扩容,这是一个双向的问题,因此这也没有什么十分固定的答案,通常来讲,一般增容一倍即可。

代码思路:在检查空间的时候,我们应该考虑传过来的指针是否是空指针,即是否是初始化后的顺序表,但realloc函数是可以对空指针进行扩容的,但是我们为了防止扩容失败,应该开辟一个新的结构体指针来接收这块空间,在开辟成功后重新覆盖回去。

代码实现:

void SLCheckCapacity(SL* ps1)//检查空间
{
	if (ps1->size == ps1->capacity)
	//判断记录的数据个数,与空间容量释放相同,相同的时候即空间满了,需要增容
	{
		int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;
		//判断开辟的空间是否是初始化的空间,如果是就让他容量为4,如果不是就开辟当前空间的两倍
		SLDataype* tmp = (SLDataype*)realloc(ps1->a, sizeof(SLDataype) * newCapacity);
		//创建一个新的结构体指针,在他的后面扩容,放在开辟失败后原本的数据也不见了
		//realloc 可以对空指针进行扩容
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps1->a = tmp;//将开辟后面的指针传给原本的地址
		ps1->capacity = newCapacity;//更新容量
	}
}

顺序表的打印

void SLPrint(SL* ps1)
{
	for (int i = 0; i < ps1->size; i++)//变量开辟的数据
	{
		printf("%d ", ps1->a[i]);//直接打印
	}
	printf("\n");
}

顺序表的尾增

代码思路:因为前面我们提到了size是有效数据的个数,也是指向的数组的最后一个元素的后一个的位置,因此只需要在此位置赋值即可,然后再让size往后偏移一位。

代码实现:

void SLPushBack(SL* ps1, SLDataype x)//尾增
{
	SLCheckCapacity(ps1);//检查空间容量
	ps1->a[ps1->size] = x;
	//因size指向的是数组最后一个元素的后一个元素,因此只需要直接在此位置赋值即可
	ps1->size++;//size继续指向后一个元素
}

现在我们实现了四个小的接口,忙活了这么久,我们来见一下效果,好歹听个响是吧。
效果图:

void TestSL1()//测试函数
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPrint(&s1);//打印数据
	SLPushBack(&s1, 5);
	SLPushBack(&s1, 6);
	SLPrint(&s1);//打印数据
	SLDestory(&s1);//销毁顺序表
}

int main()
{
	TestSL1();
	return 0;
}

在这里插入图片描述


顺序表的头增

代码实现思路:我们记录数据的最后一个位置为end,最后一个数据后面的一个数据位置为end+1,让end依次往后覆盖,然后end–直到end到起始位置即停止循环,具体思路如下图:
在这里插入图片描述
代码实现:

void SLPushFront(SL* ps1, SLDataype x)//头增
{
	SLCheckCapacity(ps1);//先检查数据

	//挪动数据
	int end = ps1->size - 1;//记录最后一个位置
	while (end >= 0)//end到起始位置时即覆盖完成
	{
		ps1->a[end + 1] = ps1->a[end];//将数据依次往后覆盖
		--end;
	}
	ps1->a[0] = x;//将数据赋值给起始位置就可以实现头增
	ps1->size++;//size++
}

当然了,不能白忙活,我们来测试一下这个函数,来看看效果如何

void TestSL2()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPrint(&s1);//打印尾增的数据
	printf("上面是尾增的数据\n");
	printf("------------------------------\n");
	printf("下面是头增的数据\n");
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1,9);
	SLPrint(&s1);//打印头增的数据
	SLDestory(&s1);//销毁顺序表
}


int main()
{
	//TestSL1();
	TestSL2();
	return 0;
}

在这里插入图片描述


顺序表的头删

代码思路:我们记录一个起始位置即数组的第二个元素记录为begin,让他往前面一个数据begin-1覆盖,然后再放入循环中不断覆盖,当运行到size的位置的时候停止循环具体思路如下图:
在这里插入图片描述
代码如下:

void SLPopFront(SL* ps1)//头删
{
	assert(ps1->size > 0);//判断传过来是是不是为空数据
	int begin = 1;//将起始位置置为1
	while (begin < ps1->size)//再起始位置等于size时即覆盖完成
	{
		ps1->a[begin - 1] = ps1->a[begin];//后面覆盖前面
		++begin;
	}
	ps1->size--;//size减减
}

当然,我们依然来听个响,听听声音,效果图如下:


void TestSL3()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是删除后的数据\n");
	SLPopFront(&s1);//头删数据
	SLPopFront(&s1);
	SLPopFront(&s1);
	SLPrint(&s1);//打印删除后的数据
	SLDestory(&s1);//销毁顺序表
}

int main()
{
	//TestSL1();
	//TestSL2();
	TestSL3();
	return 0;
}

在这里插入图片描述


顺序表的尾删

代码思路:我们可以通过前面的打印函数可以知道,我们是通过打印到size前面的一个下标来访问所有的元素,因此我们只需要让size往前面走一个,就可以把尾部的元素删除,可以看下图思路:
在这里插入图片描述

代码实现:

void SLPopBack(SL* ps1)//尾删
{
	//空
	if (ps1->size == 0)//判断删除的是否为空
	{
		return;
	}
	ps1->size--;//size--即可
}

我们依然来测试一下我们函数,看看效果是否成功实现,代码和效果图如下:

void TestSL4()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是删除后的数据\n");
	SLPopBack(&s1);//尾删数据
	SLPopBack(&s1);
	SLPrint(&s1);//打印删除后的数据
	SLDestory(&s1);//销毁顺序表
}

int main()
{
	//TestSL1();
	//TestSL2();
	//TestSL3();
	TestSL4();
	return 0;
}

在这里插入图片描述


顺序表的选择插入

代码思路:选择插入,即将一个值,任意插入到顺序表中的范围内,当然了口头总是不太好说清,我们对着下图来进行一一分析,我们可以记录一个end坐标记录数据的尾部,然后将值一一覆盖,pos为我们想要出入数据的位置,例如下图,当end走到pos的位置的时候,即可停止覆盖,这有点类似与我们前面的头删,将值pos之后的值全部往后挪动了一位,然后将最后重复的值被想插入的值覆盖即可。
在这里插入图片描述

代码实现:

void SLInsert(SL* ps1, int pos, SLDataype x)//插入数据
//pos是下标,size是数据个数,看作下标的话,他是最后一个数的下一个位置
{
	assert(ps1);//判断传来的值是否是空指针
	assert(pos >= 0 && pos <= ps1->size);//插入的值必须是再范围内(可以包括尾增)
	SLCheckCapacity(ps1);//检查空间
	// 挪动数据
	int end = ps1->size - 1;//找到尾坐标
	while (end >= pos)
	{
		ps1->a[end + 1] = ps1->a[end];//将值一一覆盖,类似于头删
		--end;
	}
	ps1->a[pos] = x;//赋值
	ps1->size++;
}

我们依然来看看函数的效果是否实现,测试代码和效果图如下:

void TestSL5()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是选择插入后的数据\n");
	SLInsert(&s1, 3, 99);
	SLInsert(&s1, 1, 2);
	SLPrint(&s1);//打印选择插入后的数据
	SLDestory(&s1);//销毁顺序表
}
int main()
{
	//TestSL1();
	//TestSL2();
	//TestSL3();
	//TestSL4();
	TestSL5();
	return 0;
}


在这里插入图片描述


顺序表的删除数据

代码思路:删除数据和选择插入的概念其实大差不差,首先也应当判断传过来的数是否是空指针,删除的数据在不在数据范围内,然后我们再通过图文来进行分析,如下图,先把删除的位置记录下来,当然了,和前面同理依次往前面覆盖,再打印的时候直接将size往前移一位即可把最后重复的值给去掉,达到顺序表的删除的功能。
在这里插入图片描述
函数代码:

void SLErase(SL* ps1, int pos)//删除数据
{
	assert(ps1);
	assert(pos >= 0 && pos < ps1->size);
	int begin = pos + 1;//记录删除数据后的位置
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];//依次覆盖
		++begin;
	}
	ps1->size--;
}

代码实现和函数实现效果图如下:

void TestSL6()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是选择插入后的数据\n");
	SLErase(&s1, 3);//删除数据
	SLErase(&s1, 1);//删除数据
	SLPrint(&s1);//打印选择插入后的数据
	SLDestory(&s1);//销毁顺序表

}

int main()
{
	//TestSL1();
	//TestSL2();
	//TestSL3();
	//TestSL4();
	//TestSL5();
	TestSL6();
	return 0;
}

在这里插入图片描述


顺序表数据的查找

代码思路:顺序表数据的查找就过于简单了,我们只需要遍历数据,看看是否有对应的值,有则返回该数的下标,没有则返回**-1**。代码如下:

int SLFind(SL* ps1, SLDataype x)//顺序表数据的查找
{
	assert(ps1);//判断传来的数据是否是空指针
	for (int i = 0; i < ps1->size; i++)//遍历数组
	{
		if (ps1->a[i] == x)
			return i;//找到即返回坐标i
	}
	return -1;//没找到返回-1
}

函数测试与效果图:

void TestSL7()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是选择插入后的数据\n");
	printf("该数的下标是:%d\n",SLFind(&s1, 2));
	SLDestory(&s1);//销毁顺序表
}
int main()
{
	//TestSL1();
	//TestSL2();
	//TestSL3();
	//TestSL4();
	//TestSL5();
	//TestSL6();
	TestSL7();
	return 0;
}

在这里插入图片描述
讲到这里,关于顺序表的基本内容实现全部讲完了,接下来我们来看一题目练习一下把!


练习

题目链接:
在这里插入图片描述

思路分析:看到这个题,大家都会想到一个很通俗易懂的方法,就是开辟一个辅助数组,将所有的数放进去,然后进去排序,当然我们今天是不讲这个方法的,因为这个方法的时间复杂度过于高。我们看到这个是一个非递减顺序,可以知道最大的数都放在了后面,因此我们可以将两个数中最后的元素拿出来依次比较,然后将较大的放在nums1中的最后面,依次类推,放到最后自然而然的可以将所有数进行排序,那怎么去实现它呢?看图说话,如下图,我们记录一个坐标i1i2分别记录下两个数组中的最后一个元素,然后依次进行比较,如果i1中的数较大就放在下标j的位置,反之则把i2放进去,且如果nums1中走完了,nums2还没有,就只需要将nums2中的数据单独拿出来,放再j所在的位置即可。
在这里插入图片描述
代码实现如下:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int i1 = m - 1;//记录第一个数组的尾坐标
    int i2 = n - 1;//第二个数组尾坐标
    int j = m + n - 1;//记录总元素的坐标
    while(i1 >= 0 &&  i2 >= 0)
    {
        if(nums1[i1] > nums2[i2])
        {
            nums1[j--] = nums1[i1--]; 
        }
        else
        {
            nums1[j--] = nums2[i2--];
        }
    }
    while(i2 >= 0)
    {
        nums1[j--] = nums2[i2--];
    }
}

运行结果:
在这里插入图片描述


结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


🫵🫵🫵 祝各位接下来好运连连 💞

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

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

相关文章

环信 IM+AI编程挑战赛开启报名!

大赛背景 即时通讯已成为现代生活中不可或缺的一部分&#xff0c;近年来人工智能的迅猛发展也为即时通讯带来了前所未有的智能化体验。高度拟人的陪伴型机器人&#xff0c;全能实用的服务型机器人&#xff0c;高效智能的对话机器人&#xff0c;AI 与即时通讯的结合创新&#x…

ARM版CentOS Linux系统镜像安装教程

Linux系统受程序员钟爱&#xff0c;目前国内常见版本有Ubuntu和CentOS等&#xff0c;CentOS是较为稳定的Linux系统。如何在苹果电脑上安装Linux系统呢&#xff0c;小编为大家准备了ARM版CentOS Linux系统镜像文件资源&#xff0c;一起来看看吧&#xff01; ARM版CentOS Linux系…

Jenkins自动化部署简单配置

下载安装jenkins 安装Jenkins步骤 点击Next的时候会有jdk版本跟Jenkins版本不符合的情况 1. 看下任务管理器内Jenkins服务是否启动&#xff0c;在浏览器里面输入localhost:2023&#xff08;端口号是安装时输入的&#xff09; 2. 根据路径找到放置密码的文件&#xff08;C…

[SpringCloud] Feign 与 Gateway 简介

目录 一、Feign 简介 1、RestTemplate 远程调用中存在的问题 2、定义和使用 Feign 客户端 3、Feign 自定义配置 4、Feign 性能优化 5、Feign 最佳实践 6、Feign 使用问题汇总 二、Gateway 网关简介 1、搭建网关服务 2、路由断言工厂 3、路由的过滤器配置 4、全局过…

SpringCloud(五) Eureka与Nacos的区别

SpringCloud(二) Eureka注册中心的使用-CSDN博客 SpringCloud(四) Nacos注册中心-CSDN博客 在这两篇博文中我们详细讲解了Eureka和Nacos分别作为微服务的注册中心的使用方法和注意事项,但是两者之间也有一些区别. 一, Nacos实例分类 Nacos实例分为两种类型: 临时实例:如果实例…

C# Onnx P2PNet 人群检测和计数

效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;namespace Onnx…

msvcp140.dll丢失怎么修复?msvcp140.dll文件缺失的解决方法

msvcp140.dll是一个动态链接库文件&#xff0c;它是Microsoft Visual C Redistributable for Visual Studio 2015的一部分。这个文件包含了C运行时库的一些函数和资源&#xff0c;许多应用程序和游戏都需要依赖这个文件来正常运行。当电脑中缺少msvcp140.dll文件或者该文件损坏…

【JQuery-XSS漏洞(CVE-2020-11022/CVE-2020-11023)漏洞复现】

文章目录 一、漏洞描述二、受影响版本三、漏洞复现四、漏洞危害五、修复建议 一、漏洞描述 进行在公司内部用nessus做漏洞扫描时&#xff0c;发现某台服务器报出这个中危漏洞&#xff0c;后面查资料复现。 根据脚本中的自我报告版本&#xff0c;远程web服务器上托管的JQuery版…

新建包含cuda和cudnn的docker

背景&#xff1a;服务器的cudnn版本太低了&#xff0c;没有权限去修改。故新建包含cuda和cudnn的docker 步骤 一、拉取镜像及创建docker 拉取相关的镜像 从镜像列表选出相关版本的镜像https://gitlab.com/nvidia/container-images/cuda/blob/master/doc/supported-tags.md …

vue实现学生成绩管理案例

实现了学生成绩的管理&#xff0c;可以增加科目成绩&#xff0c;不及格的成绩自动标红&#xff0c;删除成绩&#xff0c;实现总分统计、平均分计算。 html代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" />&…

Java:视频按帧进行截图

主要介绍了Java获取视频时长、总帧数&#xff0c;并按照时间或者帧进行截图&#xff0c;希望对大家的学习有所帮助&#xff01; 1、Maven依赖 <!--start:视频获取某一帧的图片--> <dependency><groupId>org.bytedeco</groupId><artifactId>java…

前后端分离项目(六):数据分页查询(前端视图)

&#x1f680; 优质资源分享 &#x1f680; &#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一个全栈订餐系统。 &#x1f49b;Python量化交易实战&#x1f49…

无糖茶饮三十年,从无人问津到人手一瓶

【潮汐商业评论/原创】 Joan又在外卖上点了一堆瓶装茶饮&#xff0c;东方树叶、燃茶、三得利乌龙茶……买了四五种纯茶&#xff0c;用她的话说&#xff0c;和美式咖啡相比&#xff0c;这些无糖茶更适合他这个中国体质。 事实上&#xff0c;越来越多的消费者开始像Joan一样&am…

食堂管理,这个操作不要太绝哦!

随着科技的不断进步&#xff0c;餐饮行业也在积极寻求创新的方式来提高效率、提供更好的客户体验以及降低运营成本。智慧收银系统为餐饮业提供了一个全新的方式来管理交易、优化库存和了解客户需求。 智慧收银系统使食堂经营者能够实现更高的自动化、更大的精确度和更好的数据分…

第58篇-某看准招聘参数分析-AES加密【2023-10-31】

声明&#xff1a;该专栏涉及的所有案例均为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;如有侵权&#xff0c;请私信联系本人删帖&#xff01; 文章目录 一、前言二、网站分析1.参数kiv2.参数b3.响应加密 一、前…

React 组件prop传值

将 props 传递给子组件 开发环境&#xff1a;Reacttsant 将一些 props 传递给 Avatar。例如&#xff0c;让我们传递两个 props&#xff1a;person&#xff08;一个对象&#xff09;和 size&#xff08;一个数字&#xff09; 定义类组件Avatar&#xff08;子组件&#xff09;和…

【k8s】pod详解

一、pod介绍 1、pod的基础概念 Pod是kubernetes中最小的资源管理组件&#xff0c;Pod也是最小化运行容器化应用的资源对象&#xff0c;一个pod代表着集群中运行的一个进程。kubernetes中其它大多数组件都是围绕着pod来进行支持和扩展pod功能的。 例如&#xff0c;用于管理po…

科技战再次升级!国内前沿科技行业影响悬而未决

&#xff08;图片来源&#xff1a;网络&#xff09; 美国与中国的科技贸易战正在升级&#xff0c;美国总统拜登发布行政命令限制美国对半导体和微电子、量子信息技术和人工智能等特定行业的跨国投资。在此前美国对中国芯片相关出口的一系列限制之后&#xff0c;又增加了此项新…

遥遥领先,免费开源的django4-vue3项目

星域后台管理系统前端介绍 &#x1f33f;项目简介 本项目前端基于当下流行且常用的vue3作为主要技术栈进行开发&#xff0c;融合了typescript和element-plus-ui&#xff0c;提供暗黑模式和白昼模式两种主题以及全屏切换&#xff0c;开发bug少&#xff0c;简单易学&#xff0c…

面试算法44:二叉树中每层的最大值

题目 输入一棵二叉树&#xff0c;请找出二叉树中每层的最大值。例如&#xff0c;输入图7.4中的二叉树&#xff0c;返回各层节点的最大值[3&#xff0c;4&#xff0c;9]。 分析&#xff1a;用一个队列实现二叉树的广度优先搜索 由于要找出二叉树中每层的最大值&#xff0c;因…