【数据结构】顺序表实现

news2024/9/23 11:21:28

0. 前言

小伙伴们大家好,从今天开始,我们就开始学习《数据结构》这门课程~

首先想给大家讲讲什么是数据结构?

0.1 数据结构是什么?

数据结构是由“数据”“结构”两词组合⽽来。

什么是数据?

比如常⻅的数值1、2、3、4..... ;平时我们学校教务系统⾥保存的用户信息(姓名、性别、年龄、学历等等)凡是我们在网页在肉眼可以看到的信息(⽂字、图⽚、视频等等),这些都是数据。

那何为结构呢?

当我们想要使⽤⼤量使⽤同⼀类型的数据时,通过⼿动定义⼤量的独⽴的变量对于程序来说,可读性⾮常差,我们可以借助数组这样的数据结构将⼤量的数据组织在⼀起,结构也可以理解为组织数据的⽅式。

就好像:

在草原上,想找到名叫“咩咩”的⽺很难,

但是如果我们从⽺圈⾥找到1号⽺就很简单,⽺圈这样的结构有效将⽺群组织起来。

概念:

数据结构是计算机存储、组织数据的⽅式。数据结构是指相互之间存在⼀种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么⽅式构成,以及数据元素之间呈现的结构。

总结:

1)能够存储数据(如顺序表、链表等结构)

2)存储的数据能够⽅便查找

0.2 为什么需要数据结构? 

如图中所⽰,我们生活中无论去公共场所,或者在火车站买票等等场景,我们都需要排队。

如果不借助排队的⽅式来管理客户,会导致客户感受差、等待时间⻓等情况。

同理,程序中如果不对数据进⾏管理,可能会导致数据丢失、操作数据困难、野指针等情况。

通过数据结构,能够有效将数据组织和管理在⼀起。按照我们的⽅式任意对数据进⾏

增删改查等操作。

最基础的数据结构:数组。

我们思考一下,有了数组,为什么还要我们学习其他的数据结构呢?

比如你遇到这样一个问题:

假定数组有10个空间,已经使⽤了5个,向数组中插⼊数据步骤:

求数组的⻓度,求数组的有效数据个数,向下标为数据有效个数的位置插⼊数据(注意:这⾥是否要判断数组是否满了,满了还能继续插⼊吗).....

假设数据量⾮常庞⼤,频繁的获取数组有效数据个数会影响程序执⾏效率。

结论:最基础的数据结构能够提供的操作已经不能完全满⾜复杂算法实现。

🌟🌟有什么办法可以完成数组完不成的任务呢?

这就是我们要学习的第一个数据结构——顺序表 

1、顺序表的概念及结构

1.1 线性表

线性表(linear list)n个具有相同特性的数据元素的有限序列

线性表是⼀种在实际中⼴泛使⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的⼀条直线但是在物理结构上并不⼀定是连续的,

线性表在物理上存储时,通常以数组和链式结构的形式存储。

2、顺序表分类

2.1 顺序表和数组的区别:

顺序表实质上就是对数组的封装,完成了对数组的增删改查的操作。

下面有一张图,可以帮助大家理解他俩的关系哦:

我们可以把数组和顺序表想象成两家餐厅,

一家是苍蝇馆子这样的普通餐厅,一家是米其林餐厅这样高档的五星级餐厅。

在普通餐厅能吃到炒西蓝花、玉米羹等等这样的菜,在高档的五星级餐厅也能吃到。

只不过五星级餐厅的厨师会把同样的菜做的更加细致,无论从食材的选择,料汁的调配,加上好看的摆盘,配上好听的名字,让这些菜变得更加档次。

所以简单来说,数组经过增加数据、删除数据、修改数据、查找数据等等的操作,摇身一变,就变成了顺序表。

2.2 顺序表分类:

顺序表分为静态顺序表动态顺序表

2.2.1 静态顺序表

概念:使⽤定⻓数组存储元素

静态顺序表缺陷:空间给少了不够⽤,给多了造成空间浪费

2.2.2 动态顺序表 

3. 接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

基本增删查改接口

//对数据管理 --- 增删查改
void SLInit(SL* ps);			//初始化
void SLDestory(SL* ps);			//释放
void SLPrint(SL* ps);        	//打印
void SLCheakCapacity(SL* ps);	//检查容量 -- 扩容

//头插头删 尾插尾删
void SLPushBack(SL* ps, SLDateType x); //尾插
void SLPopBack(SL* ps);				   //尾删
void SLPushFront(SL* ps, SLDateType x);//头插
void SLPopFront(SL* ps);			   //头删

//返回下标,没找到返回-1
int SLFind(SL* ps, SLDateType);		   //查找元素,返回下标

//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDateType x);	//任意位置插入
//在pos位置删除x
void SLErase(SL* ps, int pos);					//任意位置删除

void SLModify(SL* ps, int pos, SLDateType x);//修改

3.1 创建项目

由于在实际工程中,项目的实现都是采用模块化进行实现的。

所以在此处我也采用了模块化的方式进行实现。

3.2 定义动态顺序表结构 

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

动态顺序表
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;//存储数据的底层结构 
	int capacity;//记录顺序表的空间大小 
	int size;//记录顺序表当前有效的数据个数 
}SL;

为了后续好修改类型数据,我们可以使用typedef将结构体类型struct SeqList 重新命名为SL
在后续对顺序表操作中,为了用户更好的输入数据,一般我们会将输入数据的数据类型重命名为SLDataType
采用typedef将其数据类型int重命名为SLDataType 

3.3 初始化与销毁

函数声明:

//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);

函数实现: 

//初始化顺序表
void SLInit((SL* ps)//传入链表地址便于修改
{
	ps->arr= NULL;
	ps->size = ps->capacity = 0;
}

动态顺序表是动态开辟的空间,结束时需要进行释放,避免造成内存泄漏

void SLDestroy(SL* ps)
{
	assert(ps);
	if (ps->arr) 
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

 代码解读:

assert(ps):这是一个断言语句,用于检查 ps 是否为非空指针。如果ps为空,
程序会在运行时中断并报错。 
if (ps->arr):检查 ps 结构体中的 arr 成员是否不为空。
free(ps->arr)`:如果 arr 不为空,使用 free 函数释放其占用的内存空间。 
ps->arr = NULL:将 arr 成员指针设置为空,以避免悬空指针。 
ps->capacity = ps->size = 0:将 capacity 和 size 成员都设置为 0。

3.4 顺序表容量检查

注意:

  1. 每当要增加数据时,都需要考虑空间是否使用完毕
  2. 如果使用完毕则需要考虑增容,增容为原来的两倍(避免频繁扩容)
  3. 增容后更新记录容量大小

注:这里我们考虑到有许多地方要检查是否增容,为了方便将它封装成一个函数 

函数声明:

//扩容
void SLCheckCapacity(SL* ps); 

函数实现: 

void SLCheckCapacity(SL* ps) 
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * 
sizeof(SLDataType));
		if (tmp == NULL) 
		{
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

 代码解读:

判断结构体中的当前元素数量 size 是否等于容量 capacity 。如果相等,说明需要进行扩容操作。计算新的容量。如果当前容量为 0 ,则新容量设置为 4 ;否则新容量设置为当前容量的 2 倍。使用 realloc 函数尝试为数组重新分配内存,新的内存大小为新的容量乘以每个元素的大小。检查 realloc 是否成功。如果 realloc 失败(返回 NULL ),则:
打印错误信息。退出程序。如果扩容成功:更新结构体中的数组指针,使其指向新分配的内存。更新结构体中的容量值。

 3.5 打印

函数声明:

//顺序表打印
void SLPrint(SL* ps);

 上述函数定义完成后,我们通常需要测试打印以下相关数据,来判断相关函数定义是否成功.

代码实现:

void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	printf("\n");
}

3.6 尾插

函数声明:

//顺序表的尾部插入
void SLPushBack(SL* ps, SLDataType x);

我们来分析一下:

尾插是在尾部插入一个数据。

但是在数据的尾部插入一个数据时,

我们需要考虑一个问题:原有空间是否可以容纳新的数据,是否需要扩容。
所以我们在插入数据时,要先调用 SLCheakCapacity函数来检查是否需要扩容。

代码实现:

//顺序表的尾部插入
void SLPushBack(SL* ps, SLDataType x)
{
    //对于顺序表为空,可以有两种判断方式
	//①断言--粗暴的解决方式
	//assert(ps != NULL);
	assert(ps);

	//②if判断--温柔的解决方式
	//if (ps == NULL)
    //{
	//	return;
	//}

	//空间不够,扩容
	SLCheckCapacity(ps);

	//空间足够,直接插入
	ps->arr[ps->size++] = x;
}

3.7尾删

函数声明:

//顺序表的尾部删除
void SLPopBack(SL* ps);

我们来分析一下:

尾删:删除尾部最后的一个元素。

但尾删同样也要考虑一个问题,空间中是否还有数据给我们删除。
所以在进行尾删时,我们可以采用assert函数断言空间中还有数据。

代码实现:

void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size >= 0);//断言空间中还有元素
	ps->size--;//下标减1
}

在删除数据时,我们不用将原有数据删除。只需要下标减1即可。
原因在于我们时根据下标来使用数据的,当下标减1后,尾部最后一个数据便无法进行访问。

 3.8 头插

函数声明:

//顺序表头部插⼊
void SLPushFront(SL* ps, SLDataType x);

我们来分析一下:

头插:在数据最开始地方插入数据。

比如,在0前面插入100

我们可以这样做: 

同样,头插也要调用 SLCheakCapacity函数来检查空间是否足够,是否需要扩容。

 

代码实现:

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);

	//判断是否扩容 
	SLCheckCapacity(ps);

	//旧数据往后挪动一位
	for (int i = ps->size; i > 0 ; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//ps->arr[1] = ps->arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}

3.9 头删

函数声明:

//顺序表的头部删除
void SLPopFront(SL* ps);

我们来分析一下:

头删:删除数据最开始的元素。

思路和头插类似,只要下标从1开始,所有数据依次向前移动1位,再把有限个数减1即可。
同时头删也需要使用assert函数断言原有空间中还有数据可以删除。 

 代码实现:

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);//空间中还有数据可以删除

	//后面的数据往前挪动一位
	for (int i = 0; i < ps->size; i++)
	{
		ps->arr[i-1] = ps->arr[i];//ps->arr[1] = ps->arr[0]
	}
	ps->size--;
}

3.10 指定位置之前插入数据

函数声明:

//指定位置之前插⼊
void SLInsert(SL* ps, int pos, SLDataType x);

我们分析一下:

看到插入两个字,我们就要考虑是否需要扩容。这一点很重要。还有我们要多pos这个参数进行判断,看是否在顺序表指定的范围中,因为顺序表是连续的,我们任意位置插入要合理,所以要对参数进行合理性判断:

assert(pos >= 0 && pos <= ps->size); 

先给大家来画个图分析:

代码实现:

void SLInsert(SL* ps, int pos, SLDataType x)
{
    //顺序表为空
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
    
    // 空间够不够?是否扩容?
	SLCheckCapacity(ps);
	
    //pos及之后的数据往后挪动一位

	for (int i = ps->size; i> pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

代码解读:

assert(ps) :确保 ps 指针非空。
assert(pos >= 0 && pos <= ps->size) :确保指定的插入位置 pos 是有效的,即在 0 到当前元素数量 ps->size 的范围内。
SLCheckCapacity(ps) :在插入元素之前,检查并可能进行容量的扩展,以确保有足够的空间来插入新元素。
循环部分:
通过 for 循环方式,将位置 pos 及之后的元素向后移动一位,为新元素腾出位置。

ps->arr[pos] = x :将新元素 x 插入到指定位置 pos 。
ps->size++:增加元素数量,表示成功插入了一个新元素。 

3.11 删除任意位置数据

函数声明:

//删除指定位置数据 
void SLErase(SL* ps, int pos);

【代码思路】:和插入任何位置数据思想类似。首先我们要检查输入下标pos是否合法。之后从输入下标开始,后一个元素拷贝到前一个元素空间。

代码实现:

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
		//ps->arr[i-2] = ps->arr[i-1];
	}
	ps->size--;
}

3.12 查找

函数声明:

//在顺序表中查找x
int SLFind(SL* ps, SLDataType x);

【代码思路】:要查找某个元素。由于这里只是最简单的查找,我们直接暴力查找,遍历整个数组返回下标即可。更为复杂的数据查找,会有更高阶的数据结构来实现。

代码实现:

int SLFind(SL* ps, SLDateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->a[i])
			return i;
	}
	return -1;
}

4. 所有代码 

SeqList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//静态顺序表
//#define N 100
//typedef int SLDataType;
//
struct SeqList
{
	SLDataType a[N];
	int size;
};

//动态顺序表
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;//存储数据的底层结构 
	int capacity;//记录顺序表的空间大小 
	int size;//记录顺序表当前有效的数据个数 
}SL;

//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);//保证接口的一致性


//顺序表头部 尾部插⼊
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);

//顺序表的头部 尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//指定位置之前插入数据
//删除指定位置数据 
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);

//在顺序表中查找x
int SLFind(SL* ps, SLDataType x);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqList.h"

void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

void SLDestroy(SL* ps)
{
	assert(ps);
	if (ps->arr) 
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}


void SLCheckCapacity(SL* ps) 
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL) 
		{
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDataType x) {
	//断言--粗暴的解决方式
	//assert(ps != NULL);
	assert(ps);

	//if判断--温柔的解决方式
	//if (ps == NULL) {
	//	return;
	//}

	//空间不够,扩容
	SLCheckCapacity(ps);

	//空间足够,直接插入
	ps->arr[ps->size++] = x;
	//ps->size++;
}

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);

	//判断是否扩容 
	SLCheckCapacity(ps);

	//旧数据往后挪动一位
	for (int i = ps->size; i > 0 ; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//ps->arr[1] = ps->arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}

//顺序表的头部 尾部删除
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);

	ps->size--;
}
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//后面的数据往前挪动一位
	for (int i = 0; i < ps->size; i++)
	{
		ps->arr[i-1] = ps->arr[i];//ps->arr[1] = ps->arr[0]
	}
	ps->size--;
}

void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	printf("\n");
}

//指定位置之前插入数据
//删除指定位置数据 

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	SLCheckCapacity(ps);
	//pos及之后的数据往后挪动一位

	for (int i = ps->size; i> pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
		//ps->arr[i-2] = ps->arr[i-1];
	}
	ps->size--;
}

//在顺序表中查找x

int SLFind(SL* ps, SLDataType x)
{
	//加上断言健壮性更好 
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->arr[i])
			return i;
	}
	return -1;
}

测试代码:Test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqList.h"

void SLTest01()
{
	SL sl;
	SLInit(&sl);
	//测试尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);// 1 2 3 4
	SLPrint(&sl);
	//SLPushBack(&sl, 5);
	//SLPrint(&sl);


	//头插
	/*SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	SLPushFront(&sl, 7);*///7 6 5 1 2 3 4

	//SLPrint(&sl);

	//尾删
	//SLPopBack(&sl);
	//SLPopBack(&sl);
	//SLPopBack(&sl);
	//SLPopBack(&sl);
	//SLPopBack(&sl);

	/*SLPopFront(&sl);
	SLPopFront(&sl);
	SLPrint(&sl);
	SLPopFront(&sl);

	SLPrint(&sl);*/

	//指定位置插入
	//SLInsert(&sl, 0, 100);
	//SLPrint(&sl);//100 1 2 3 4
	//SLInsert(&sl, sl.size, 200);
	//SLPrint(&sl);//100 1 2 3 4 200

	//SLInsert(&sl, 100, 300);
	//SLPrint(&sl);//100 1 2 3 4 200

	//SLErase(&sl, 0);
	//SLPrint(&sl);
	//SLErase(&sl, sl.size-1);
	//SLPrint(&sl);
	SLErase(&sl, 1);
	SLPrint(&sl);

}

void SLTest02()
{
	SL sl;
	SLInit(&sl);
	//测试尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);// 1 2 3 4
	SLPrint(&sl);

	//测试查找 
	int ret = SLFind(&sl, 30);
	if (ret < 0) {
		printf("数据不存在,查找失败!\n");
	}
	else
	{
		printf("数据找到了, 在下标为%d位置\n", ret);
	}
}

void SLTest03()
{
	SL sl;
	SLInit(&sl);
	//测试尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);// 1 2 3 4
	SLPrint(&sl);
	//测试销毁
	SLDestroy(&sl);
	SLPrint(&sl);

}

int main()
{
	//SLTest01();
	//SLTest02();
	SLTest03();

	return 0;
}

 大家可以根据上述思路和提供的源码,自己练习哦~

后续数据结构的学习,大家需要多画图,多练习代码,这样在实现中能够得心应手~

那么本期博客就讲到这里,如果对你有所帮助~ 别忘了收藏点赞哦

有疑问的,可以随时在评论区骚扰我哟~

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

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

相关文章

Visionpro二次开发学习笔记8-如何将静态或交互式图形添加到CogDisplay中

如何将静态或交互式图形添加到CogDisplay中 CogDisplay支持两种类型的图形&#xff1a;静态图形和交互式图形。静态图形一旦添加到显示中&#xff0c;就无法移动或更改。静态图形不能添加提示文本&#xff08;TipText&#xff09;。 交互式图形在启用图形的交互属性时&#x…

【数据结构】-----二叉搜索树(C++)

目录 前言 一、是什么 ​编辑 二、实现 Ⅰ、结点类 Ⅱ、结构及基本接口实现 ​编辑 ①插入 ②查找 ③删除(重难点) 情况一&#xff1a;待删除结点为叶子结点(无孩子) 情况二&#xff1a;待删除结点存在一个孩子结点(可能左/右) 情况三&#xff1a;待删除结点存在…

【iOS】—— 事件传递链和响应者链总结

事件传递链和响应者链总结 1. 事件传递链&#xff1a;事件传递链&#xff1a;传递流程&#xff1a;总结第一响应者&#xff1a; 2. 响应者链响应者链传递流程总结响应者链流程 总结&#xff1a; 之前也学习过这个内容这次在复习的时候&#xff0c;就想着写一下总结&#xff1a;…

Linux部署python3.0版本——及基本操作

&#xff08;一&#xff09;部署环境 首先查看列表&#xff0c;找到python3.0的包 yum list installed|grep python 如果没有&#xff0c;是因为yum源的问题&#xff0c;可部署阿里云镜像然后下载epel包&#xff0c;这里的内容可参考前面的阿里云镜像部署 然后进行下载 yum…

TensorRT-LLM中的 Quantization GEMM(Ampere Mixed GEMM)的 CUTLASS 2.x 实现讲解

在LLM的推理和部署中&#xff0c;低精度量化对于性能的提升十分关键&#xff0c;本次分享将为大家介绍TRT-LLM中是如何基于CUTLASS 2.x来实现PerChannel/AWQ/SmoothQuant等量化方法在模型推理过程的计算。Slides来自BiliBili NVIDIA英伟达频道 上传的《TensorRT-LLM中的 Quanti…

最新CSS3伪类和伪元素详解

第4章 伪类和伪元素 4.1结构伪类 E:first-child{},第一个元素 样式&#xff1a; p:first-child {color: red; } <div><p>Lorem ipsum</p><p>Dolor sit amet.</p> </div> 4.1.1nth-*伪类 以计数为基础的&#xff0c;默认情况下&…

某赛通电子文档安全管理系统 CDGAuthoriseTempletService1 SQL注入漏洞复现(XVE-2024-19611)

0x01 产品简介 某赛通电子文档安全管理系统(简称:CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护,系统具有透明加密、主动加密、智能…

RPA在政务服务中的挑战与解决方案

随着数字化时代的到来&#xff0c;数字政务的建设已成必然趋势&#xff0c;RPA作为数字化转型的重要工具之一&#xff0c;能够帮助政府单位快速实现业务流程的自动化和智能化&#xff0c;提高工作效率和质量&#xff0c;为建设数字政务提供强有力的支持&#xff0c;因此正被越来…

深植根基、蓬勃向上 | openKylin 2.0正式发布!

2024年8月8日&#xff0c;openKylin 2.0版本正式发布&#xff01;该版本默认搭载Linux 6.6 LTS内核&#xff0c;完成180操作系统核心组件自主选型升级&#xff0c;深度融合AI技术&#xff0c;上线麒麟AI助手等实用AI功能&#xff0c;并为用户带来包括开明软件包格式、不可变系统…

Unity 在Editor下保存对Text组件的文本的修改

Unity 在Editor下保存对Text组件的文本的修改 /****************************************************文件&#xff1a;TimeStampForText.cs作者&#xff1a;lenovo邮箱: 日期&#xff1a;2024/8/8 1:9:21功能&#xff1a; *************************************************…

聚观早报 | 小米15 Ultra相机规格;一加Ace 5参数规格

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 8月8日消息 小米15 Ultra相机规格 一加Ace 5参数规格 iOS 18.1代码曝光 SK电讯加大AI投入 Figure 02 人形机器人…

【VScode】如何在anaconda虚拟环境中打开vscode项目

文章目录 【必备知识】打开anaconda虚拟环境切换到项目工作目录激活anaconda虚拟路径让vscode从当前目录打开 【必备知识】 anaconda环境变量配置及配置python虚拟环境 https://blog.csdn.net/xzzteach/article/details/140621596 打开anaconda虚拟环境 切换到项目工作目录 …

Ftrans文件摆渡方案:重塑文件传输与管控的科技先锋

一、哪些行业会用到文件摆渡相关方案 文件摆渡相关的产品和方案通常用于需要在不同的网络、安全域、网段之间传输数据的场景&#xff0c;主要是一些有核心数据需要保护的行业&#xff0c;做了网络隔离和划分。以下是一些应用比较普遍的行业&#xff1a; 金融行业&#xff1a;…

第 11 课:多方安全计算在安全核对的行业实践

业务背景&#xff1a;安全核对产生的土壤 产品方案&#xff1a;从试点到规模化的路 技术共建&#xff1a;与隐语的共同成长

three.js 空间坐标绘制多边形围栏(结合react)

空间坐标点绘制多边形&#xff0c;实际上可以理解为是由 “点” 到 “线” 到 “面” 的一个过程。将空间坐标点通过THREE.Shape绘制多条线并闭合而得到一个封闭的二维形状平面对象&#xff0c;使用THREE.ShapeGeometry将Shape对象转换为Geometry对象添加Mesh&#xff0c;最终得…

全国多地公布2024下半年软考报名具体时间

下半年开考科目&#xff1a; 高级资格&#xff1a;系统分析师、系统架构设计师、网络规划设计师、系统规划与管理师 中级资格&#xff1a;软件设计师、网络工程师、信息安全工程师、信息系统监理师、多媒体应用设计师、系统集成项目管理工程师 初级资格&#xff1a;网络管理…

【时时三省】(C语言基础)操作符2

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ——csdn时时三省 赋值操作符 它可以重新赋值 示例: 使用赋值操作符赋值 复合赋值符 &#xff0b;&#xff1d; -&#xff1d; &#xff0a;&#xff1d; /&#xff1d; &#xff05;&#xff1d; &g…

Linux磁盘管理_LVM逻辑卷_SWAP交换分区_Centos-LVM格式磁盘扩容

目录 一、基本磁盘管理1.1 创建分区1.2 创建文件系统1.3 挂载mount1.4 查看挂载信息1.5 重启失效解决方式 二、逻辑卷LVM2.1 LVM2.2 创建LVM2.3 扩大卷组VG2.4 命令汇总 三、交换分区SWAP管理3.1 SWAP3.2 查看swap3.3 增加交换分区 四、Centos调整分区&#xff0c;在线调整分区…

05 数据类型

目录 分类数值类型小数类型字符串类型日期和时间类型集合类型 1. 分类 2. 数值类型 tinyint create table t1 (num tinyint); insert into t1 values (1); insert into t1 values (128); – 越界插入&#xff0c;报错 select * from t1; 说明: 在mysql中&#xff0c;整形可以指…

LeetCode面试150——14最长公共前缀

题目难度&#xff1a;简单 默认优化目标&#xff1a;最小化平均时间复杂度。 Python默认为Python3。 目录 1 题目描述 2 题目解析 3 算法原理及代码实现 3.1 横向扫描 3.2 纵向扫描 3.3 分治 3.4 二分查找 参考文献 1 题目描述 编写一个函数来查找字符串数组中的最长…