第 2 章 线性表 ( 具有实用意义的线性链表(带头结点)实现)

news2024/11/25 10:35:51

1. 背景说明

链表中携带尾指针信息能够在插入新结点时提高效率。

2. 示例代码

1) status.h

/* DataStructure 预定义常量和类型头文件 */

#ifndef STATUS_H
#define STATUS_H

#define CHECK_NULL(pointer) if (!(pointer)) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PTR); \
	return NULL; \
}

#define CHECK_RET(ret) if (ret != RET_OK) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ret); \
	return ret; \
}

#define CHECK_VALUE(value, ERR_CODE) if (value) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
	return ERR_CODE; \
}

#define CHECK_FALSE(value, ERR_CODE) if (!(value)) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
	return FALSE; \
} 

/* 函数结果状态码 */
#define TRUE 					1			/* 返回值为真 */
#define FALSE 					0			/* 返回值为假 */
#define RET_OK 					0			/* 返回值正确 */
#define INFEASIABLE    		   	2			/* 返回值未知 */
#define ERR_MEMORY     		   	3			/* 访问内存错 */
#define ERR_NULL_PTR   			4			/* 空指针错误 */
#define ERR_MEMORY_ALLOCATE		5			/* 内存分配错 */
#define ERR_NULL_STACK			6			/* 栈元素为空 */
#define ERR_PARA				7			/* 函数参数错 */
#define ERR_OPEN_FILE			8			/* 打开文件错 */
#define ERR_NULL_QUEUE			9			/* 队列为空错 */
#define ERR_FULL_QUEUE			10			/* 队列为满错 */
#define ERR_NOT_FOUND			11			/* 表项不存在 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */

#endif // !STATUS_H

2) linkList.h

/* 具有实用意义的线性链表(带头结点)实现头文件 */

#ifndef LINKLIST_H
#define LINKLIST_H

#include "status.h"

typedef int ElemType;

typedef struct LNode {
	ElemType data;
	struct LNode *next;
} LNode, *Link, *Position;

typedef struct LinkList {
	Link head;
	Link tail;
	int length;
} LinkList;

/* 分配由指向的值为 e 的结点,并返回 OK;若分配失败, 则返回 NULL */
Link MakeNewLNode(ElemType e);

/* 释放 p 所指结点 */
void FreeLNode(Link *p);

/* 构造一个空的线性链表 */
Status InitList(LinkList *L);

/* 将线性链表 L 重置为空表,并释放原链表的结点空间 */
Status ClearList(LinkList *L);

/* 销毁线性链表 L,L 不再存在 */
Status DestroyList(LinkList *L);

/* h 指向 L 的一个结点,把 head 当做头结点,将 s 所指结点插入在第一个结点之前 */
Status InsFirst(LinkList *L, Link head, Link s);

/* h 指向 L 的一个结点,把 h 当做头结点,删除链表中的第一个结点并以 q 返回
   若链表为空( h 指向尾结点),q = NULL,返回 FALSE */
Status DelFirst(LinkList *L, Link head, Link *q);

/* 将指针 s(s->data 为第一个数据元素)所指(彼此以指针相链,以 NULL 结尾)的一
   串结点链接在线性链表L的最后一个结点之后,并改变链表 L 的尾指针指向新的尾结点 */
Status Append(LinkList *L, Link s);

/* 已知 p 指向线性链表 L 中的一个结点,返回 p 所指结点的直接前驱的位置若无前驱
   则返回 NULL */
Position PriorPos(LinkList L, Link p);

/* 删除线性链表 L 中的尾结点并以 q 返回,改变链表 L 的尾指针指向新的尾结点 */
Bollean Remove(LinkList *L, Link *q);

/* 已知 *p 指向线性链表 L 中的一个结点,将 s 所指结点插入在 *p 所指结点之前
   并修改指针 p 指向新插入的结点 */
Status InsBefore(LinkList *L, Link *p, Link s);

/* 已知 *p 指向线性链表 L 中的一个结点,将 s 所指结点插入在 *p 所指结点之后
   并修改指针 p 指向新插入的结点 */
Status InsAfter(LinkList *L, Link *p, Link s);

/* 已知 p 指向线性链表中的一个结点,用 e 更新 p 所指结点中数据元素的值 */
Status SetCurrElem(Link p, ElemType e);

/* 已知 p 指向线性链表中的一个结点,返回 p 所指结点中数据元素的值 */
ElemType GetCurrElem(Link p);

/* 若线性链表 L 为空表,则返回 TRUE,否则返回 FALSE */
Bollean ListEmpty(LinkList L);

/* 返回线性链表 L 中元素个数 */
int ListLength(LinkList L);

/* 返回线性链表 L 中头结点的位置 */
Position GetHead(LinkList L);

/* 返回线性链表 L 中最后一个结点的位置 */
Position GetLast(LinkList L);

/* 已知 p 指向线性链表 L 中的一个结点,返回 p 所指结点的直接后继的位置
   若无后继,则返回 NULL */
Position NextPos(Link p);

/* 返回 p 指示线性链表 L 中第 i 个结点的位置,并返回 OK,i 值不合法时
   返回 ERROR, i = 0 为头结点 */
Status LocatePos(LinkList L, int i, Link *p);

/* 返回线性链表 L 中第 1 个与 e 满足函数 compare() 判定关系的元素的位
   置若不存在这样的元素,则返回 NULL */
Position LocateElem(LinkList L, ElemType e, Bollean(*compare)(ElemType, ElemType));

/* 依次对 L 的每个数据元素调用函数 visit()。一旦 visit() 失败,则操作失败 */
Status ListTraverse(LinkList L, void(*visit)(ElemType));

/* 已知 L 为有序线性链表,将元素 e 按非降序插入在 L 中 */
Status InsertAscend(LinkList *L, ElemType e, int(*compare)(ElemType, ElemType));

/* 若升序链表 L 中存在与 e 满足判定函数 compare() 取值为 0 的元素,则 q 指示 L 中
   第一个值为 e 的结点的位置,并返回 TRUE;否则 q 指示第一个与 e 满足判定函数
   compare() 取值 > 0 的元素的前驱的位置, 并返回 FALSE */
Bollean LocateElemP(LinkList L, ElemType e, Position *q, int(*compare)(ElemType, ElemType));

#endif // !LINKLIST_H

3) linkList.c

/* 具有实用意义的线性链表(带头结点)实现源文件 */

#include "linkList.h"
#include <stdio.h>
#include <stdlib.h>

/* 分配由指向的值为 e 的结点,并返回 OK;若分配失败, 则返回 NULL */
Link MakeNewLNode(ElemType e)
{
	Link newLNode = (Link)malloc(sizeof(LNode));
	CHECK_NULL(newLNode)
	newLNode->data = e;
	newLNode->next = NULL;

	return newLNode;
}

/* 释放 p 所指结点 */
void FreeLNode(Link *p)
{
	free(*p);
	*p = NULL;
}

/* 构造一个空的线性链表 */
Status InitList(LinkList *L)
{
	Link p = (Link)malloc(sizeof(LNode));
	CHECK_VALUE(!p, ERR_MEMORY_ALLOCATE)
	p->next = NULL;
	(*L).head = (*L).tail = p;
	(*L).length = 0;

	return RET_OK;
}

/* 将线性链表 L 重置为空表,并释放原链表的结点空间 */
Status ClearList(LinkList *L)
{
	CHECK_VALUE(!L, ERR_NULL_PTR)
	if ((*L).head == (*L).tail) {
		return RET_OK;
	}

	Link p, q;
	p = (*L).head->next;
	(*L).head->next = NULL;
	while (p != (*L).tail) {
		q = p;
		p = p->next;
		free(q);
	}

	free(p);
	(*L).tail = (*L).head;
	(*L).length = 0;

	return RET_OK;
}

/* 销毁线性链表 L,L 不再存在 */
Status DestroyList(LinkList *L)
{
	ClearList(L);
	FreeLNode(&((*L).head));
	(*L).tail = NULL;
	
	return RET_OK;
}

/* h 指向 L 的一个结点,把 head 当做头结点,将 s 所指结点插入在第一个结点之前 */
Status InsFirst(LinkList *L, Link head, Link s)
{
	s->next = head->next;
	head->next = s;
	if (head == (*L).tail) {
		(*L).tail = head->next;
	}

	++((*L).length);

	return RET_OK;
}

/* h 指向 L 的一个结点,把 h 当做头结点,删除链表中的第一个结点并以 q 返回
   若链表为空( h 指向尾结点),q = NULL,返回 FALSE */
Status DelFirst(LinkList *L, Link head, Link *q)
{
	*q = head->next;
	if (!(*q)) {
		return FALSE;
	}

	head->next = (*q)->next;
	if (!(head->next)) {
		(*L).tail = head;
	}

	--(*L).length;

	return RET_OK;
}

/* 将指针 s(s->data 为第一个数据元素)所指(彼此以指针相链,以 NULL 结尾)的一
   串结点链接在线性链表L的最后一个结点之后,并改变链表 L 的尾指针指向新的尾结点 */
Status Append(LinkList *L, Link s)
{
	int length = 1;
	(*L).tail->next = s;
	while (s->next) {
		++length;
		s = s->next;
	}

	(*L).tail = s;
	(*L).length += length;

	return RET_OK;
}

/* 已知 p 指向线性链表 L 中的一个结点,返回 p 所指结点的直接前驱的位置若无前驱
   则返回 NULL */
Position PriorPos(LinkList L, Link p)
{
	Link q = L.head->next;
	if (p == q) {
		return NULL;
	}

	while (q->next != p) {
		q = q->next;
	}

	return q;
}

/* 删除线性链表 L 中的尾结点并以 q 返回,改变链表 L 的尾指针指向新的尾结点 */
Bollean Remove(LinkList *L, Link *q)
{
	CHECK_VALUE(!L, ERR_NULL_PTR)
	if ((*L).length == 0) {
		*q = NULL;
		return FALSE;
	}

	Link p = (*L).head;
	while (p->next != (*L).tail) {
		p = p->next;
	}

	*q = (*L).tail;
	p->next = NULL;
	(*L).tail = p;
	--((*L).length);

	return TRUE;
}

/* 已知 *p 指向线性链表 L 中的一个结点,将 s 所指结点插入在 *p 所指结点之前
   并修改指针 *p 指向新插入的结点 */
Status InsBefore(LinkList *L, Link *p, Link s)
{
	Link q = PriorPos(*L, *p);
	if (!q) {
		q = (*L).head;
	}

	s->next = *p;
	q->next = s;
	*p = s;
	++((*L).length);

	return RET_OK;
}

/* 已知 *p 指向线性链表 L 中的一个结点,将 s 所指结点插入在 *p 所指结点之后
   并修改指针 p 指向新插入的结点 */
Status InsAfter(LinkList *L, Link *p, Link s)
{
	if (*p == (*L).tail) {
		(*L).tail = s;
	}

	s->next = (*p)->next;
	(*p)->next = s;
	*p = s;
	++((*L).length);

	return RET_OK;
}

/* 已知 p 指向线性链表中的一个结点,用 e 更新 p 所指结点中数据元素的值 */
Status SetCurrElem(Link p, ElemType e)
{
	p->data = e;

	return RET_OK;
}

/* 已知 p 指向线性链表中的一个结点,返回 p 所指结点中数据元素的值 */
ElemType GetCurrElem(Link p)
{
	return p->data;
}

/* 若线性链表 L 为空表,则返回 TRUE,否则返回 FALSE */
Bollean ListEmpty(LinkList L)
{
	return (L.length == 0) ? TRUE : FALSE;
}

/* 返回线性链表 L 中元素个数 */
int ListLength(LinkList L)
{
	return L.length;
}

/* 返回线性链表 L 中头结点的位置 */
Position GetHead(LinkList L)
{
	return L.head;
}

/* 返回线性链表 L 中最后一个结点的位置 */
Position GetLast(LinkList L)
{
	return L.tail;
}

/* 已知 p 指向线性链表 L 中的一个结点,返回 p 所指结点的直接后继的位置
   若无后继,则返回 NULL */
Position NextPos(Link p)
{
	return p->next;
}

/* 返回 p 指示线性链表 L 中第 i 个结点的位置,并返回 OK,i 值不合法时
   返回 ERROR, i = 0 为头结点 */
Status LocatePos(LinkList L, int i, Link *p)
{
	CHECK_VALUE((i < 0 || i > L.length), ERR_PARA)
	*p = L.head;
	for (int j = 0; j < i; ++j) {
		*p = (*p)->next;
	}

	return RET_OK;
}

/* 返回线性链表 L 中第 1 个与 e 满足函数 compare() 判定关系的元素的位
   置若不存在这样的元素,则返回 NULL */
Position LocateElem(LinkList L, ElemType e, Bollean(*compare)(ElemType, ElemType))
{
	Link p = L.head->next;
	while ((p) && !(compare(p->data, e))) {
		p = p->next;
	}
	
	return p;
}

/* 依次对 L 的每个数据元素调用函数 visit()。一旦 visit() 失败,则操作失败 */
Status ListTraverse(LinkList L, void(*visit)(ElemType))
{
	Link p = L.head->next;
	for (int i = 0; i < L.length; ++i) {
		visit(p->data);
		p = p->next;
	}

	return RET_OK;
}

/* 已知 L 为有序线性链表,将元素 e 按非降序插入在 L 中 */
Status InsertAscend(LinkList *L, ElemType e, int(*compare)(ElemType, ElemType))
{
	Link q = (*L).head;
	Link p = q->next;
	while ((p) && (compare(p->data, e) < 0)) {
		q = p;
		p = p->next;
	}

	Link newLNode = MakeNewLNode(e);
	q->next = newLNode;
	newLNode->next = p;
	++((*L).length);
	if (!p) {
		(*L).tail = newLNode;
	}

	return RET_OK;
}

/* 若升序链表 L 中存在与 e 满足判定函数 compare() 取值为 0 的元素,则 q 指示 L 中
   第一个值为 e 的结点的位置,并返回 TRUE;否则 q 指示第一个与 e 满足判定函数
   compare() 取值 > 0 的元素的前驱的位置, 并返回 FALSE */
Bollean LocateElemP(LinkList L, ElemType e, Position *q, int(*compare)(ElemType, ElemType))
{
	Link pos = L.head;
	Link p = pos->next;
	while ((p) && (compare(p->data, e) < 0)) {
		pos = p;
		p = p->next;
	}

	if ((!p) || (compare(p->data, e) > 0)) {
		*q = pos;
		return FALSE;
	}

	*q = p;

	return TRUE;
}

4) main.c

/* 入口程序源文件 */

#include "linkList.h"
#include <stdio.h>

Bollean Compare1(ElemType e1, ElemType e2);
int Compare2(ElemType e1, ElemType e2);
void Visit(ElemType e);

int main(void)
{
	LinkList L;
	Status ret = InitList(&L);
	CHECK_RET(ret)
	Link p;
	for (int i = 0; i < 2; ++i) {
		p = MakeNewLNode(i + 1);
		InsFirst(&L, L.tail, p);
	}
	
	InsertAscend(&L, 0, Compare2);
	for (int i = 0; i < 4; ++i) {
		ret = LocateElemP(L, i, &p, Compare2);
		if (ret) {
			printf("%d is exist in L\n", p->data);
		} else {
			printf("%d is not exist in L\n", i);
		}
	}

	printf("Now L is: ");
	ListTraverse(L, Visit);
	putchar('\n');
	for (int i = 0; i < 4; ++i) {
		printf("Delete head node: ");
		DelFirst(&L, L.head, &p);
		if (p) {
			printf("%d\n", GetCurrElem(p));
		} else {
			printf("Can not delete %p\n", p);
		}
	}

	printf("The elements num in L is %d, L is %s\n", ListLength(L), (ListEmpty(L) == TRUE)
		? "empty" : "not empty");
	p = MakeNewLNode(10);
	Link q;
	for (int i = 4; i > 0; --i) {
		q = MakeNewLNode(2 * i);
		q->next = p;
		p = q;
	}

	Append(&L, q);
	InsertAscend(&L, 12, Compare2);
	InsertAscend(&L, 7, Compare2);
	printf("Now L is: ");
	ListTraverse(L, Visit);
	putchar('\n');
	for (int i = 0; i < 2; ++i) {
		p = LocateElem(L, (i + 1) * 5, Compare1);
		if (p) {
			printf("%d is exist in L\n", p->data);
		} else {
			printf("%d is not exist in L\n", (i + 1) * 5);
		}
	}

	for (int i = 0; i < 2; ++i) {
		LocatePos(L, i + 1, &p);
		Link pre = PriorPos(L, p);
		if (pre) {
			printf("The prior element of %d is %d\n", p->data, pre->data);
		} else {
			printf("%d do not have previous element\n", p->data);
		}
	}

	int length = ListLength(L);
	for (int i = length - 1; i < length + 1; ++i) {
		LocatePos(L, i, &p);
		Link next = NextPos(p);
		if (next) {
			printf("The next element of %d is %d\n", p->data, next->data);
		} else {
			printf("%d do not have next element\n", p->data);
		}
	}

	printf("The elements num in L is %d, L is %s\n", ListLength(L), (ListEmpty(L) == TRUE)
		? "empty" : "not empty");
	p = GetLast(L);
	SetCurrElem(p, 15);
	printf("The first element in L is %d, the last element in L is %d\n",
		GetCurrElem(GetHead(L)->next), GetCurrElem(p));
	q = MakeNewLNode(10);
	InsBefore(&L, &p, q);
	p = p->next;
	q = MakeNewLNode(20);
	InsAfter(&L, &p, q);
	length = ListLength(L);
	printf("Delete tail in L one by one:\n");
	for (int i = 0; i < length + 1; ++i) {
		Status ret = Remove(&L, &p);
		if (!ret) {
			printf("Delete failed!\n");
		} else {
			printf("Delete %d success!\n", p->data);
		}
	}

	p = MakeNewLNode(29);
	InsFirst(&L, L.head, p);
	printf("Now L is: ");
	ListTraverse(L, Visit);
	putchar('\n');

	DestroyList(&L);
	printf("After destroy L, L.head = %p, L.tail = %p, L.length = %d\n", L.head, L.tail, L.length);

	return 0;
}

Bollean Compare1(ElemType e1, ElemType e2)
{
	return (e1 == e2) ? TRUE : FALSE;
}

int Compare2(ElemType e1, ElemType e2)
{
	return (e1 == e2) ? 0 : ((e1 < e2) ? -1 : 1);
}

void Visit(ElemType e)
{
	printf("%d ", e);
}

3. 输出示例

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

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

相关文章

Matlab之创建空数组的多种方法汇总

一、matlab空数组是什么&#xff1f; 在MATLAB中&#xff0c;空数组是指没有元素的数组对象。它可以用于占位或者作为容器&#xff0c;等待后续添加元素。 二、创建空数组的多种方法 1、使用空方括号 [] 创建空矩阵 A []; % 创建一个空双精度矩阵 B logical([]); % 创建一…

Unity Shader 溶解带描边

一、效果图 二、原理分析 实现原理就是在片元着色器中&#xff0c;对像素点进行渐进丢弃不显示。借助美术做的噪点图(利用噪点图中rgb中r值来做计算)。比如噪点图r值从0-1。我们从小到大让r值逐渐丢弃&#xff0c;比如刚开始r < 0.1丢弃&#xff0c;然后t < 0.2丢弃...知…

【GO语言基础】控制流

系列文章目录 【Go语言学习】ide安装与配置 【GO语言基础】前言 【GO语言基础】变量常量 【GO语言基础】数据类型 【GO语言基础】控制流 文章目录 系列文章目录条件语句if-else 结构判断一个字符串是否为空&#xff1a;switch结构 循环结构for 循环&#xff08;C风格&#xff…

CSS 实现让最后一排元素向左对齐并且整体要居中的几种方式

背景 好久没写 CSS 了&#xff0c;最近产品提了个样式需求&#xff0c;让列表最后一排的元素要向左对齐&#xff0c;而不是居中分配&#xff0c;如图&#xff1a; 由于项目采用 flex 布局&#xff0c;一开始想到的是直接给容器加个 justify-content: flex-start 看起来确实…

【C++】day3学习成果:类

1.自行封装一个栈的类&#xff0c;包含私有成员属性&#xff1a;栈的数组、记录栈顶的变量 成员函数完成&#xff1a;构造函数、析构函数、拷贝构造函数、入栈、出栈、清空栈、判空、判满、获取栈顶元素、求栈的大小 头文件stack.h: #ifndef STACK_H #define STACK_H#include …

计算机专业毕业设计项目推荐01-生产管理系统(JavaSpringBoot+原生Js+Mysql)

生产管理系统&#xff08;JavaSpringBoot原生JsMysql&#xff09; **介绍****系统总体开发情况-功能模块****各部分模块实现****最后想说的****联系方式** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以…

LLM 位置编码及外推

RoPE https://zhuanlan.zhihu.com/p/629681325 PI 位置插值&#xff08;POSITION INTERPOLATION&#xff09;显著改善RoPE的外推能力。你只需要对PT&#xff08;pretraining)模型fine-turing最多1000步就能实现。PI是通过将线性的缩小了输入位置的索引使其匹配原始上下文窗口…

【Java 基础篇】Java ArrayList 指南:无所不能的数据伴侣

Java 是一门流行的编程语言&#xff0c;拥有丰富的集合类库&#xff0c;其中之一是 ArrayList。ArrayList 是 Java 集合框架中的一个重要类&#xff0c;它允许我们以动态数组的方式存储和操作数据。无论你是初学者还是有一定经验的开发者&#xff0c;本篇博客都将为你详细介绍 …

怎样吃透一个java项目?

前言 对于刚开始看视频敲代码&#xff0c;最忌讳的便是一上来就完全照着视频做&#xff0c;这么做就算完完全全的跟着视频做出来一个项目&#xff0c;始终都无法将里面具体的知识化为己有&#xff0c;单纯来说只是简单的复刻&#xff0c;视频的作者本身是不会对他在做该项目过…

TouchGFX之自定义触发条件和操作

通过TouchGFX Designer&#xff0c;您可以自己定义具有触发条件和操作的交互组件。 自定义容器创建自定义触发条件&#xff1a;通过自定义容器的属性选项卡添加自定义触发条件 使用交互系统发送自定义触发条件&#xff1a; 通过自定义容器的“交互”选项卡&#xff0c;创建新的…

【工具使用】Dependency Walker使用

一&#xff0c;简介 在工作过程中常常会遇到编译的dll库运行不正常的情况&#xff0c;那就需要确认dll库是否编译正常&#xff0c;即是否将函数编译到dll中去。今天介绍一种查看dll库中函数定义的工具——Dependency walker。 二&#xff0c;软件介绍 Dependency Walker是一…

centos7安装kubernets集群

一、准备工作 准备三台虚拟机&#xff0c;centos7系统 二、系统配置 1. 修改主机名 # 三台机器都需要执行 hostnamectl set-hostname k8s-master hostnamectl set-hostname k8s-node1 hostnamectl set-hostname k8s-node22. 修改hosts文件 # 三台机器都需要执行 [rootk8s-…

微信小程序开发教学系列(2)- 抖音小程序开发基础

2.1 抖音小程序的基本组成部分 抖音小程序的目录结构非常简单&#xff0c;主要包含以下几个核心文件和文件夹&#xff1a; app.json 文件&#xff1a;用于配置小程序的全局配置&#xff0c;包括窗口样式、页面路径、网络请求设置等等。pages 文件夹&#xff1a;用于存放所有的…

智慧工地:实现作业区域安全管控

智慧工地是围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效。 建设工程安全文明施工与质量提升,全方位的监测施工人员、各类器械设备、消防安全隐患&#xff0c;并提前对风险进行预警…

高校网络安全体系建设及零信任安全架构应用的探索

网络安全是高校信息化建设的重中之重&#xff0c;它同时也随着高校信息化的快速发展而不断面临新的挑战。因此&#xff0c;要用发展的眼光去看待网络安全&#xff0c;体系化推进网络安全体系建设。山东师范大学校园信息化经过10多年的建设发展&#xff0c;在网络安全上探索出了…

博客系统(升级(Spring))(一)创建数据库,创建实例化对象,统一数据格式,统一报错信息

博客系统&#xff08;一&#xff09; 博客系统创建项目 建立数据库结构链接服务器和数据库和Redis 创建实例化对象统一数据结构结构 统一报错信息 博客系统 博客系统是干什么的&#xff1f; CSDN就是一个典型的博客系统。而我在这里就是通过模拟实现一个博客系统&#xff0c;这…

SAP中的新旧事务码

SAP中的新旧事务码 SAP随着新版本的发布&#xff0c;我们知道sap已经更新了很多的程序和TCODE。sap提供了很多新的TCODE来替换旧的TCODE&#xff0c;新TCODE有很多的新特性和新功能。在这个这种情况下&#xff0c;很多旧TCODE就会被废弃。我们如何查找这个替换呢&#xff1f; …

如何使用OpenGL画出ROS rviz那样的点云可视化效果

【请尊重原创&#xff01;转载和引用文章内容务必注明出处&#xff01;未经许可上传到某文库或其他收费阅读/下载网站赚钱的必追究责任&#xff01;】 ROS rviz可以将点云以多种形式渲染出来比较漂亮&#xff0c;尤其是根据intensity渲染点云不同的色彩和亮度的功能比较好&…

List集合详解

目录 1、集合是什么&#xff1f; 1.1、集合与集合之间的关系 2、List集合的特点 3、遍历集合的三种方式 3.1、foreach(增强佛如循环遍历) 3.2、for循环遍历 3.3、迭代器遍历 4、LinkedList和ArrayList的区别 4.1、为什么ArrayList查询会快一些&#xff1f; 4.2、为什么LinkedLi…

2023大数据挑战赛全国六强团队获奖经验+ppt分享(五)

团队名称 会魔法的老人 团队成员 刘克林&#xff08;重庆邮电大学&#xff09; 敖宇&#xff08;重庆邮电大学&#xff09; 杨敏&#xff08;重庆邮电大学&#xff09; 团队名次 全国第二名 赛题描述说明介绍 2023大数据挑战赛赛题说明决赛评分标准回顾 参赛分享与收获 本次大赛…