数据结构【顺序表】

文章目录

  • 1.顺序表的概念
    • 线性表
      • 物理结构
      • 逻辑结构
  • 2.顺序表的分类
    • 2.1静态顺序表
    • 2.2动态顺序表
  • 3.顺序表接口的实现
    • 头文件(SQList.h)如下
    • 源文件
      • 初始化顺序表
      • 销毁顺序表
      • 插入
        • 扩容
        • 尾插
        • 头插
      • 封装扩容函数
      • 删除
        • 尾删
        • 头删
      • 查找元素
      • 在指定位置前插入数据
        • 情况一(指定的位置不是首元素)
        • 情况二(指定的位置是首元素)
      • 删除指定位置
      • 打印顺序表
  • 完整代码
    • SQList.h
    • SQList.c
    • test.c (测试部分)
  • 结语

1.顺序表的概念

在认识顺序表之前,让我们先认识下线性表。

线性表

线性表是由n个相同类型的数据所组成的有限序列,线性表是一种在现实里被广泛使用的,常见的线性表有:顺序表、链表、栈、队列等等。
线性表在逻辑结构一定连续,但在物理结构中并不一定是连续的。

物理结构

物理结构就是数据存储于内存的结构,就那数组来说,数组开辟的空间是连续的,第x个数据的空间的下一块空间就是第x+1个数据,这就是物理结构连续。
在这里插入图片描述
如果我在设计表的时候,专门设计一个指针用来存放下一个数据的地址。
如下图:
在这里插入图片描述

第x数据和第x+1数据的空间并不是连续的,而是被指针位连接的,是像一个绳子,每个数据位就相当于绳结,指针位相当于绳结后面的绳子,这就是物理结构不连续。

逻辑结构

逻辑结构是我们自己抽象出来的,对于线性表来说,它的逻辑结构我们就可以把他想象成直线的线性结构,就拿上面物理结构不连续的例子来说,尽管它第一个数据和第二个数据在空间上并不是连续,但是我们可以把它们想象是连续的。
就类似于下图:
在这里插入图片描述
顺序表是线性表的一种,顺序表的特点就是物理层面和逻辑层面都连续,数据与数据之间都是相邻的
顺序表的底层是数组!!!

2.顺序表的分类

顺序表可以分为静态和动态两种

2.1静态顺序表

在创建之前将大小固定,这样虽然很简单,但是有局限性;如果给定的数据多了,就无法完整的存储数据;如果给定的数据少了,就会造成空间的浪费

typedef int SQLDATATYPE;
typedef struct SQList
{
	SQLDATATYPE a[100];//给定了100个数据,后续无法改动大小
	int size;//当前数据的个数
}SQList;

哪有什么方法可以解决呢?

2.2动态顺序表

内存大小是不固定的,需要使用时再进行动态开辟,如果后面有多的数据要存储,就可以使用realloc函数来进行增容,所以就更加的灵活

typedef int SQLDATATYPE;
typedef struct SQList
{
	SQLDATATYPE* a;
	int size;//当前数据的个数
	int capacity;//当前顺序表的容量
}SQList;

我们本章讲解的是动态顺序表

3.顺序表接口的实现

首先我们需要一个头文件和一个源文件;
头文件是用来声明顺序表函数的,源文件是用来实现顺序表函数的实现

头文件(SQList.h)如下

#pragma once

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

//typedef int SQLDATATYPE;
//typedef struct SQList
//{
//	SQLDATATYPE a[100];//给定了100个数据,后续无法改动大小
//	int size;//当前数据的个数
//}SQList;

typedef int SQLDATATYPE;
typedef struct SQList
{
	SQLDATATYPE* a;
	int size;//当前数据的个数
	int capacity;//当前顺序表的容量
}SQList;

//初始化顺序表
void SQListInit(SQList* plist);
//销毁顺序表
void SQListDestroy(SQList* plist);

//插入(尾部)
void SQListPushBack(SQList* plist, SQLDATATYPE x);
//删除(尾部)
void SQListPopBack(SQList* plist);

//插入(头部)
void SQListPushFront(SQList* plist, SQLDATATYPE x);
//删除(头部)
void SQListPopFront(SQList* plist);

//查找元素
int SQListFind(SQList* plist, SQLDATATYPE x);

//插入(指定位置前)
void SQListInsect(SQList* plist, int pst, SQLDATATYPE x);
//删除(指定位置)
void SQListDelete(SQList* plist, int pst);


//打印顺序表
void SQListPrint(SQList* plist);

源文件

记住要包含头文件

#include"SQList.h"

初始化顺序表

//初始化顺序表
void SQListInit(SQList* plist)
{
	plist->a = NULL;
	//其实也可以在初始化的时候就给a开辟空间(看个人喜好)
	plist->size = plist->capacity = 0;
}

一定要传址调用,这样才能真正的改变到顺序表

销毁顺序表

//销毁顺序表
void SQListDestroy(SQList* plist)
{
	assert(plist);
	free(plist->a);
	plist->a = NULL;//这一步是为了让a不会野指针
					//也可以避免a被重复释放(free函数不会对NULL进行操作)
	plist->size = plist->capacity = 0;
}

插入

插入就意味这内容的增加,就必然会导致内容空间的不足,这时候我们就需要进行扩容。

扩容

我们在插入之前要看,内部是否还有空间可以让我们插入,当size==capacity时,就代表表内已经填满数据了,我们就需要进行扩容
扩容用到的是realloc函数,我们扩容是默认是以两倍来扩容

尾插
void SQListPushBack(SQList* plist, SQLDATATYPE x)
{
	assert(plist);//检查plist是否为空指针
	if (plist->size == plist->capacity)//判断空间是否满了
	{
		int NewCapacity = plist->capacity == 0 ? 4 : 2 * plist->capacity;//此处为一个三目表达式
		//如果plist->capacity==0为真,将4赋给NewCapacity;反之则赋值2*plist->capacity

		SQLDATATYPE* tmp = (SQLDATATYPE*)realloc(plist->a, NewCapacity * sizeof(SQLDATATYPE));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(1);
		}
		plist->a = tmp;//将调整的空间赋给顺序表
		plist->capacity = NewCapacity;//调整容量
	}
	plist->a[plist->size] = x;
	plist->size++;
}
头插

头插我们就会遇到一个问题。
我们不能直接在顺序表的头部进行插入,这样会覆盖掉顺序表原来的数据,会造成数据的丢失。在这里插入图片描述

解决方法也很简单
我们将整个顺序表往后挪动一位,让下标为x的数据等于下标为x-1的数据。
因为我们size处是一个待插入数据的空间,所以这样并不会造成数据的丢失。在这里插入图片描述

代码如下:

void SQListPushFront(SQList* plist, SQLDATATYPE x)
{
	assert(plist);//检查plist是否为空指针
	if (plist->size == plist->capacity)
	{
		int NewCapacity = plist->capacity == 0 ? 4 : 2 * plist->capacity;//此处为一个三目表达式
		//如果plist->capacity==0为真,将4赋给NewCapacity;反之则赋值2*plist->capacity

		SQLDATATYPE* tmp = (SQLDATATYPE*)realloc(plist->a, NewCapacity * sizeof(SQLDATATYPE));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(1);
		}
		plist->a = tmp;//将调整的空间赋给顺序表
		plist->capacity = NewCapacity;//调整容量
	}

	for (int i = plist->size; i > 0; i--)//将整个顺序表往后挪动一位
	{
		plist->a[i] = plist->a[i - 1];
	}

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

封装扩容函数

这时候我们看到,尾插函数和头插函数有一段代码是一模一样的,我们接下来还有个指定位置前的插入,它也是可能会进行扩容函数的,如果这三个函数都使用一段相同的代码,就会显得代码很冗余。

我们就可以将这段代码抽离出来,封装成一个独立的函数,需要扩容的时候调用该函数就可以了。

代码如下:

//扩容函数
//因为扩容函数是在源代码运行的,所以可以不用在头文件进行声明(当然你也可以在头文件进行声明  看个人喜好)
void SQListAdd(SQList* plist)
{
	int NewCapacity = plist->capacity == 0 ? 4 : 2 * plist->capacity;//此处为一个三目表达式
	//如果plist->capacity==0为真,将4赋给NewCapacity;反之则赋值2*plist->capacity

	SQLDATATYPE* tmp = (SQLDATATYPE*)realloc(plist->a, NewCapacity * sizeof(SQLDATATYPE));
	if (tmp == NULL)
	{
		perror("realloc fail");
		exit(1);
	}
	plist->a = tmp;//将调整的空间赋给顺序表
	plist->capacity = NewCapacity;//调整容量
}

删除

尾删
//删除(尾部)
void SQListPopBack(SQList* plist)
{
	assert(plist);
	assert(plist->size > 0);//如果为0了,我还删什么呢?

	plist->size--;//这里很简单,就是将他的size进行--
	//size指向的是尾数据的下一块空间,也就是待插入的空间
	//我们--size,就相当于把尾数据的空间变成了待插入的空间
	//我们新增数据的时候,会把原来的值覆盖掉的
}
头删

这里有个问题

因为是删除头元素,我们不能直接将size–。

解决方法也很简单

将整个顺序表往前挪动一位,原理和头插的解决方法是类似的。
在这里插入图片描述
代码如下:

//删除(头部)
void SQListPopFront(SQList* plist)
{
	assert(plist);
	assert(plist->size > 0);//如果为0了,我还删什么呢?

	for (int i = 0; i < plist->size - 1; i++)//将整个顺序表往前挪动一位
	{
		plist->a[i] = plist->a[i + 1];
	}

	plist->size--;
}

查找元素

//查找元素
int SQListFind(SQList* plist, SQLDATATYPE x)
{
	assert(plist);
	int i = 0;
	while (i < plist->size)//size-1处就是最后一个数据
	{
		if (plist->a[i] == x)//找到了
			return i;//返回的是下标
		i++;
	}
	//i=size 跳出循环
	//找不到
	return EOF;//EOF(-1)
}

在指定位置前插入数据

情况一(指定的位置不是首元素)

我们就将指定位置及以后的数据往后挪一位;,再将数据插入到指定位置的下标。
在这里插入图片描述

情况二(指定的位置是首元素)

那么是首元素了,我们在首元素前进行插入,这是什么?
这不就是头插吗
所以我们可以直接调用我们已经写好的头插函数

//插入(指定位置前)
void SQListInsect(SQList* plist, int pst, SQLDATATYPE x)
{
	assert(plist);
	if (plist->size == plist->capacity)
	{
		SQListAdd(plist);//这里就直接调用了增容函数
	}

	//这里有两种情况
	//第一种当pst不是首元素
	if (pst != 0)
	{
		for (int i = plist->size; i > pst; i--)//将顺序表pst后面的数据往后挪动一位
		{
			plist->a[i] = plist->a[i - 1];
		}
		plist->a[pst] = x;
	}

	//第二种:当pst是首元素
	//那么是首元素了,我们在首元素前进行插入,这是什么?
	//这不就是头插吗
	//所以我们可以直接调用我们已经写好的头插函数
	else
	{
		SQListPushFront(plist, x);
	}
}

删除指定位置

我们只要将指定位置后面的数据往前挪动一位

//删除(指定位置)
void SQListDelete(SQList* plist, int pst)
{
	assert(plist);
	assert(plist->size > 0);//如果为0了,我还删什么呢

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

打印顺序表

//打印顺序表
void SQListPrint(SQList* plist)
{
	assert(plist);
	if (plist->size == 0)
		printf(NULL);
	for (int i = 0; i < plist->size; i++)
	{
		printf("%d ", plist->a[i]);
	}
	printf("\n");
}

完整代码

SQList.h

#pragma once

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

//typedef int SQLDATATYPE;
//typedef struct SQList
//{
//	SQLDATATYPE a[100];//给定了100个数据,后续无法改动大小
//	int size;//当前数据的个数
//}SQList;

typedef int SQLDATATYPE;
typedef struct SQList
{
	SQLDATATYPE* a;
	int size;//当前数据的个数
	int capacity;//当前顺序表的容量
}SQList;

//初始化顺序表
void SQListInit(SQList* plist);
//销毁顺序表
void SQListDestroy(SQList* plist);

//插入(尾部)
void SQListPushBack(SQList* plist, SQLDATATYPE x);
//删除(尾部)
void SQListPopBack(SQList* plist);

//插入(头部)
void SQListPushFront(SQList* plist, SQLDATATYPE x);
//删除(头部)
void SQListPopFront(SQList* plist);

//查找元素
int SQListFind(SQList* plist, SQLDATATYPE x);

//插入(指定位置前)
void SQListInsect(SQList* plist, int pst, SQLDATATYPE x);
//删除(指定位置)
void SQListDelete(SQList* plist, int pst);


//打印顺序表
void SQListPrint(SQList* plist);

SQList.c

#include"SQList.h"

//初始化顺序表
void SQListInit(SQList* plist)
{
	plist->a = NULL;
	//其实也可以在初始化的时候就给a开辟空间(看个人喜好)
	plist->size = plist->capacity = 0;
}

//销毁顺序表
void SQListDestroy(SQList* plist)
{
	assert(plist);
	free(plist->a);
	plist->a = NULL;//这一步是为了让a不会野指针
					//也可以避免a被重复释放(free函数不会对NULL进行操作)
	plist->size = plist->capacity = 0;
}

//扩容函数
//因为扩容函数是在源代码运行的,所以可以不用在头文件进行声明(当然你也可以在头文件进行声明  看个人喜好)
void SQListAdd(SQList* plist)
{
	int NewCapacity = plist->capacity == 0 ? 4 : 2 * plist->capacity;//此处为一个三目表达式
	//如果plist->capacity==0为真,将4赋给NewCapacity;反之则赋值2*plist->capacity

	SQLDATATYPE* tmp = (SQLDATATYPE*)realloc(plist->a, NewCapacity * sizeof(SQLDATATYPE));
	if (tmp == NULL)
	{
		perror("realloc fail");
		exit(1);
	}
	plist->a = tmp;//将调整的空间赋给顺序表
	plist->capacity = NewCapacity;//调整容量
}

//插入(尾部)
void SQListPushBack(SQList* plist, SQLDATATYPE x)
{
	assert(plist);//检查plist是否为空指针
	if (plist->size == plist->capacity)
	{
		SQListAdd(plist);
	}
	plist->a[plist->size] = x;
	plist->size++;
}

//删除(尾部)
void SQListPopBack(SQList* plist)
{
	assert(plist);
	assert(plist->size > 0);//如果为0了,我还删什么呢?

	plist->size--;//这里很简单,就是将他的size进行--
	//size指向的是尾数据的下一块空间,也就是待插入的空间
	//我们--size,就相当于把尾数据的空间变成了待插入的空间
	//我们新增数据的时候,会把原来的值覆盖掉的
}

//插入(头部)
void SQListPushFront(SQList* plist, SQLDATATYPE x)
{
	assert(plist);//检查plist是否为空指针
	if (plist->size == plist->capacity)
	{
		SQListAdd(plist);
	}

	for (int i = plist->size; i > 0; i--)//将整个顺序表往后挪动一位
	{
		plist->a[i] = plist->a[i - 1];
	}

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

//删除(头部)
void SQListPopFront(SQList* plist)
{
	assert(plist);
	assert(plist->size > 0);//如果为0了,我还删什么呢?

	for (int i = 0; i < plist->size - 1; i++)//将整个顺序表往前挪动一位
	{
		plist->a[i] = plist->a[i + 1];
	}

	plist->size--;
}

//查找元素
int SQListFind(SQList* plist, SQLDATATYPE x)
{
	assert(plist);
	int i = 0;
	while (i < plist->size)//size-1处就是最后一个数据
	{
		if (plist->a[i] == x)//找到了
			return i;//返回的是下标
		i++;
	}
	//i=size 跳出循环
	//找不到
	return EOF;//EOF(-1)
}

//插入(指定位置前)
void SQListInsect(SQList* plist, int pst, SQLDATATYPE x)
{
	assert(plist);
	if (plist->size == plist->capacity)
	{
		SQListAdd(plist);
	}

	//这里有两种情况
	//第一种当pst不是首元素
	if (pst != 0)
	{
		for (int i = plist->size; i > pst; i--)//将顺序表pst后面的数据往后挪动一位
		{
			plist->a[i] = plist->a[i - 1];
		}
		plist->a[pst] = x;
	}

	//第二种:当pst是首元素
	//那么是首元素了,我们在首元素前进行插入,这是什么?
	//这不就是头插吗
	//所以我们可以直接调用我们已经写好的头插函数
	else
	{
		SQListPushFront(plist, x);
	}
}

//删除(指定位置)
void SQListDelete(SQList* plist, int pst)
{
	assert(plist);
	assert(plist->size > 0);//如果为0了,我还删什么呢

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

//打印顺序表
void SQListPrint(SQList* plist)
{
	assert(plist);
	if (plist->size == 0)
		printf(NULL);
	for (int i = 0; i < plist->size; i++)
	{
		printf("%d ", plist->a[i]);
	}
	printf("\n");
}

test.c (测试部分)

#include"SQList.h"

void TestSQL()
{
	SQList sq;
	SQListInit(&sq);

	SQListPushBack(&sq, 1);
	SQListPushBack(&sq, 2);
	SQListPushBack(&sq, 3);
	SQListPushBack(&sq, 4);
	SQListPushBack(&sq, 5);
	SQListPushBack(&sq, 6);

	SQListPushFront(&sq, 0);

	SQListPopBack(&sq);
	SQListPushBack(&sq, 128);
	//SQListPrint(&sq);
	//SQListPopFront(&sq);
	//SQListPrint(&sq);

	int flag = SQListFind(&sq, 3);
	//if (flag != EOF)
	//{
	//	printf("找到了 下标为%d\n", flag);
	//}
	//else
	//{
	//	printf("找不到\n");
	//}

	SQListInsect(&sq, flag, 255);

	//SQListDelete(&sq, flag);

	SQListPrint(&sq);

	SQListDestroy(&sq);
}

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

结语

最后感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言。

如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!!!

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

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

相关文章

淘宝扭蛋机小程序开发:探索未知的惊喜世界

一、引言 在这个充满无限可能的数字时代&#xff0c;每一次点击都可能带来意想不到的惊喜。淘宝扭蛋机小程序&#xff0c;正是为了满足您对惊喜的渴望&#xff0c;将扭蛋的趣味与购物的便捷完美结合&#xff0c;带您进入一个充满未知与乐趣的惊喜世界。 二、产品介绍 淘宝扭…

Redis教程(二):Redis在Linux环境下的安装

Linux环境下安装&#xff1a; 下载地址&#xff1a;Downloads - Redis 安装步骤&#xff1a; 下载得到一个 tar.gz 压缩文件 上传到Linux的/opt/soft目录&#xff0c;使用以下命令解压 tar -zxvf redis-6.2.14.tar.gz Linux安装基本环境gcc&#xff0c;安装命令 yum insta…

Encoder——Decoder工作原理与代码支撑

神经网络算法 &#xff1a;一文搞懂 Encoder-Decoder&#xff08;编码器-解码器&#xff09;_有编码器和解码器的神经网络-CSDN博客这篇文章写的不错&#xff0c;从定性的角度解释了一下&#xff0c;什么是编码器与解码器&#xff0c;我再学习笔记补充的时候&#xff0c;讲一下…

什么是网络端口?为什么会有高危端口?

一、什么是网络端口&#xff1f; 网络技术中的端口默认指的是TCP/IP协议中的服务端口&#xff0c;一共有0-65535个端口&#xff0c;比如我们最常见的端口是80端口默认访问网站的端口就是80&#xff0c;你直接在浏览器打开&#xff0c;会发现浏览器默认把80去掉&#xff0c;就是…

dfs记忆化搜索,动态规划

动态规划概念&#xff1a; 给定一个问题&#xff0c;将其拆成一个个子问题&#xff0c;直到子问题可以直接解决。然后把子问题的答案保存起来&#xff0c;以减少重复计算。再根据子问题的答案反推&#xff0c;得出原问题解。 821 运行时间长的原因&#xff1a; 重复大量计算…

Cadence 16.6 绘制PCB封装时总是卡死的解决方法

Cadence 16.6 绘制PCB封装时总是卡死的解决方法 在用Cadence 16.6 PCB Editor绘制PCB封装时候&#xff0c;绘制一步卡死一步&#xff0c;不知道怎么回事儿&#xff0c;在咨询公司IT后&#xff0c;发现是WIN系统自带输入法的某些热键与PCB Editor有冲突&#xff0c;导致卡死。 …

融资融券最低利率4.0!,融资融券利息计算公式,怎么开通?

融资融券的费率&#xff1a; 融资融券的费率主要包括融资利率和融券费率&#xff0c;这些费率的高低主要取决于证券公司的成本、政策倾向以及投资者的资金量大小。 融资利率方面&#xff0c;多数券商的优惠融资利率在5.5%到7.5%之间&#xff0c;与券商的成本和政策有关。一些…

带你了解AI大模型的前世今生

过去&#xff0c;开发者用代码来改变世界&#xff0c;未来&#xff0c;自然语言将成为通用的编程语言。大模型是如何成功的&#xff1f;有哪些应用&#xff1f;现在如何入局&#xff1f;一个全知全能的大模型能适配一切吗&#xff1f;在这个 AI 时代&#xff0c;什么样的工具才…

请收好,这份思科备考攻略很细节

对于网络工程师来说&#xff0c;思科认证无疑是一块金字招牌。它不仅代表着专业技能&#xff0c;更是职业发展的加速器。 今天我们不聊选思科认证还是华为认证&#xff0c;只能说是各有各的好&#xff0c;如果你已经选择了思科认证&#xff0c;那么这份备考攻略将为你提供一些实…

JavaScript异步编程——11-异常处理方案【万字长文,感谢支持】

异常处理方案 在JS开发中&#xff0c;处理异常包括两步&#xff1a;先抛出异常&#xff0c;然后捕获异常。 为什么要做异常处理 异常处理非常重要&#xff0c;至少有以下几个原因&#xff1a; 防止程序报错甚至停止运行&#xff1a;当代码执行过程中发生错误或异常时&#x…

国网1376.1主站与采集终端通信协议和国网1376.2集中器本地通信模块接口协议报文解析工具

本文分享一个国网1376.1主站与采集终端通信协议的报文解析工具&#xff0c;同时本报文解析软件也支持国网1376.2集中器本地通信模块接口协议的报文解析。 下载链接: https://pan.baidu.com/s/1ngbBG-yL8ucRWLDflqzEnQ 提取码: y1de 主界面如下图所示&#xff1a; 同时本软件自…

继承,多态,封装以及对象的打印

前言&#xff1a; 我们都知道Java是一种面向对象的编程语言&#xff0c;面向对象语言的三大特性就是继承&#xff0c;多态&#xff0c;封装&#xff0c;而这些特性正好的Java基础的一个主体内容。在学到这之前&#xff0c;我们肯定已经学习过了类和对象&#xff0c;所以这部分…

关于FIFO Generator IP和XPM_FIFO在涉及位宽转换上的区别

在Xilinx FPGA中&#xff0c;要实现FIFO的功能时&#xff0c;大部分时候会使用两种方法&#xff1a; FIFO Generator IP核XPM_FIFO原语 FIFO Generator IP核的优点是有图形化界面&#xff0c;配置参数非常直观&#xff1b;缺点是参数一旦固定&#xff0c;想要更改的化就只能重…

幻兽帕鲁Palworld服务器手动部署

目录 帕鲁官方文档手动安装steamcmd通过steamcmd安装帕鲁后端客户端连接附录&#xff1a;PalServer.sh的启动项附录&#xff1a;配置文件 帕鲁官方文档 https://tech.palworldgame.com/ 手动安装steamcmd 创建steam用户 sudo useradd -m steam sudo passwd steam下载steamc…

迭代的难题:敏捷团队每次都有未完成的工作,如何破解?

各位是否遇到过类似的情况&#xff1a;每次迭代结束后&#xff0c;团队都有未完成的任务&#xff0c;很少有完成迭代全部的工作&#xff0c;相反&#xff0c;总是将上期未完成的任务重新挪到本期计划会中&#xff0c;重新规划。敏捷的核心之一是“快速迭代&#xff0c;及时反馈…

ssm基于BS的项目监管系统+jsp论文

系统简介 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上…

Unity 2021 升级至团结引擎

UnityWebRequest 报错 InvalidOperationException: Insecure connection not allowed 解决方法 不兼容jdk 8 需要安装 JDK11 64bit 必须JDK 11&#xff0c;高版本也不行 安卓环境hub 未给我安装完全。 Data\PlaybackEngines\AndroidPlayer 并没有NDK,SDK。但是 HUB 显示已经…

IT行业的现状和未来发展趋势:技术创新、市场需求、人才培养、政策法规和社会影响

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

【大数据】计算引擎MapReduce

目录 1.概述 1.1.前言 1.2.大数据要怎么计算&#xff1f; 1.3.什么是MapReduce&#xff1f; 2.架构 3.工作流程 4.shuffle 4.1.map过程 4.2.reduce过程 1.概述 1.1.前言 本文是作者大数据系列专栏的其中一篇&#xff0c;专栏地址&#xff1a; https://blog.csdn.ne…

Java | 增强for底层工作机制

✍&#x1f3fc;作者&#xff1a;周棋洛&#xff0c;bilidown开发者。 ♉星座&#xff1a;金牛座 &#x1f3e0;主页&#xff1a;我的个人网站 &#x1f310;关键&#xff1a;Java 增强for 工作机制 目录 引言增强for循环语法增强for工作机制探究简单总结1.对于实现了Iterable接…