深入解析顺序表:揭开数据结构的奥秘,掌握顺序表的精髓

news2025/1/24 2:18:51

  • 💓 博客主页:江池俊的博客
  • ⏩ 收录专栏:数据结构探索
  • 👉专栏推荐:✅C语言初阶之路 ✅C语言进阶之路
  • 💻代码仓库:江池俊的代码仓库
  • 🔥编译环境:Visual Studio 2022
  • 🎉欢迎大家点赞👍评论📝收藏⭐

在这里插入图片描述

文章目录

  • 🚀线性表
  • 🚀顺序表
    • 🚨概念及结构
      • 🎈. 静态顺序表:使用定长数组存储元素。
      • 🎈. 动态顺序表:使用动态开辟的数组存储。
  • 🚀接口实现
    • 📌有哪些接口呢
    • 📌准备工作
    • 📌初始化
    • 📌扩容
    • 📌顺序表打印
    • 📌顺序表销毁
    • 📌尾插
    • 📌尾删
    • 📌头插
    • 📌头删
    • 📌指定pos下标位置插入数据
    • 📌删除pos位置的数据
    • 📌查找
    • 📌修改pos位置的数据
  • 🚀源码
    • 🌴SeqList.h 文件
    • 🌴SeqList.c 文件
    • 🌴Test.c 文件


🚀线性表

【维基百科】 线性表(英语:Linear List)是由n(n≥0)个数据元素(结点)a[0],a[1],a[2]…,a[n-1]组成的有限序列。

其中:

  • 数据元素的个数n定义为表的长度 = “list”.length() (“list”.length() = 0(表里没有一个元素)时称为空表)
  • 将非空的线性表(n>=1)记作:(a[0],a[1],a[2],…,a[n-1])
  • 数据元素a[i](0≤i≤n-1)只是个抽象符号,其具体含义在不同情况下可以不同

一个数据元素可以由若干个数据项组成。数据元素称为记录,含有大量记录的线性表又称为文件。这种结构具有下列特点:存在一个唯一的没有前驱的(头)数据元素;存在一个唯一的没有后继的(尾)数据元素;此外,每一个数据元素均有一个直接前驱和一个直接后继数据元素。

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组链式结构的形式存储。

在这里插入图片描述


🚀顺序表

🚨概念及结构

【维基百科】 顺序表是在计算机内存中数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。

即:顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改

🎈. 静态顺序表:使用定长数组存储元素。

在这里插入图片描述

🎈. 动态顺序表:使用动态开辟的数组存储。

在这里插入图片描述


🚀接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。

所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表

这里的接口其实就是 接口函数 ,这些 接口函数 提供了顺序表的各种基本操作,允许我们对顺序表进行 增、删、查、改 等操作。

📌有哪些接口呢

// 基本 增删查改 接口 --- 命名风格是跟着STL走的,方便后续学习STL
// 顺序表初始化
void SeqListInit(SL* psl);
// 检查空间,如果满了,进行增容 --> 扩容
void SLCheckCapacity(SL* psl);
// 顺序表尾插
void SeqListPushBack(SL* psl, SLDataType x);
// 顺序表头插
void SeqListPushFront(SL* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SL* psl);
// 顺序表头删
void SeqListPopFront(SL* psl);
// 顺序表查找
int SeqListFind(SL* psl, SLDataType x);
//顺序表的修改
void SeqListModify(SL* psl,int pos, SLDataType x);
// 顺序表在pos位置插入x(可以实现头插和尾插)
void SeqListInsert(SL* psl, int pos, SLDataType x);
// 顺序表删除pos位置的值(可以实现头删和尾删)
void SeqListErase(SL* psl, int pos);
// 顺序表打印
void SeqListPrint(SL* psl);
// 顺序表销毁
void SeqListDestroy(SL* psl);

接下来我将带着大家一 一实现这些接口。

📌准备工作

在写顺序表前,我们需要创建工程,这里为了让大家养成模块化的好习惯,我们尽量将代码分成三个文件来写。这里我打开的编译器是 vs 2022,在资源管理器的 头文件 中创建 SeqList.h 文件,此文件作用主要是为了存储各种头文件和接口函数的声明以及顺序表结构体的创建;在源文件中创建 SeqList.c 文件用来实现接口函数,Test.c 文件用来测试顺序表的各个接口。具体如下图所示:

在这里插入图片描述
注意:

  • 为了能够在顺序表中方便地存储各种类型的数据,我们可以使用 typedef 将要存储的数据类型重命名为 SLDataType ,这样在定义顺序表的数据类型时只需要使用 SLDataType 就行了,修改数据类型时只需要修改 typedef 后面跟着的这个数据类型,这样就大大方便了对不同类型数据的存储。
  • 类似的,为了方便结构体的定义和使用,我们也可以使用 typedef 将结构体定义一个简单的别名为 SL
#pragma once

#include<stdio.h>
#include<stdlib.h> // NULL、size_t
#include<assert.h>

// 静态的顺序表:使用定长数组存储元素。
// 特点:如果满了就不让插入
// 缺点:N给小了不够用,给多了浪费,这个很难确定
//#define N 100
//typedef int SLDataType; // 给int取别名
//struct SeqList // 创建顺序表
//{
//	SLDataType a[N]; // 定长数组
//	int size; // 存储的有效数据的个数
//};

// 动态顺序表:使用动态开辟的数组存储。
//typedef double SLDatatype;
typedef int SLDataType; //重定义类型名称,方便顺序表对不同类型的数据的存储和操作
typedef struct SeqList // 创建顺序表
{
	SLDataType* a; //指向动态开辟的数组
	int size;       // 存储的有效数据的个数
	int capacity;   // 容量空间大小
}SL; //将结构体类型取别名为 SL

📌初始化

这里我们实现动态顺序表,所以刚开始时我们可以假设给定顺序表的大小为 4(即能存放4个元素),不够就扩容,顺序表中刚开始是没有元素的。

//顺序表初始化
void SeqListInit(SL* psl)
{
	//防止psl为空指针(即防止传错结构体地址)
	assert(psl);
	psl->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
	//判断能否成功开辟空间
	if (psl->a == NULL)
	{
		perror("malloc fail");//将系统错误信息输出到屏幕
		return;
	}
	psl->capacity = 4;
	psl->size = 0;
}

📌扩容

在后续对顺序表进行操作过程中我们会插入数据,如果顺序表空间不够,我们就需要使用 realloc 函数进行扩容。
这里newcapacity表示扩容后能存放的元素个数(即空间的容量),tmp表示的是扩容后的空间的地址,如果顺序表的空间为空,就给定能存放4个元素的空间;如果空间不够,就在原来空间的基础上,增加 1 倍的空间(这样也依然无法避免空间的部分浪费,所以就有了链表,后续文章我会为大家带来)。

// 扩容 ---> 检查空间,如果满了,进行增容
void SLCheckCapacity(SL* psl)
{
	if (psl->size == psl->capacity)
	{
		//如果没有空间或者空间不足,就扩容
		int newcapacity = (psl->capacity == 0 ? 4 : psl->capacity * 2);
		SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType) * newcapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1); //退出程序
		}
		psl->a = tmp;
		psl->capacity = newcapacity;
	}
}

📌顺序表打印

打印比较简单,这里我们只需要依次遍历每一个节点就行。

//打印
void SeqListPrint(SL* psl)
{
    //防止psl为空指针(即防止传错结构体地址)
	assert(psl);
	//遍历
	for (int i = 0; i < psl->size; i++)
	{
		printf("%d ", psl->a[i]);
	}
	printf("\n");
}

📌顺序表销毁

因为是动态开辟的,所以如果空间不用我们就需要销毁掉。如果不销毁会存在内存泄漏的风险,所以这里我们使用free函数释放开辟的动态空间,并把有效数据个数和容量空间都置为0

//销毁
void SeqListDestroy(SL* psl)
{
	assert(psl);
	free(psl->a);
	psl->a = NULL;
	psl->size = 0;
	psl->capacity = 0;
}

📌尾插

尾插就是在最后一个元素的后面插入一个元素(即在size下标位置处插入数据),但要注意的是当capacity空间满了就需要扩容,因此我们要调用SLCheckCapacity函数。

//尾插
void SeqListPushBack(SL* psl, SLDataType x)
{
	assert(psl);

	//psl->a[psl->size] = x;
	//psl->size++;

	SLCheckCapacity(psl); // 检查扩容

	psl->a[psl->size++] = x;

	//复用指定pos下标位置插入数据的函数
	//SeqListInsert(psl, psl->size, x);
}

📌尾删

尾删其实就是将顺序表最后一个数据删去,要实现这一操作其实只需要将有效数据个数减一就可以了(即size--),但是在尾删之前要先判断顺序表中是否有元素,如果没有元素就没有必要删了。

//尾删
void SeqListPopBack(SL* psl)
{
	assert(psl);

	//温柔的处理方式
	//if (psl->size > 0)
	//{
	//	psl->size--;
	//}
	//else
	//{
	//	printf("没有数据能够再删了!\n");
	//		exit(-1); //退出程序
	//}
	
	//暴力的处理方式
	assert(psl->size > 0);//确保顺序表中有数据
	psl->size--;

	//复用pos下标位置删除数据的函数
	//SeqListErase(psl, psl->size - 1);
}

📌头插

头插操作其实就是在顺序表下表为 0 的位置插入数据,然后 size++,但是在此之前要判断顺序表容量空间是否已满,所以要先调用 SLCheakCapacity 函数。在这里插入图片描述

//头插
void SeqListPushFront(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++;

	//复用指定pos下标位置插入数据的函数
	//SeqListInsert(psl, 0, x);
}

📌头删

头删的实现其实只需要将顺序表开头后面的数据依次往前挪动,然后将 size-- 就可以了,这里要从前往后挪,如果从后往前挪数据会被覆盖。注意:这里与尾删类似,在头删之前要先判断顺序表中是否有元素,如果没有元素就没有必要删了。
在这里插入图片描述

//头删
void SeqListPopFront(SL* psl)
{
	assert(psl);
	assert(psl->size > 0);//有数据才能删,没数据就会报错
	int begin = 1;
	while (begin < psl -> size)
	{
		psl->a[begin - 1] = psl->a[begin];
		begin++;
	}
	psl->size--;

	//复用pos效标位置删除数据的函数
	//SeqListErase(psl, 0);
}

📌指定pos下标位置插入数据

我们只需要将顺序表中pos位置到最后的数据依次往后挪动(从后往前挪),然后将pos下标位置的数据改为要插入的数据,最后 size++ 即可。但是我们依然要判断是否满容,所以在插入数据前要调用 SLCheakCapacity 函数。同时我们也要判断pos位置是否合理,防止越界访问。

//指定pos下标位置插入数据
void SeqListInsert(SL* psl, int pos, SLDataType x)
{
	assert(psl);
	//if (pos > psl->size || pos < 0)
	//{
	//	printf("pos的下标位置越界");
	//	return;
	//}
	//暴力的方式处理(pos下标不能越界)
	assert(pos >= 0 && pos <= psl->size);
	//如果没有空间或者空间不足,就扩容
	SLCheckCapacity(psl);
	//挪动数据
	int end = psl->size - 1;
	while (end >= pos)
	{
		psl->a[end + 1] = psl->a[end];
		end--;
	}
	psl->a[pos] = x;
	psl->size++;
}

📌删除pos位置的数据

与头删类似,我们只需要将pos位置后的数据依次往前挪动将pos位置处的数据覆盖,然后再 size-- 就可以了。但是要判断pos位置是否合理,防止越界访问。

//删除pos位置的数据(结合SeqListFind函数可以删除指定的数据)
void SeqListErase(SL* psl, int pos)
{
	assert(psl);
	assert(pos >= 0 && pos < psl->size);//pos位置需要有数据
    //挪动数据
	int begin = pos + 1;
	while (begin < psl->size)
	{
		psl->a[begin - 1] = psl->a[begin];
		begin++;
	}
	psl->size--;
}

📌查找

这个比较简单,我们只需要遍历一遍顺序表,查找相应数据,若找到,就返回下标,若没找到,就返回-1。

//查找,找到了返回下标,没找到返回-1
int SeqListFind(SL* psl, SLDataType x)
{
	assert(psl);
	for (int i = 0; i < psl->size; i++)
	{
		if (psl->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

📌修改pos位置的数据

通过pos下标直接修改

//修改pos位置的数据
void SeqListModify(SL* psl, int pos, SLDataType x)
{
	assert(psl);
	assert(pos >= 0 && pos < psl->size);

	psl->a[pos] = x;
}

🚀源码

🌴SeqList.h 文件

#pragma once

#include<stdio.h>
#include<stdlib.h>//NULL、size_t
#include<assert.h>


// 静态的顺序表:使用定长数组存储元素。
// 特点:如果满了就不让插入
// 缺点:N给小了不够用,给多了浪费,这个很难确定
//#define N 10000
//typedef int SLDatatype; // 给int取别名
//struct SeqList // 创建顺序表
//{
//	SLDatatype a[N]; // 定长数组
//	int size; // 存储的有效数据的个数
//};
//静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪
//费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实
//现动态顺序表。


// 动态顺序表:使用动态开辟的数组存储。
//typedef double SLDatatype;
typedef int SLDataType; //重定义类型名称,方便顺序表对不同类型的数据的存储和操作
typedef struct SeqList
{
	SLDataType* a; //指向动态开辟的数组
	int size;       // 存储的有效数据的个数
	int capacity;   // 容量空间大小
}SL;

// 基本 增删查改 接口 --- 命名风格是跟着STL走的,方便后续学习STL
// 顺序表初始化
void SeqListInit(SL* psl);

// 检查空间,如果满了,进行增容
void SLCheckCapacity(SL* psl);

// 顺序表尾插
void SeqListPushBack(SL* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SL* psl);
// 顺序表头插
void SeqListPushFront(SL* psl, SLDataType x);
// 顺序表头删
void SeqListPopFront(SL* psl);
// 顺序表查找
int SeqListFind(SL* psl, SLDataType x);
// 顺序表在pos位置插入x(可以实现头插和尾插)
void SeqListInsert(SL* psl, int pos, SLDataType x);
// 顺序表删除pos位置的值(可以实现头删和尾删)
void SeqListErase(SL* psl, int pos);

// 顺序表打印
void SeqListPrint(SL* psl);
// 顺序表销毁
void SeqListDestroy(SL* psl);

//顺序表的修改
void SeqListModify(SL* psl, int pos, SLDataType x);

🌴SeqList.c 文件

#include"SeqList.h"

//void SeqListInit(SL* psl)
//{
//	psl->a = NULL;
//	psl->size = 0;
//	psl->capacity = 0;
//}

//顺序表初始化
void SeqListInit(SL* psl)
{
	//防止psl为空指针(即防止传错结构体地址)
	assert(psl);
	psl->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
	//判断能否成功开辟空间
	if (psl->a == NULL)
	{
		perror("malloc fail");//将系统错误信息输出到屏幕
		return;
	}

	psl->capacity = 4;
	psl->size = 0;
}
//销毁
void SeqListDestroy(SL* psl)
{
	assert(psl);
	free(psl->a);
	psl->a = NULL;
	psl->size = 0;
	psl->capacity = 0;
}
//打印
void SeqListPrint(SL* psl)
{
	assert(psl);
	for (int i = 0; i < psl->size; i++)
	{
		printf("%d ", psl->a[i]);
	}
	printf("\n");
}
// 检查空间,如果满了,进行增容
void SLCheckCapacity(SL* psl)
{
	assert(psl);
	if (psl->size == psl->capacity)
	{
		//如果没有空间或者空间不足,就扩容
		int newcapacity = (psl->capacity == 0 ? 4 : psl->capacity * 2);
		SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType) * newcapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);//退出程序
		}

		psl->a = tmp;
		psl->capacity = newcapacity;
	}
}
//尾插
void SeqListPushBack(SL* psl, SLDataType x)
{
	assert(psl);

	//psl->a[psl->size] = x;
	//psl->size++;
	
	SLCheckCapacity(psl);//检查扩容

	psl->a[psl->size++] = x;

	//复用指定pos下标位置插入数据的函数
	//SeqListInsert(psl, psl->size, x);
}
//尾删
void SeqListPopBack(SL* psl)
{
	assert(psl);

	//温柔的处理方式
	//if (psl->size > 0)
	//{
	//	psl->size--;
	//}
	//else
	//{
	//	printf("没有数据能够再删了!\n");
	//		exit(-1);
	//}
	
	//暴力的处理方式
	assert(psl->size > 0);//确保顺序表中有数据
	psl->size--;

	//复用pos下标位置删除数据的函数
	//SeqListErase(psl, psl->size - 1);
}
//头插
void SeqListPushFront(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++;

	//复用指定pos下标位置插入数据的函数
	//SeqListInsert(psl, 0, x);
}
//头删
void SeqListPopFront(SL* psl)
{
	assert(psl);
	assert(psl->size > 0);//有数据才能删,没数据就会报错
	int begin = 1;
	while (begin < psl -> size)
	{
		psl->a[begin - 1] = psl->a[begin];
		begin++;
	}
	psl->size--;

	//复用pos效标位置删除数据的函数
	//SeqListErase(psl, 0);
}
//查找,找到了返回下标,没找到返回-1
int SeqListFind(SL* psl, SLDataType x)
{
	assert(psl);
	for (int i = 0; i < psl->size; i++)
	{
		if (psl->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}
//指定pos下标位置插入数据
void SeqListInsert(SL* psl, int pos, SLDataType x)
{
	assert(psl);
	//if (pos > psl->size || pos < 0)
	//{
	//	printf("pos的下标位置越界");
	//	return;
	//}
	//暴力的方式处理(pos下标不能越界)
	assert(pos >= 0 && pos <= psl->size);
	//如果没有空间或者空间不足,就扩容
	SLCheckCapacity(psl);
	//挪动数据
	int end = psl->size - 1;
	while (end >= pos)
	{
		psl->a[end + 1] = psl->a[end];
		end--;
	}
	psl->a[pos] = x;
	psl->size++;
}

//删除pos位置的数据(结合SeqListFind函数可以删除指定的数据)
void SeqListErase(SL* psl, int pos)
{
	assert(psl);
	assert(pos >= 0 && pos < psl->size);//pos位置需要有数据
    //挪动数据
	int begin = pos + 1;
	while (begin < psl->size)
	{
		psl->a[begin - 1] = psl->a[begin];
		begin++;
	}
	psl->size--;
}

//修改pos位置的数据
void SeqListModify(SL* psl, int pos, SLDataType x)
{
	assert(psl);
	assert(pos >= 0 && pos < psl->size);

	psl->a[pos] = x;

}

🌴Test.c 文件

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqList.h"

int main()
{
	SL s;
	SeqListInit(&s);
	SeqListPushBack(&s, 1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPushBack(&s, 5);
	SeqListPushBack(&s, 6);//尾插
	SeqListPopBack(&s);//尾删
	SeqListPushFront(&s, 0);//头插
	SeqListPopFront(&s);//头删
	SeqListInsert(&s, 2, 8);//指定pos下标为2的位置插入数据8

	SeqListPrint(&s);//打印
	SeqListDestroy(&s);//销毁

	return 0;
}

💨 今天的分享就到这里,如果觉得博主的文章还不错的话, 请👍三连支持一下博主哦🤞

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

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

相关文章

包装类、多线程的基本使用

包装类 1.基本数据类型对应的引用数据类型(包装类) 1.概述:所谓的包装类就是基本类型对应的类(引用类型),我们需要将基本类型转成包装类,从而让基本类型具有类的特性(说白了,就是将基本类型的数据转成包装类,就可以使用包装类中的方法来操作此数据)2.为啥要学包装类:a.将来有…

springboot上传文件到后台指定文件夹

第一步&#xff0c;在application.yml做一下配置&#xff0c;预设下载目录 files:upload:path: D:/SpringBootItem/springboot/files/ 其中有用到hutool工具依赖&#xff0c;如下在pom.xml中添加依赖&#xff0c;也可以选择不添加&#xff0c;自己修改下Controller中的代码即可…

批量采集头条号文章的工具-让我们更好地辨别信息好坏

大家好&#xff0c;今天我想和大家聊一聊一个在互联网时代备受瞩目的话题&#xff0c;那就是批量采集头条号的文章。作为一个热衷于信息获取和分享的人&#xff0c;我深知这一领域的挑战和机遇。 让我们来谈谈批量采集头条号的文章所面临的挑战。随着互联网的迅猛发展&#xff…

亚马逊API接口解析,实现获得AMAZON商品详情

要解析亚马逊API接口并实现获取亚马逊商品详情&#xff0c;你需要按照以下步骤进行操作&#xff1a; 了解亚马逊开发者中心&#xff1a;访问亚马逊开发者中心&#xff0c;并了解相关的API文档、开发者指南和规定。注册开发者账号&#xff1a;在亚马逊开发者中心上注册一个开发…

Java“牵手”京东商品详情数据,京东商品详情接口,京东API接口申请指南

京东商品详情API是京东平台提供给开发者的应用程序编程接口&#xff0c;通过API可以获取京东平台上商品详情信息。 京东商品详情API可以获取到商品的标题、价格、销量、评价、详情页等信息。开发者在京东开放平台注册开发者账号&#xff0c;并获得访问API接口的密钥后&#xf…

代码随想录算法训练营day46|139.单词拆分|多重背包基础理论| 背包总结

139.单词拆分 力扣题目链接 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明&#xff1a; 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 示例 1&#xff1a…

关于批量安装多个apk

for %i in (apks地址/*.apk); do adb install %i https://www.cnblogs.com/lihongtaoya/p/15084378.html adb install -r apks地址/1.apk && adb install -r apks地址/2.apk install-multi-package - 暂时nok https://adbshell.com/commands 最新版本的platform-tool…

Dinky上路之旅

1、部署flink集群 1.1、flink-conf.yaml cat > flink-conf.yaml << EOF jobmanager.rpc.address: boshi-146 jobmanager.rpc.port: 6123 jobmanager.bind-host: 0.0.0.0 jobmanager.memory.process.size: 1600m taskmanager.bind-host: 0.0.0.0 # 修改为本机ip tas…

今日宜分享:科技十足主页面的高校官网颜值排行榜

科技十足主页面的高校官网颜值排行榜 全国985名单&#xff08;最新&#xff09;1. 北京&#xff08;8所&#xff09;2. 上海&#xff08;4所&#xff09;3. 湖南&#xff08;3所&#xff09;4. 陕西&#xff08;3所&#xff09;5. 湖北&#xff08;2所&#xff09;6. 山东&…

postgresql如何关闭自动提交设置

问题&#xff1a;代码运行报错&#xff1a; Caused by: org.postgresql.util.PSQLException: Cannot commit when autoCommit is enabled. 解决方法&#xff1a;修改postgresql配置文件&#xff0c;关闭自动提价设置

机器学习:PCA(Principal Component Analysis主成分)降维

参考&#xff1a;PCA降维原理 操作步骤与优缺点_TranSad的博客-CSDN博客 PCA降维算法_偶尔努力翻身的咸鱼的博客-CSDN博客 需要提前了解的数学知识&#xff1a; 一、PCA的主要思想 PCA&#xff0c;即主成分分析方法&#xff0c;是一种使用最广泛的数据降维算法。PCA的主要思想…

centerOS连不上网解决办法

1、检查路由 route -n如果你缺失第一个路由&#xff0c;是肯定无法ping通外网的。 2、添加dns # vim /etc/resolv.conf nameserver 8.8.8.83、在/etc/resolv.conf文件添加路由 route add default gw 192.168.0.14、重启网卡 service network restart

KT142C-sop16语音芯片的4个IO口如何一对一触发播放_配置文件详细说明

目录 KT142C是一个提供串口的SOP16语音芯片&#xff0c;完美的集成了MP3的硬解码。内置330KByte的空间&#xff0c;最大支持330秒的语音长度&#xff0c;支持多段语音&#xff0c;支持直驱0.5W的扬声器无需外置功放 如上图&#xff0c;芯片有4个IO口可以一对一&#xff0c;详…

服务器数据恢复-热备盘同步过程中硬盘离线的RAID5数据恢复案例

服务器数据恢复环境&#xff1a; 华为OceanStor某型号存储&#xff0c;11块硬盘组建了一组RAID5阵列&#xff0c;另外1块硬盘作为热备盘使用。基于RAID5阵列的LUN分配给linux系统使用&#xff0c;存放Oracle数据库。 服务器故障&#xff1a; RAID5阵列1块硬盘由于未知原因离线…

线程详细解析

本文重点: 目录 什么是线程? 线程共享和非共享资源 线程的优缺点 多线程 线程池 Java创建线程池 什么是线程? 线程是操作系统调度和执行的基本单位,线程和进程一样也有PCB 一个进程必定会有一个线程 在Linux内核中是不会区分进程和线程的,只在用户层面区分 线程共享…

新手询问想要成功学好嵌入式开发有什么建议吗?

今日话题&#xff0c;想要成功学好嵌入式开发有什么建议吗&#xff1f;想要学好的话选择一门合适的编程语言是关键。虽然嵌入式开发支持多种语言&#xff0c;但C和C仍然是最常用的。如果你是初学者&#xff0c;从学习C语言开始是一个不错的选择。它相对容易学习&#xff0c;而且…

基于Python开发的智能停车场车牌识别计费系统(源码+可执行程序+程序配置说明书+程序使用说明书)

一、项目简介 本项目是一套基于Python开发的智能停车场车牌识别计费系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。 包含&#xff1a;项目源码、项目文档等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试…

教你制作作业查询系统

嗨&#xff0c;各位老师们&#xff0c;今天我要给你们介绍一个超级方便的工具——易查分&#xff01;你知道吗&#xff0c;利用易查分&#xff0c;我们可以轻松制作一个便捷高效的作业查询系统哦&#xff01; 是不是想有个自己的分班or成绩查询页面&#xff1f;博主给老师们争取…

​重生奇迹失落之塔三-四层刷怪攻略​

重生奇迹中的失落之塔一共是八层&#xff0c;每一层均需玩家达到相应的等级后方可进入&#xff0c;等级不到&#xff0c;谢绝入内&#xff0c;甚至有时即便你的等级达标&#xff0c;在里面刷一会怪之后&#xff0c;便自动地退去&#xff0c;因为这里面的怪物绝非等闲之辈&#…