一篇带你走进线性表之顺序表(C语言阐述)——逐行解释代码

在这里插入图片描述

目录哇

  • 1. 引言
    • - 顺序表在数据结构中的地位和作用
    • - 概述本文将讨论的内容和结构
  • 2. 顺序表的基本概念
    • - 定义:什么是顺序表?
    • - 结构:顺序表的内部结构和特点
  • 3. 实现一个基本的顺序表
    • ***需要用到的头文件***
    • ***定义顺序表的基本结构和属性***
    • ***实现顺序表的初始化***
    • ***销毁***
    • ***打印***
    • ***检查容量***
    • ***尾插***
    • ***头插***
    • ***尾删***
    • ***头删***
    • ***任意下标位置的插入***
    • ***任意下标位置的删除***
    • ***查找***
    • ***代码合集***
  • 4. 顺序表的优缺点分析
    • - 优点:顺序表的性能优势
    • - 缺点:顺序表的局限性和可能的改进空间
  • 5. 顺序表的应用场景
    • - 实际应用:顺序表在实际项目中的应用案例
    • - 对比分析:与其他数据结构在实际应用中的对比情况
  • 6. 顺序表的扩展与优化
    • - 动态扩容:如何处理顺序表空间不足的情况?
    • - 性能优化:针对顺序表常见操作的性能优化方法

1. 引言

- 顺序表在数据结构中的地位和作用

顺序表是一种线性表的实现方式,通过数组来存储元素,具有快速的随机访问特性。顺序表的设计使得元素在内存中连续存储,这样就可以通过下标直接访问元素,而无需遍历整个表格。这种特性使得顺序表在需要频繁访问元素和对内存空间要求严格的场景下具有显著的优势。在算法设计和实际编程中,顺序表常常被广泛应用,对于提高程序执行效率和节约内存空间都具有重要意义。

- 概述本文将讨论的内容和结构

2. 顺序表的基本概念

- 定义:什么是顺序表?

顺序表是一种线性表的存储结构,它通过一段连续的内存空间存储数据元素,元素之间的逻辑关系与物理位置一一对应。顺序表可以用数组实现,也被称为数组表。在顺序表中,元素的存储是按照其在逻辑上的顺序依次存放的,通过元素在数组中的索引来定位和访问。

- 结构:顺序表的内部结构和特点

顺序表的内部结构由两部分组成:数据存储区和控制信息区。数据存储区用于存放数据元素,通常采用数组来实现;控制信息区用于存储顺序表的一些信息,如表的长度、容量等。

顺序表的特点包括

  • 元素的逻辑次序与物理次序一致;
  • 内存空间是连续分配的;
  • 具有固定的大小(预分配的空间大小);
  • 可以通过下标直接访问元素;
  • 插入和删除操作可能需要移动其他元素。

3. 实现一个基本的顺序表

在这里我们要实现顺序表的初始化、销毁、打印、检查剩余容量+扩容、尾插、头插、尾删、头删、任意下标位置的插入、任意下标位置的删除、查找、二分查找。

需要用到的头文件

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

定义顺序表的基本结构和属性

typedef int SLDataType;		//方便我们随时更改顺序表的数类型
typedef struct SequenceList
{
	SLDataType* a;	// a是指向 SLDataType 类型的指针,用于存储实际的数据数组
	int size;		// 用于表示当前顺序表中有效数据的个数
	int capacity;	// 用于表示当前顺序表的空间容量
};

SLDataType* a:这是一个指向 SLDataType 类型的指针,用于存储实际的数据数组。在顺序表中,通过这个指针可以访问顺序表中的各个元素。

int size:size 用于表示当前顺序表中有效数据的个数。在对顺序表进行操作时,size
可以帮助确定当前顺序表中有多少个元素是有效的。

int capacity:capacity 用于表示当前顺序表的空间容量,即可以容纳的元素个数上限。当顺序表中的元素数量接近
capacity 时,我们需要进行动态扩容操作。

实现顺序表的初始化

void SLInit(SL* s1)
{
	assert(s1);		//确保传入的参数 s1 不为空。如果 s1 为空,程序会中止执行并输出错误信息
	s1->a = NULL;	
	s1->size = 0;
	s1->capacity = 0;
}

assert(s1):使用 assert 宏确保传入的参数 s1 不为空。如果 s1 为空,assert 会触发断言失败,程序会中止执行并输出错误信息。

s1->a = NULL;:将 s1 指向的顺序表的数据数组指针设置为 NULL,表示暂时没有分配内存来存储数据。

s1->size = 0;:将 s1 指向的顺序表的有效数据个数设置为 0,表示当前顺序表中没有有效数据。

s1->capacity = 0;:将 s1 指向的顺序表的空间容量设置为 0,表示当前顺序表的容量为 0。

销毁

void SLDestroy(SL* s1)
{
	assert(s1);
	if (s1->a != NULL)
	{
		free(s1->a);
		s1->a = NULL;
		s1->size = 0;
		s1->capacity = 0;
	}
}

if (s1->a != NULL):检查顺序表的数据数组指针是否为空,避免对空指针进行操作。

free(s1->a):释放顺序表的数据数组所占用的内存空间。

s1->a = NULL;:将顺序表的数据数组指针设置为空,避免出现野指针。

s1->size = 0;:将顺序表的有效数据个数设置为 0,表示当前顺序表中没有有效数据。

s1->capacity = 0;:将顺序表的空间容量设置为 0,表示当前顺序表的容量为 0。

打印

void SLPrint(SL* s1)
{
	assert(s1);
	for (int i = 0; i < s1->size; i++)
	{
		printf("%d", s1->a[i]);
	}
	printf("\n");
}

for (int i = 0; i < s1->size; i++):使用循环遍历顺序表中的所有有效数据。

printf(“%d”, s1->a[i]):对于每个有效数据,使用 printf 函数打印它的值。

printf(“\n”):在循环结束后,使用 printf 函数打印一个换行符,以便下次输出不会与当前输出混在一起。

检查容量

void SLCheckCapacity(SL* sl)
{
	assert(sl);
	if (sl->size == sl->capacity)
	{
		int newCapacity = sl->capacity == 0 ? 4 : sl->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(sl->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		sl->a = tmp;
		sl->capacity = newCapacity;
	}
}

----assert(sl):同样使用了 assert 宏,用于确保传入的参数 sl 不为空。如果 sl 为空,assert
会触发断言失败,程序会中止执行并输出错误信息。

----if (sl->size ==sl->capacity):判断当前顺序表的有效数据个数(size)是否等于容量(capacity)。如果相等,表示当前顺序表已经满了,需要进行动态扩容操作。

----int newCapacity = sl->capacity == 0 ? 4 : sl->capacity *2;:根据当前顺序表的容量计算新的容量。如果原容量为 0,则将新容量设置为 4;否则将新容量设置为原容量的两倍。

----SLDataType* tmp = (SLDataType*)realloc(sl->a, sizeof(SLDataType) *newCapacity);:使用 realloc 函数重新分配内存给顺序表的数据数组。将原来的数据数组指针 sl->a按照新容量分配的大小进行重新分配内存,并将返回的指针赋值给临时变量 tmp。

----if (tmp == NULL):检查 realloc 函数是否成功分配了新的内存。如果分配失败,tmp 会为 NULL。

----perror(“realloc fail”):如果 realloc 函数分配失败,使用 perror 函数输出错误信息。

----- sl->a = tmp;:将重新分配的内存指针 tmp 赋值给顺序表的数据数组指针 sl->a。

----sl->capacity = newCapacity;:将顺序表的容量设置为新容量。

尾插

void SLPushBack(SL* sl,SLDataType k)
{
	assert(sl);
	SLCheckCapacity(sl);
	sl->a[sl->size] = k;
	sl->size++;
}

SLCheckCapacity(sl):调用 SLCheckCapacity 函数,用于检查顺序表的容量是否足够,如果不足则进行扩容操作。

sl->a[sl->size ] = k:将新的数据 k 赋值给顺序表的最后一个位置(下标为 sl->size )。

sl->size++:将顺序表的有效数据个数加一,表示插入了一个新的数据。

头插

void SLPushFront(SL* psl, SLDataType x)
{
	assert(psl);
	SLCheckCapacity(psl);
	int end = psl->size - 1;
	while (end >= 0)
	{
		psl->a[end + 1] = psl->a[end];
		--end;
	}
	psl->a[0] = x;
	psl->size++;
}

SLCheckCapacity(sl):调用 SLCheckCapacity 函数,用于检查顺序表的容量是否足够,如果不足则进行扩容操作。

for (int i = sl->size-1; i > 0; i–):使用循环从顺序表的最后一个元素开始,向前遍历到第一个元素。

sl->a[i + 1] = sl->a[i]:将当前位置的数据向后移动一位,为新的数据腾出空间。

sl->a[0] = k:将新的数据 k 插入到顺序表的开头位置(下标为 0)。

sl->size++:将顺序表的有效数据个数加一,表示插入了一个新的数据。

尾删

void SLPopBack(SL* sl)
{
	assert(sl);
	assert(sl->size > 0);
	sl->size--;
}

assert(sl):使用 assert 宏确保传入的参数 sl 不为空。如果 sl 为空,assert
会触发断言失败,程序会中止执行并输出错误信息。

assert(sl->size > 0):使用 assert
宏确保顺序表中至少有一个数据可供删除。如果顺序表中没有数据可供删除,assert 会触发断言失败,程序会中止执行并输出错误信息。

sl->size–:将顺序表的有效数据个数减一,表示删除了最后一个数据。

头删

void SLPopFront(SL* sl)
{
	assert(sl);
	assert(sl->size > 0);
	for (int i = 1; i < sl->size; i++)
	{
		sl->a[i-1] = sl->a[i];
	}
	sl->size--;
}

-----assert(sl):使用 assert 宏确保传入的参数 sl 不为空。如果 sl 为空,assert会触发断言失败,程序会中止执行并输出错误信息。

----assert(sl->size > 0):使用 assert宏确保顺序表中至少有一个数据可供删除。如果顺序表中没有数据可供删除,assert 会触发断言失败,程序会中止执行并输出错误信息。

for (int i = 1; i < sl->size; i++):使用循环从顺序表的第二个元素开始,向后遍历到最后一个元素。

sl->a[i-1] = sl->a[i]:将当前位置的数据向前移动一位,覆盖前一个位置的数据。

sl->size–:将顺序表的有效数据个数减一,表示删除了第一个数据。

任意下标位置的插入

void SLInsertAnyWhere(SL* sl,int pos,SLDataType k)
{
	assert(sl);
	assert(pos >= 0 && pos <= sl->size);
	for (int i = sl->size - 1; i >= pos; i--)
	{
		sl->a[i + 1] = sl->a[i];
	}
	sl->a[pos] = k;
}

assert(sl):使用 assert 宏确保传入的参数 sl 不为空。如果 sl 为空,assert 会触发断言失败,程序会中止执行并输出错误信息。

assert(pos >= 0 && pos <= sl->size):使用 assert 宏确保插入的位置 pos 合法。如果插入的位置不合法,assert 会触发断言失败,程序会中止执行并输出错误信息。

for (int i = sl->size - 1; i >= pos; i–):使用循环从顺序表的最后一个元素开始,向前遍历到插入位置。

sl->a[i + 1] = sl->a[i]:将当前位置的数据向后移动一位,为新的数据腾出空间。

sl->a[pos] = k:在插入位置处插入新的数据。

sl->size++:将顺序表的有效数据个数加一,表示插入了新的数据。

任意下标位置的删除

void SLPopAnyWhere(SL* sl, int pos, SLDataType k)
{
	assert(sl);
	assert(pos >= 0 && pos <= sl->size);
	for (int i = pos; i < sl->size; i++)
	{
		sl->a[i] = sl->a[i + 1];
	}
	sl->size--;
}

assert(sl):使用 assert 宏确保传入的参数 sl 不为空。如果 sl 为空,assert会触发断言失败,程序会中止执行并输出错误信息。

assert(pos >= 0 && pos <= sl->size):使用 assert 宏确保删除的位置 pos 合法。如果删除的位置不合法,assert 会触发断言失败,程序会中止执行并输出错误信息。

for (int i = pos; i < sl->size; i++):使用循环从指定位置开始,向后遍历到最后一个元素。

sl->a[i] = sl->a[i + 1]:将当前位置的数据向前移动一位,覆盖后一个位置的数据。

sl->size–:将顺序表的有效数据个数减一,表示删除了指定位置的数据。

查找

void SLSer(SL* sl,int pos)
{
	assert(sl);
	for (int i = sl->size; i >= 0; i--)
	{
		if (sl->a[i] == pos)
		{
			printf("%d\n", i);
		}
	}
}

assert(sl):使用 assert 宏确保传入的参数 sl 不为空。如果 sl 为空,assert
会触发断言失败,程序会中止执行并输出错误信息。

for (int i = sl->size; i >= 0; i–):使用循环从顺序表的最后一个元素开始,向前遍历到第一个元素。

if (sl->a[i] == pos):判断当前位置的数据是否等于指定数据。

printf(“%d\n”, i);:如果当前位置的数据等于指定数据,则输出该数据在顺序表中的位置。

代码合集

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* a;
	int size;		// 有效数据
	int capacity;	// 空间容量
}SL;

//初始化
void SLInit(SL* sl)
{
	assert(sl);
	sl->a = NULL;
	sl->size = 0;
	sl->capacity = 0;
}

//销毁
void SLDestroy(SL* sl)
{
	assert(sl);
	if (sl->a != NULL)
	{
		free(sl->a);
		sl->a = NULL;
		sl->size = 0;
		sl->capacity = 0;
	}
}

//打印
void SLPrint(SL* sl)
{
	assert(sl);
	for (int i = 0; i < sl->size; i++)
	{
		printf("%d ", sl->a[i]);
	}
	printf("\n");
}

//检查容量
void SLCheckCapacity(SL* sl)
{
	assert(sl);
	if (sl->size == sl->capacity)
	{
		int newCapacity = sl->capacity == 0 ? 4 : sl->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(sl->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		sl->a = tmp;
		sl->capacity = newCapacity;
	}
}
//尾插
void SLPushBack(SL* sl,SLDataType k)
{
	assert(sl);
	SLCheckCapacity(sl);
	sl->a[sl->size ] = k;
	sl->size++;
}
//头插	
void SLPushFront(SL* sl, SLDataType k)
{
	assert(sl);
	SLCheckCapacity(sl);	
	for (int i = sl->size-1; i >= 0; i--)
	{
		sl->a[i + 1] = sl->a[i];
	}
	sl->a[0] = k;
	sl->size++;
}
//尾删
void SLPopBack(SL* sl)
{
	assert(sl);
	assert(sl->size > 0);
	sl->size--;
}
//头删
void SLPopFront(SL* sl)
{
	assert(sl);
	assert(sl->size > 0);
	for (int i = 0; i < sl->size; i++)
	{
		sl->a[i] = sl->a[i+1];
	}
	sl->size--;
}
//任意下标位置的插入
void SLInsertAnyWhere(SL* sl,int pos,SLDataType k)
{
	assert(sl);
	assert(pos >= 0 && pos <= sl->size);
	for (int i = sl->size - 1; i >= pos; i--)
	{
		sl->a[i + 1] = sl->a[i];
	}
	sl->a[pos] = k;
}
//任意下标位置的删除
void SLPopAnyWhere(SL* sl, int pos, SLDataType k)
{
	assert(sl);
	assert(pos >= 0 && pos <= sl->size);
	for (int i = pos; i < sl->size; i++)
	{
		sl->a[i] = sl->a[i + 1];
	}
	sl->size--;
}
//查找
void SLSer(SL* sl,int pos)
{
	assert(sl);
	for (int i = sl->size; i >= 0; i--)
	{
		if (sl->a[i] == pos)
		{
			printf("%d\n", i);
		}
	}
}

int main()
{
	SL sl;
	SLInit(&sl);
	//尾插
	printf("尾插测试\n");
	SLPushBack(&sl, 10);
	SLPushBack(&sl, 20);
	SLPushBack(&sl, 30);
	SLPushBack(&sl, 40);
	SLPushBack(&sl, 50);
	SLPrint(&sl);
	//头插
	printf("头插测试\n");
	SLPushFront(&sl, 9);
	SLPushFront(&sl, 8);
	SLPushFront(&sl, 7);
	SLPushFront(&sl, 6);
	SLPushFront(&sl, 5);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 1);
	SLPrint(&sl);
	//尾删
	printf("尾删一次测试\n");
	SLPopBack(&sl);
	SLPrint(&sl);
	printf("尾删两次测试\n");
	SLPopBack(&sl);
	SLPrint(&sl);
	//头删
	printf("头删测试\n");
	SLPopFront(&sl);
	SLPrint(&sl);
	//任意下标位置插入
	printf("下标为1的位置插入测试\n");
	SLInsertAnyWhere(&sl, 1,2);
	SLPrint(&sl);
	//任意下标位置的删除
	printf("下标为1的位置删除测试\n");
	SLPopAnyWhere(&sl, 1, 2);
	SLPrint(&sl);
	//查找测试
	printf("查找数值为5的下标位置\n");
	SLPrint(&sl);
	SLSer(&sl, 5);
	return 0;
}

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

4. 顺序表的优缺点分析

- 优点:顺序表的性能优势

  1. 访问速度快:由于顺序表使用连续的内存空间存储元素,并且可以通过下标直接访问元素,因此访问速度非常快。无需遍历或搜索就能够定位和访问指定位置的元素。

  2. 节省存储空间:相比于链表等非顺序存储结构,顺序表使用的是连续的内存空间,不需要额外的指针来连接元素,因此节省了存储空间。

  3. 支持随机访问:顺序表可以根据下标进行随机访问,即可以根据位置直接访问元素。这对于需要频繁按照位置访问元素的场景非常高效。

- 缺点:顺序表的局限性和可能的改进空间

  1. 插入和删除操作耗时:当需要在顺序表中插入或删除元素时,可能需要移动其他元素,导致操作耗时。插入和删除操作的时间复杂度为 O(n),其中 n 是元素的数量。

  2. 固定大小:顺序表的大小是固定的,一旦分配了固定大小的内存空间,就无法动态调整大小。如果元素的数量超过了预分配的空间大小,就需要重新分配更大的空间,进行数据的搬迁,这可能会导致额外的开销。

  3. 不适合频繁插入和删除操作:由于插入和删除操作需要移动其他元素,因此在需要频繁执行插入和删除操作的场景下,顺序表的性能可能较差。

为了克服顺序表的一些缺点,可以考虑以下改进空间:

  1. 引入动态扩容机制:当顺序表的元素数量超过预分配的空间大小时,可以动态扩容,重新分配更大的空间,并将原有的元素复制到新的空间中,以适应更多的元素。

  2. 使用链表实现:对于频繁插入和删除操作较多的场景,可以考虑使用链表实现,链表的插入和删除操作时间复杂度为 O(1)。

5. 顺序表的应用场景

- 实际应用:顺序表在实际项目中的应用案例

  1. 数组:数组是一种顺序表的特殊形式,可以用于存储和处理一组具有相同数据类型的元素。在各种编程语言中,数组作为基本的数据结构被广泛应用,用于解决各种问题。

  2. 数据库索引:数据库中的索引通常使用顺序表来实现。通过将索引字段的值按照一定的顺序存储在顺序表中,可以加快数据库的检索速度,提高查询效率。

  3. 缓存管理:在计算机系统中,顺序表常被用作缓存的数据结构。通过将最常访问的数据存储在顺序表中,可以提高数据的访问速度,减少对底层存储的访问次数。

  4. 排序算法:许多排序算法,如冒泡排序、插入排序等,都可以通过顺序表来实现。顺序表提供了随机访问的能力,使得排序算法的实现更加简单和高效。

- 对比分析:与其他数据结构在实际应用中的对比情况

  1. 访问速度:与链表等非顺序存储结构相比,顺序表的访问速度更快。由于顺序表使用连续的内存空间存储元素,并且可以通过下标直接访问元素,因此在需要频繁访问元素的场景下,顺序表的性能更好。

  2. 存储空间:相比于链表等需要额外指针来连接元素的数据结构,顺序表的存储空间更加紧凑。顺序表不需要额外的指针来连接元素,节省了存储空间。

  3. 插入和删除操作:顺序表的插入和删除操作可能比链表等数据结构耗时,特别是需要移动其他元素的情况下。但对于随机访问和按位置访问较多的场景,顺序表仍然是一种合适的选择。

  4. 动态调整大小:相比于顺序表,链表等数据结构具有动态调整大小的能力。链表可以根据实际需要动态分配和释放内存空间,而顺序表的大小是固定的。

6. 顺序表的扩展与优化

- 动态扩容:如何处理顺序表空间不足的情况?

当顺序表空间不足时,需要进行动态扩容操作,以便能够继续存储更多的元素。一般来说,可以采取以下步骤来处理顺序表空间不足的情况:

  1. 重新分配内存空间:首先,需要重新分配一个更大的内存空间来存储元素。可以通过动态内存分配的方式(如realloc函数)来实现这一步骤。

  2. 数据迁移:接着,需要将当前顺序表中的元素迁移到新的内存空间中。这包括将原有的元素复制到新的内存空间,并释放原有的内存空间。

  3. 更新指针或引用:最后,需要更新指向顺序表的指针或引用,使其指向新的内存空间。

动态扩容的关键在于及时检测顺序表空间不足的情况,并采取合适的措施来扩充内存空间。一种常见的做法是在插入元素时检查当前空间是否足够,若不足则按照一定的策略进行扩容操作,通常是以一定的比例增加现有空间大小,以减少频繁扩容的开销。

- 性能优化:针对顺序表常见操作的性能优化方法

针对顺序表的常见操作,可以采取一些性能优化方法来提高其操作效率:

  1. 随机访问优化:顺序表的优势之一是能够进行快速的随机访问,但为了进一步提高访问速度,可以考虑使用局部性原理来优化。例如,可以利用CPU缓存的特性,将经常访问的数据预先加载到缓存中,以减少内存访问的时间。

  2. 插入和删除优化:虽然顺序表的插入和删除操作可能较慢,但可以通过一些技巧来进行优化。例如,针对频繁的插入和删除操作,可以考虑使用“延迟复制”或“分块复制”等技术,减少数据移动的次数。

  3. 内存预分配:为了减少动态扩容操作的频率,可以在创建顺序表时预先分配一定大小的内存空间,以减少频繁的内存重新分配和数据迁移操作。

  4. 数据压缩:针对稀疏性较大的顺序表,可以考虑使用数据压缩技术,将稀疏区域的内存空间释放出来,以节省存储空间。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows11系统下MemoryCompression导致内存占用率过高

. # &#x1f4d1;前言 本文主要是win11系统下CPU占用率过高如何下降的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日…

计算机毕业设计|基于SpringBoot+MyBatis框架健身房管理系统的设计与实现

计算机毕业设计|基于SpringBootMyBatis框架的健身房管理系统的设计与实现 摘 要:本文基于Spring Boot和MyBatis框架&#xff0c;设计并实现了一款综合功能强大的健身房管理系统。该系统涵盖了会员卡查询、会员管理、员工管理、器材管理以及课程管理等核心功能&#xff0c;并且…

【vue-router】useRoute 和 useRouter 的区别

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

Python模块与Linux stat 命令:双剑合璧的文件系统探索

简介&#xff1a;在Linux和Unix-like系统中&#xff0c;stat命令用于获取文件或目录的详细属性信息&#xff0c;包括但不限于大小、所有权、权限和时间戳。同样&#xff0c;在Python编程中&#xff0c;我们也有多个模块&#xff08;例如os、pathlib等&#xff09;提供了与stat类…

力扣题:字符串的反转-11.24

力扣题-11.24 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;151. 翻转字符串里的单词 解题思想&#xff1a;保存字符串中的单词即可 class Solution(object):def reverseWords(self, s):""":type s: str:rtype: str"&quo…

使用JSP+Servlet+MySQL实现登录注册功能

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

windows11 hosts文件没权限修改

1 win➕R 2 输入 cmd 3 同时按三个键 ctrl➕shift➕enter打开管理员权限 4 输入notepad回车,在记事本里直接点击文件-打开&#xff0c;选择路径:C:\Windows\System32\drivers\etc&#xff0c;继续选择所有文件&#xff0c;然后打开hosts文件 5 修改完之后&#xff0c;c…

科研学习|论文解读——Open government research over a decade: A systematic review

Open government research over a decade: A systematic review 十年来的开放政府研究&#xff1a;一个系统性综述 摘要 在过去十年中&#xff0c;对开放政府的学术研究蓬勃发展。然而&#xff0c;对开放政府的全面审查是有限的。这一研究空白不仅阻碍了我们对开放政府整体知…

【C语言:数据在内存中的存储】

文章目录 1.整数在内存中的存储1.1整数在内存中的存储1.2整型提升 2.大小端字节序2.1什么是大小端2.2为什么有大小端之分 3.整数在内存中的存储相关题目题目一题目二题目三题目四题目五题目六题目七 4.浮点数在内存中的存储4.1浮点数存的过程4.2浮点数取得过程 在这之前呢&…

深度学习之基于yolov3学生课堂行为及专注力检测预警监督系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习技术在学生课堂行为及专注力检测预警监督系统的应用是一项极具挑战性和创新性的研究领域。利用YOLOv3&…

C++解析xml示例

C解析xml示例 1. Xml文档介绍1.1 特点及作用1.2 Xml优点1.2.1 良好的可拓展性1.2.2 内容与形式分离 1.3 Xml组成1.3.1 Xml声明1.3.2 根元素1.3.3 元素1.3.4 属性1.3.5 实体1.3.6 注释 2 C解析Xml2.1 tinyXml2类库2.2 关键接口2.2.1 LoadFile2.2.2 RootElement2.2.3 FirstChildE…

计算机网络扫盲(2)——网络边缘

一、概述 在计算机网络得到术语中&#xff0c;我们把与因特网相连的计算机或其他设备称为端系统&#xff08;或者主机&#xff09;&#xff0c;如下图所示&#xff0c;因为它们位于因特网的边缘&#xff0c;所以被称为端系统。因特网的端系统包括了桌面计算机&#xff…

Linux的权限(一)

目录 权限的本质 Linux权限的概念 如何创建与删除普通用户 创建普通用户&#xff1a; 设置用户密码&#xff1a; 删除普通用户&#xff1a; 删除与该用户关联的主目录和邮件目录 &#xff1a; su指令 sudo指令 Linux权限管理 Linux中文件访问者有三种“人” Linux…

HashMap源码全面解析

注&#xff1a;本篇文章是在JDK1.8版本源码进行分析。 一、概述 HashMap 是基于哈希表的 Map接口的实现&#xff0c;是以 key-value 存储形式存在&#xff0c;即主要用来存储键值对。 HashMap的类图&#xff1a; HashMap继承抽象类AbstractMap&#xff0c;实现了Map、Clonea…

深度学习:什么是知识蒸馏(Knowledge Distillation)

1 概况 1.1 定义 知识蒸馏&#xff08;Knowledge Distillation&#xff09;是一种深度学习技术&#xff0c;旨在将一个复杂模型&#xff08;通常称为“教师模型”&#xff09;的知识转移到一个更简单、更小的模型&#xff08;称为“学生模型”&#xff09;中。这一技术由Hint…

基于SpringBoot蜗牛兼职网的设计与实现

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;蜗牛兼职网当然也不能排除在外。蜗牛兼职网是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c…

面试就是这么简单,offer拿到手软(一)—— 常见非技术问题回答思路

面试系列&#xff1a; 面试就是这么简单&#xff0c;offer拿到手软&#xff08;一&#xff09;—— 常见非技术问题回答思路 面试就是这么简单&#xff0c;offer拿到手软&#xff08;二&#xff09;—— 常见65道非技术面试问题 文章目录 一、前言二、常见面试问题回答思路问…

算法通关村第四关—栈的经典算法问题(白银)

emsp;emsp;栈的经典算法问题 一、括号匹配问题 emsp;首先看题目要求&#xff0c;LeetCode20.给定一个只包括’(‘&#xff0c;)’&#xff0c;‘{&#xff0c;’&#xff0c;[&#xff0c;]的字符串s&#xff0c;,判断字符串是否有效。有效字符串需满足&#xff1a; 1.左括号…

python绘制箱线图boxplot——用于多组数据的比较, 异常值检测

python绘制箱线图boxplot——用于多组数据的比较, 异常值检测 介绍箱线图方法简介箱线图适用范围seaborn.boxplot箱图外观设置异常值marker形状、填充色、轮廓设置完整代码 如下matplotlib.pyplot常见参数介绍 本文系统详解利用python中seaborn.boxplot绘制箱图boxplot。seab…

Linux系统安装Docker-根据官方教程教程(以Ubuntu为例)

Linux系统安装Docker-根据官方教程教程&#xff08;以Ubuntu为例&#xff09; 1. 背景介绍2. 环境配置2.1 软件环境要求2.2 软件下载2.3 文档地址2.3 必备命令工具下载 3. 安装Docker3.1 使用root用户操作后续命令3.2 卸载可能存在的旧版本 4. 安装Docker4.1 更新依赖包4.2 配置…