【数据结构 · 初阶】- 顺序表

news2025/4/19 1:28:19

目录

一、线性表

二、顺序表

1.实现动态顺序表

SeqList.h

SeqList.c

Test.c

问题

经验:free 出问题,2种可能性

解决问题

(2)尾删

(3)头插,头删

(4)在 pos 位插

(5)在 pos 位删

(6)查找

2.整体代码

SeqList.h

SeqList.c

test.c


一、线性表

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

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

二、顺序表

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

分类:
(1)静态顺序表:使用定长数组存储元素
(2)动态顺序表:使用动态开辟的数组存储

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

1.实现动态顺序表

SeqList.h 

为方便替换成其他类型,我们将这些类型统一重命名为 SLDataType

typedef int SLDataType;
#define INIT_CAPACITY 4 // 初始化容量

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

// 增删查改
void SLInit(SL* ps);
void SLDestroy(SL* ps);

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

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

// 扩容,2倍合适
void SLCheckCapacity(SL* ps);
SeqList.c
void SLInit(SL* ps)
{
	assert(ps);
	ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		return;
	}

	ps->size = 0;
	ps->capacity = INIT_CAPACITY;
}

void SLDestroy(SL* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0; // 结合性,从右往左赋值
}

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

// 扩容,2倍合适
void SLCheckCapacity(SL* ps)
{
	assert(ps);
    if (ps->size == ps->capacity)
	{
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2);//思考这里对不对
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		ps->a = tmp; // 防止不是原地扩容
		ps->capacity *= 2;
	}

}

void SLPushBack(SL* ps, SLDataType x) // 尾插
{
	assert(ps);
	// 扩容  2倍合适
    SLCheckCapacity(ps);

	ps->a[ps->size++] = x;
}
Test.c
void TestSeqList1()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPrint(&s);

	SLDestroy(&s);
}

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

运行上面的代码,顺序表里插入1234:,程序没毛病


问题

void TestSeqList1()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPrint(&s);

	SLDestroy(&s);
}

奇怪的事情发生了:

SLPushBack(&s, 6);
SLPushBack(&s, 7);

奇怪的事情又发生了:    光标在闪

这里反反复复调试都发现不了问题


经验:free 出问题,2种可能性

(1)野指针 或 位置不对。这种情况不多
eg:申请一块空间,从中间位置释放,报错。(应该从起始位置释放)
(2)指针指向的空间(数组)上面,可能有越界。

  • 下标越界
  • 开少了

解决问题

realloc 返回的是地址,->a,a 我们没有动过,动的都是 a 指向的内容
free 有时候出问题,通常不是free ( ) 里面有问题,而是前面有越界

仔细查,动空间的只有 SLPushBack(    )

// 扩容,2倍合适
void SLCheckCapacity(SL* ps)
{
	assert(ps);
    if (ps->size == ps->capacity)
	{
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2);//思考这里对不对
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		ps->a = tmp; // 防止原地扩容
		ps->capacity *= 2;
	}

}

void SLPushBack(SL* ps, SLDataType x) // 尾插
{
	assert(ps);
	// 扩容  2倍合适
    SLCheckCapacity(ps);
	ps->a[ps->size++] = x;
}

ps->a[ps->size++] = x; 逻辑没有问题,问题大概率出现在扩容

先看下标越界了吗?size 没有越界的可能性

还有一种可能是开少了。
你以为你原来是 4 个,扩容到 8 个。你以为你有 8 个,实际上没有 8 个。你当成 8 个访问的呀,就越了。

8 个 SLDataType 是 4*8=32 字节。
ps->capacity * 2 这里是 4*2=8 字节


正确写法:

// 扩容  2倍合适
void SLCheckCapacity(SL* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType) * ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		ps->a = tmp;
		ps->capacity *= 2;
	}
}

void SLPushBack(SL* ps, SLDataType x) // 尾插
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->a[ps->size++] = x;
}

 问题解决

(2)尾删

void SLPopBack(SL* ps) // 尾删
{
	assert(ps);
	//ps->a[ps->size - 1] = 0; 加上没用
	ps->size--;
}

由 size 遍例顺序表,size -- 后,前 size-1个是有效数据,第 size 个访问不到了

注意:这里不用释放,一部分一部分释放会报错。
但是不用担心,当我们不用这个顺序表时会 SLDestroy(&s) ; 空间还是会释放的


删空了还删,会报错。所以要检查

void SLPopBack(SL* ps) // 尾删
{
	assert(ps);
	// 温柔的检查
	if (ps->size == 0)
		return;

	ps->size--;
}

断言 assert 会直接告诉你哪出错了,并且终止掉程序

void SLPopBack(SL* ps) // 尾删
{
	assert(ps);
	// 暴力检查
	assert(ps->size > 0);

	ps->size--;
}

(3)头插,头删

要挪动数据,以实现顺序表连续性
顺序表尾插,尾删效率不错。头插,头删效率不太行。但有时候就要头插,头删

void SLPushFront(SL* ps, SLDataType x) // 头插
{
	assert(ps);
	SLCheckCapacity(ps);

	//挪动
	memmove(&(ps->a[1]), &(ps->a[0]), sizeof(SLDataType) * ps->size);
	//头插
	ps->a[0] = x;
	ps->size++;
}

void SLPopFront(SL* ps) // 头删
{
	assert(ps);
	assert(ps->size > 0);
	memmove(&(ps->a[0]), &(ps->a[1]), sizeof(SLDataType) * ps->size);

	ps->size--;
}

我们发现:插入N个数据。尾插时间复杂度:O(N)     头插时间复杂度:O(N^2)
头插1万个数据,要执行1亿次。所以,尽量避免使用头插

疑问:为什么头插用memmove库函数了,时间复杂度还是O(N^2)
答:虽然我们用的是库函数,一步到位,没有用模拟实现。我们分析它的时间复杂度,还是要看到本质,本质就是模拟实现,通过模拟实现分析它的时间复杂度。

本质:

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

	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}

	ps->a[0] = x;
	ps->size++;
}

可以看到,头插1个数据,执行N次,时间复杂度O(N)。头插N个数据,执行N^2次,时间复杂度O(N^2)  从模拟实现的角度看,它是一个等差数列

(4)在 pos 位插

// 顺序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);// 插入时 = size 相当于尾插
	
	SLCheckCapacity(ps);

	//挪动
	memmove(&(ps->a[pos + 1]), &(ps->a[pos]), sizeof(SLDataType) * (ps->size - pos));
	//插入
	ps->a[pos] = x;
	ps->size++;
}

我们可以简化头插(在第0位),尾插(在第size位)。

void SLPushBack(SL* ps, SLDataType x) // 尾插
{
	assert(ps);
	/*SLCheckCapacity(ps);

	ps->a[ps->size++] = x;*/

	SLInsert(ps, ps->size, x);
}

void SLPushFront(SL* ps, SLDataType x) // 头插
{
	assert(ps);
	/*SLCheckCapacity(ps);

	//挪动
	memmove(&(ps->a[1]), &(ps->a[0]), sizeof(SLDataType) * ps->size);
	//头插
	ps->a[0] = x;
	ps->size++;*/

	SLInsert(ps, 0, x);
}

(5)在 pos 位删

// 顺序表删除pos位置的值
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	//覆盖
	memmove(&(ps->a[pos]), &(ps->a[pos + 1]), sizeof(SLDataType) * (ps->size - pos - 1));
	
	ps->size--;
}

可以简化 头删,尾删 的代码。

void SLPopBack(SL* ps) // 尾删
{
	assert(ps);
	/*// 暴力检查
	assert(ps->size > 0);
	 温柔的检查
	//if (ps->size == 0)
	//	return;

	ps->size--;*/
	SLErase(ps, ps->size - 1);
}

void SLPopFront(SL* ps) // 头删
{
	assert(ps);
	/*assert(ps->size > 0);
	memmove(&(ps->a[0]), &(ps->a[1]), sizeof(SLDataType) * ps->size);

	ps->size--;*/
	SLErase(ps, 0);
}

疑问:用这个新的代码尾删,假设现在size = 8,根据上面代码,最大容量 capacity 也 = 8。要尾删,删下标为7的位置,传给 pos,pos+1 = 8 。SLErase 里面 &(ps->a[pos + 1]) 不会越界访问吗?
解答:这时要 memmove 移动 ps->size - pos - 1 = 0 个字节。我们看 memmove 模拟实现:num 是要移动的字节个数,这里 num = 0 ,循环没进去,也就不存在越界访问了

(6)查找

//顺序表查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->a[i])
		{
			return i;
		}
	}
	return -1;
}

问:为什么删除后,不用 realloc 回收一部分内存的使用权?
答:当扩容时,realloc 开内存,分为异地扩容,本地扩容。想要新开辟空间,如果原空间后面的大小够,就本地扩容,效率高。后面大小不够,就异地扩容,效率低
而现代计算机内存空间的数量很多,不怕浪费,为保证运行效率,宁愿占着茅坑不拉屎。

当我们确认不再使用时,也会 SLDestroy 释放全部空间

问:为什么不写菜单?
答:数据结构部分,菜单没有什么价值。而且不好调试。菜单一般在命令行程序,控制数据库的服务器,会输入选项(指令去控制)。
写菜单的话,也不要一上来就写菜单。先在 test.c 里写一组一组测试 ,测的没问题了,再写菜单

2.整体代码

SeqList.h

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

typedef int SLDataType;
#define INIT_CAPACITY 4 // 初始化容量

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

// 增删查改
void SLInit(SL* ps);
void SLDestroy(SL* ps);

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

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

// 顺序表查找
int SLFind(SL* ps, SLDataType x);
// 顺序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x);
// 顺序表删除pos位置的值
void SLErase(SL* ps, int pos);

// 扩容,2倍合适
void SLCheckCapacity(SL* ps);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"

void SLInit(SL* ps)
{
	assert(ps);
	ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		return;
	}

	ps->size = 0;
	ps->capacity = INIT_CAPACITY;
}

void SLDestroy(SL* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0; // 结合性,从右往左赋值
}

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

// 扩容  2倍合适
void SLCheckCapacity(SL* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType) * ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		ps->a = tmp;
		ps->capacity *= 2;
	}
}

void SLPushBack(SL* ps, SLDataType x) // 尾插
{
	assert(ps);
	/*SLCheckCapacity(ps);

	ps->a[ps->size++] = x;*/

	SLInsert(ps, ps->size, x);
}

void SLPopBack(SL* ps) // 尾删
{
	assert(ps);
	/*// 暴力检查
	assert(ps->size > 0);
	 温柔的检查
	//if (ps->size == 0)
	//	return;

	ps->size--;*/
	SLErase(ps, ps->size - 1);
}

void SLPushFront(SL* ps, SLDataType x) // 头插
{
	assert(ps);
	/*SLCheckCapacity(ps);

	//挪动
	memmove(&(ps->a[1]), &(ps->a[0]), sizeof(SLDataType) * ps->size);
	//头插
	ps->a[0] = x;
	ps->size++;*/

	SLInsert(ps, 0, x);
}

void SLPopFront(SL* ps) // 头删
{
	assert(ps);
	/*assert(ps->size > 0);
	memmove(&(ps->a[0]), &(ps->a[1]), sizeof(SLDataType) * ps->size);

	ps->size--;*/
	SLErase(ps, 0);
}

//顺序表查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->a[i])
		{
			return i;
		}
	}
	return -1;
}

// 顺序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);// 插入时 = size 相当于尾插
	
	SLCheckCapacity(ps);

	//挪动
	memmove(&(ps->a[pos + 1]), &(ps->a[pos]), sizeof(SLDataType) * (ps->size - pos));
	//插入
	ps->a[pos] = x;
	ps->size++;
}

// 顺序表删除pos位置的值
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	//覆盖
	memmove(&(ps->a[pos]), &(ps->a[pos + 1]), sizeof(SLDataType) * (ps->size - pos - 1));
	
	ps->size--;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"

void TestSeqList1()//第一组测试用例
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLPushBack(&s, 7);
	SLPushBack(&s, 8);
	SLPrint(&s);

	SLPopBack(&s);
	SLPopBack(&s);
	SLPrint(&s);

	SLPushFront(&s, 9);
	SLPushFront(&s, 10);
	SLPushFront(&s, 11);
	SLPushFront(&s, 12);
	SLPushFront(&s, 13);
	SLPushFront(&s, 14);
	SLPrint(&s);

	SLPopFront(&s);
	SLPopFront(&s);
	SLPopFront(&s);
	SLPrint(&s);

	SLInsert(&s, 3, 30);
	SLPrint(&s);

	SLErase(&s, 3);
	SLPrint(&s);

	int pos = SLFind(&s, 3);
	if (pos == -1)
	{
		printf("没找到\n");
	}
	else
	{
		printf("找到了,下标是:%d", pos);
	}

	SLDestroy(&s);
}

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

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

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

相关文章

NHANES指标推荐:aMED

文章题目&#xff1a;The moderating effect of alternate Mediterranean diet on the association between sedentary behavior and insomnia in postmenopausal women DOI&#xff1a;10.3389/fnut.2024.1516334 中文标题&#xff1a;替代性地中海饮食对绝经后女性久坐行为与…

Spring Cloud 远程调用

4.OpenFeign的实现原理是什么&#xff1f; 在使用OpenFeign的时候&#xff0c;主要关心两个注解&#xff0c;EnableFeignClients和FeignClient。整体的流程分为以下几个部分&#xff1a; 启用Feign代理&#xff0c;通过在启动类上添加EnableFeignClients注解&#xff0c;开启F…

力扣 — — 最长公共子序列

力扣 — — 最长公共子序列 最长公共子序列 题源&#xff1a;1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 分析&#xff1a; 一道经典的题目&#xff1a;最长公共子序列(LCS) 题目大意&#xff1a;求两个字符串的最长公共序列。 算法&…

当一个 HTTP 请求发往 Kubernetes(K8s)部署的微服务时,整个过程流转时怎样的?

以下是一个简单的示意图来展示这个过程&#xff1a; 1. 请求发起 客户端&#xff08;可以是浏览器、移动应用或者其他服务&#xff09;发起一个 HTTP 请求到目标微服务的地址。这个地址可以是服务的域名、IP 地址或者 Kubernetes 服务的 ClusterIP、NodePort 等。 2. 外部流量…

蓝桥杯-蓝桥幼儿园(Java-并查集)

并查集的核心思想 并查集主要由两个操作构成&#xff1a; Find&#xff1a;查找某个元素所在集合的根节点。并查集的特点是&#xff0c;每个元素都指向它自己的父节点&#xff0c;根节点的父节点指向它自己。查找过程中可以通过路径压缩来加速后续的查找操作&#xff0c;即将路…

C++蓝桥杯填空题(攻克版)

片头 嗨~小伙伴们&#xff0c;咱们继续攻克填空题&#xff0c;先把5分拿到手~ 第1题 数位递增的数 这道题&#xff0c;需要我们计算在整数 1 至 n 中有多少个数位递增的数。 什么是数位递增的数呢&#xff1f;一个正整数如果任何一个数位不大于右边相邻的数位。比如&#xf…

JS 构造函数实现封装性

通过构造函数实现封装性&#xff0c;构造函数生成的对象独立存在互不影响 创建实例对象时&#xff0c;其中函数的创建会浪费内存

一站式云分账系统!智能虚拟户分账系统成电商合规“刚需”

电商智能分账解决&#xff1a;电商一站式破解多平台资金管理难题集中管理分账&#xff0c;分账后秒到&#xff0c;并为针对电商行业三大核心痛点提供高效应对策略&#xff1a; 1. 票据合规困境 智能对接上下游交易数据流&#xff0c;构建自动化票据协同机制&#xff0c;有效规…

数组 array

1、数组定义 是一种用于存储多个相同类型数据的存储模型。 2、数组格式 &#xff08;1&#xff09;数据类型[ ] 变量名&#xff08;比较常见这种格式&#xff09; 例如&#xff1a; int [ ] arr0&#xff0c;定义了一个int类型的数组&#xff0c;数组名是arr0&#xff1b; &am…

linux命令六

逻辑卷 作用: 整合分散空间 空间支持扩大 步骤一:建立卷组&#xff08;VG&#xff09; 格式&#xff1a;vgcreate 卷组名 设备路径……. 如果分区不是卷组,则会先调用pvcreat 组建物理卷,再将其组建成组卷 Successfully:成功 example&#xff1a;例子 在man帮助中可以使用examp…

深度学习总结(8)

模型工作流程 模型由许多层链接在一起组成&#xff0c;并将输入数据映射为预测值。随后&#xff0c;损失函数将这些预测值与目标值进行比较&#xff0c;得到一个损失值&#xff0c;用于衡量模型预测值与预期结果之间的匹配程度。优化器将利用这个损失值来更新模型权重。 下面是…

基于docker搭建redis集群环境

在redis目录下创建redis-cluster目录&#xff0c;创建docker-compose.yml文化和generate.sh文件 【配置generate.sh文件】 for port in $(seq 1 9); \ do \ mkdir -p redis${port}/ touch redis${port}/redis.conf cat << EOF > redis${port}/redis.conf port 6379 …

分治-归并系列一>翻转对

目录 题目&#xff1a;解析&#xff1a;策略一&#xff1a; 代码&#xff1a;策略二&#xff1a; 代码&#xff1a; 题目&#xff1a; 链接: link 这题和逆序对区别点就是&#xff0c;要找到前一个元素是后一个元素的2倍 先找到目标值再&#xff0c;继续堆排序 解析&#xff1…

FFMPEG大文件视频分割传输教程,微信不支持1G文件以上

如下是一个2.77g的文件分割教程 . 前言 FFmpeg 是一个用于处理视频、音频等多媒体文件的开源工具包。它支持几乎所有的多媒体格式转换、剪辑和编辑&#xff0c;是开发者和多媒体工作者必备的工具。本文详细讲解如何在 Windows 系统上安装 FFmpeg 并进行基本配置。 2. 下载 FF…

MySQL5.7数据库部署和安装

1. 准备系统环境 Vmawre安装CentOS7 略… 2. 下载MySQL5.7安装包 下载地址&#xff1a; https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz 3. 卸载系统自带的MariaDB sudo yum remove $(rpm -qa | grep mariadb)4. 解压安…

Java学习手册:JVM、JRE和JDK的关系

在Java生态系统中&#xff0c;JVM&#xff08;Java虚拟机&#xff09;、JRE&#xff08;Java运行时环境&#xff09;和JDK&#xff08;Java开发工具包&#xff09;是三个核心概念。它们共同构成了Java语言运行和开发的基础。理解它们之间的关系对于Java开发者来说至关重要。本文…

如何用 esProc 实现 Oracle 和 MySQL 的混合运算

逻辑数仓可以实现多源混算&#xff0c;但需要配置视图、预处理数据&#xff0c;结构太沉重。duckdb 是轻量级的方案&#xff0c;但没有内置 Oracle 的 connector&#xff0c;自己开发难度又太高。同为轻量级方案&#xff0c;esProc 支持 JDBC 公共接口&#xff0c;可以实现任何…

Linux 第二讲 --- 基础指令(二)

前言 这是基础指令的第二部分&#xff0c;但是该部分的讲解会大量使用到基础指令&#xff08;一&#xff09;的内容&#xff0c;为了大家的观感&#xff0c;如果对Linux的一些基本指令不了解的话&#xff0c;可以先看基础指令&#xff08;一&#xff09;&#xff0c;同样的本文…

P8627 [蓝桥杯 2015 省 A] 饮料换购

题目描述 思路 一是可以多枚举几个数&#xff0c;找找规律 二可以模拟 代码 #include<bits/stdc.h> #define int long long using namespace std;const int N 2e510;int a[N]; int b[N]; //前缀和 signed main() {int n;cin >> n; //表示初始的饮料盖int ans …

《Vue Router实战教程》12.不同的历史记录模式

欢迎观看《Vue Router 实战&#xff08;第4版&#xff09;》视频课程 不同的历史记录模式 在创建路由器实例时&#xff0c;history 配置允许我们在不同的历史模式中进行选择。 Hash 模式 hash 模式是用 createWebHashHistory() 创建的&#xff1a; import { createRouter,…