数据结构:栈和队列的实现附上源代码(C语言版)

news2024/11/18 7:24:32

目录

前言

1.栈

1.1 栈的概念及结构

1.2 栈的底层数据结构选择

1.2 数据结构设计代码(栈的实现)

1.3 接口函数实现代码

(1)初始化栈

(2)销毁栈

(3)压栈

(4)出栈

(5)获取栈顶元素

(6)获取栈中有效元素的个数

(7)检测栈是否为空

1.4 测试函数

2. 队列

2.1 队列概念及结构

2.2 队列的底层数据结构的选择

2.2 数据结构设计代码(队列的实现)

2.3 接口函数

(1)初始化队列

(2)销毁队列

(3)队尾入队列

(4)队头出队列

(5)获取队列头部元素

(6)获取队列尾部元素

(7)获取队列中有效元素个数

(8)检测队列是否为空

2.4 测试函数

3. 栈和队列的源代码

3.1 栈

(1)Stack.h

(2)Stack.c

(3)STtest.c

3.2 队列

(1)Queue.h

(2)Queue.c

(3)Qtest.c

总结


前言

这篇文章是关于栈和队列的C语言实现,干货满满,大家可以边看边手写代码,最后附上栈和队列的参考代码。


1.栈

1.1 栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶

这个数据结构可以理解为炸串。在最开始,插入丸子时,要插到这根签的最底部,就是入栈。开始吃的时候,一般从最上面的丸子入手,就是出栈

1.2 栈的底层数据结构选择

我们学过顺序表和链表两种数据结构,用那种会更好呢?

  • 相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。不用挪动数据,删除操作也很简单。
  • 而链表如果要入栈,就是链表的尾插,我们需要找到链表的尾结点,效率低。出栈也是一样。

1.2 数据结构设计代码(栈的实现)

在用C语言实现栈各种接口函数,需要创建三个文件,分别是STtest.c,Stack.c和Stack.h。

  • STtest.c文件用来测试接口函数是否能成功。
  • Stack.c文件里面放的是各种接口函数实现的代码
  • Stack.h文件放置各种头文件的声明,栈数据结构的设计和接口函数的声明。下面的代码就是放在此文件中。
typedef int STDataType;
// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
typedef int STDataType;
#define N 10
typedef struct Stack
{
	STDataType _a[N];
	int _top; // 栈顶
}Stack;

// 支持动态增长的栈
typedef struct Stack
{
	STDataType* a;
	int top;      //栈顶
	int capacity; //容量
}ST;

//初始化栈
void StackInit(ST* ps);
//销毁栈
void StackDestroy(ST* ps);
//压栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//获取栈顶元素
STDataType StackTop(ST* ps);
//获取栈中有效元素个数
int StackSize(ST* ps);
//检测栈是否为空,为空返回true
bool StackEmpty(ST* ps);

1.3 接口函数实现代码

(1)初始化栈

初始化栈一开始要断言,断言来判断ps指针是否为空,如果为空会直接终止程序并给出提示,方便之后的调试,之后的断言不再赘述。指针指向空,内部整型数据赋值为0。但是top得注意,top其实也是个下标。看下面的注释,top可以有两种赋值方式,只是表示不同意思。

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;//表示指向栈顶的下一个元素
    //ps->top = -1 ///表示指向栈顶元素
	ps->capacity = 0;
}

(2)销毁栈

因为我们是以数组为基础,是动态开辟的连续空间,直接释放掉ps中的数组指针,并要置为空。

void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;//易错
	ps->top = ps->capacity = 0;
}

(3)压栈

栈的压栈操作跟顺序表的尾插类似,先要检查内部空间容量是否足够,一开始给四个该数据结构的空间,之后的按两倍来扩容。最后就是插入数据,栈顶减一。

void StackPush(ST* ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

		ps->a = tmp;
		ps->capacity = newCapacity;
	}

	ps->a[ps->top] = x;
	ps->top++;
}

(4)出栈

这次不仅要判断ps是否不为空指针,还要判断栈内是否有元素,这样才可以删除元素,让栈顶减一即可。

void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}

(5)获取栈顶元素

这里的判断跟上个接口函数一样,只有栈内有元素,才能取栈顶元素。

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	return ps->a[ps->top - 1];
}

(6)获取栈中有效元素的个数

此时的top表示的是栈顶的下一个元素的下标,刚好就是元素个数,直接返回栈顶top

int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

(7)检测栈是否为空

很多人会写个if语句判断,其实可以直接像下面一样写,ps->top == 0变成一个判断语句,如果为真返回一个部位0的数,如果为假返回0。

bool StackEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

1.4 测试函数

我们写两个测试函数,第一个测试函数,是出栈和入栈的操作,可以调试查看。第二个测试函数是栈的数据打印,需要使用StackTop获取栈顶元素,然后将打印的数据出栈。

void TestStack1()
{
	ST st;
	StackInit(&st);

	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);

	StackPop(&st);
	StackPop(&st);
	StackPop(&st);
	StackPop(&st);
	StackPop(&st);

	StackDestroy(&st);
}

void TestStack2()
{
	ST st;
	StackInit(&st);

	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);

	while (!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}
	StackDestroy(&st);
}

int main()
{
	TestStack1();
	TestStack2();

	return 0;
}

输出结果:

2. 队列

2.1 队列概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)

入队列:进行插入操作的一端称为队尾

出队列:进行删除操作的一端称为队头

 这个数据结构可以理解为在银行取号,先取号的人,就是入队列。然后先取到号的人,就先去窗口处理业务,这就是出队列。

2.2 队列的底层数据结构的选择

跟栈一样,队列也可以用顺序表和链表来实现,那哪一个更好呢?

  • 相较于数组,使用链表更优一些。队列的入队和出队,分别是链表的尾插和头删,不过我们会创建两个指针指向头结点和尾结点,所以不会有时间的消耗。
  • 而数组在头部插入和删除数据,都要挪动数据,效率较低。

链表的数据结构存储的是一个数据变量,和指向下一个结点的指针变量。我们入队列和出队列分别在队尾和队头,所以我们在队列的数据结构定义两个链表的指针变量head和tail,表示队头和队尾

2.2 数据结构设计代码(队列的实现)

跟栈的实现一样,首先要创建三个文件Qtest.c,Queue.c和Queue.h。

  • Qtest.c文件用来测试接口函数是否能成功。
  • Queue.c文件里面放的是各种接口函数实现的代码
  • Queue.h文件放置各种头文件的声明,栈数据结构的设计和接口函数的声明。下面的代码就是放在此文件中。
// 链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;

// 队列的结构
typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
}Queue;

//初始化队列
void QueueInit(Queue* pq); 
//销毁队列
void QueueDestroy(Queue* pq);
//队尾入队列
void QueuePush(Queue* pq, QDataType x);
//队头出队列
void QueuePop(Queue* pq);
//获取队列头部元素
QDataType QueueFront(Queue* pq);
//获取队列尾部元素
QDataType QueueBack(Queue* pq);
//获取队列中有效元素个数
int QueueSize(Queue* pq);
//检测队列是否为空,如果为空返回true
bool QueueEmpty(Queue* pq);

2.3 接口函数

(1)初始化队列

队列初始化,只需要将队头链表指针和队尾链表指针置为空指针就好。

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

(2)销毁队列

因为是以链表为基础,需要用while循环释放掉每一个动态开辟的结点。

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->head;
	while (cur != NULL)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->head = pq->tail = NULL;
}

(3)队尾入队列

队尾入队列就是链表的尾插,但是我们有tail指针,直接在tail后面插入就好。不过需要分是否为空队列两种情况,如果是空队列,head和tail指针都指向新结点,如果不是空队列,在tail之后插入。

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("Queue malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;

	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

(4)队头出队列

在操作之前,我们需要判断队列是否有元素。然后在释放第一个结点,改变指针指向。

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	QueueNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;
}

(5)获取队列头部元素

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;
}

(6)获取队列尾部元素

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

(7)获取队列中有效元素个数

这需要一个计数变量。

int QueueSize(Queue* pq)
{
	assert(pq);

	int n = 0;
	QueueNode* cur = pq->head;
	while (cur)
	{
		n++;
		cur = cur->next;
	}

	return n;
}

(8)检测队列是否为空

跟栈判空相同。

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

2.4 测试函数

写两个测试函数,第一是入队列和出队列的操作,可以一步一步调试看情况。第二个测试函数,是打印队列里的数据,现获取队头的数据,然后再出队。

void TestQueue1()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);

	QueuePop(&q);
	QueuePop(&q);
	QueuePop(&q);
	QueuePop(&q);
	
	printf("%d\n", QueueBack(&q));

	QueueDestroy(&q);
}

void TestQueue2()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);

	while (!QueueEmpty(&q))
	{
		QDataType front = QueueFront(&q);
		printf("%d ", front);
		QueuePop(&q);
	}
	printf("\n");
}

int main()
{
	TestQueue1();
	TestQueue2();

	return 0;
}

输出的结果:

3. 栈和队列的源代码

3.1 栈

(1)Stack.h

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

typedef int STDataType;
 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
//typedef int STDataType;
//#define N 10
//typedef struct Stack
//{
//	STDataType _a[N];
//	int _top; // 栈顶
//}Stack;

// 支持动态增长的栈
typedef struct Stack
{
	STDataType* a;
	int top;      //栈顶
	int capacity; //容量
}ST;
//初始化栈
void StackInit(ST* ps);
//销毁栈
void StackDestroy(ST* ps);
//压栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//获取栈顶元素
STDataType StackTop(ST* ps);
//获取栈中有效元素个数
int StackSize(ST* ps);
//检测栈是否为空,为空返回true
bool StackEmpty(ST* ps);

(2)Stack.c

#include "Stack.h"

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;//ps->top = -1
	ps->capacity = 0;
}

void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

void StackPush(ST* ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

		ps->a = tmp;
		ps->capacity = newCapacity;
	}

	ps->a[ps->top] = x;
	ps->top++;
}

void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	return ps->a[ps->top - 1];
}

int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

bool StackEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

(3)STtest.c

#include "Stack.h"

void TestStack1()
{
	ST st;
	StackInit(&st);

	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);

	StackPop(&st);
	StackPop(&st);
	StackPop(&st);
	StackPop(&st);
	StackPop(&st);

	StackDestroy(&st);
}

void TestStack2()
{
	ST st;
	StackInit(&st);

	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);

	//printf("%d ", StackTop(&st));
	//StackPop(&st);
	//printf("%d ", StackTop(&st));
	//StackPop(&st);

	//StackPush(&st, 5);
	//StackPush(&st, 6);

	while (!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}

	StackDestroy(&st);
}

int main()
{
	TestStack1();
	//TestStack2();

	return 0;
}

3.2 队列

(1)Queue.h

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

// 链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;

// 队列的结构
typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
}Queue;

//初始化队列
void QueueInit(Queue* pq); 
//销毁队列
void QueueDestroy(Queue* pq);
//队尾入队列
void QueuePush(Queue* pq, QDataType x);
//队头出队列
void QueuePop(Queue* pq);
//获取队列头部元素
QDataType QueueFront(Queue* pq);
//获取队列尾部元素
QDataType QueueBack(Queue* pq);
//获取队列中有效元素个数
int QueueSize(Queue* pq);
//检测队列是否为空,如果为空返回true
bool QueueEmpty(Queue* pq);

(2)Queue.c

#include "Queue.h"

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->head;
	while (cur != NULL)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->head = pq->tail = NULL;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("Queue malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;

	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	QueueNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;
}


QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

int QueueSize(Queue* pq)
{
	assert(pq);

	int n = 0;
	QueueNode* cur = pq->head;
	while (cur)
	{
		n++;
		cur = cur->next;
	}

	return n;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

(3)Qtest.c

void TestQueue1()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);

	QueuePop(&q);
	QueuePop(&q);
	QueuePop(&q);
	QueuePop(&q);
	
	printf("%d\n", QueueBack(&q));

	QueueDestroy(&q);
}

void TestQueue2()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);

	while (!QueueEmpty(&q))
	{
		QDataType front = QueueFront(&q);
		printf("%d ", front);
		QueuePop(&q);
	}
	printf("\n");
}

int main()
{
	//TestQueue1();
	TestQueue2();
	return 0;
}


总结

栈和队列的实现其实相较于链表的实现简单一些,是因为其结构的特殊要求。之后会出一篇关于栈和队列的OJ题目。多多重复,百炼成钢!

创作不易,希望这篇文章能给你带来启发和帮助,如果喜欢这篇文章,请留下你的三连,你的支持的我最大的动力!!!

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

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

相关文章

求最短路径之BF算法

介绍 全称Bellman-Ford算法&#xff0c;目的是求解有负权边的最短路径问题。 考虑环&#xff0c;根据环中边的边权之和的正负&#xff0c;将环分为零环、正环、负环。其中零环、正环不会影响最短路径的求解&#xff0c;而负环会影响最短路径的求解。 可用BF算法返回一个bool值…

java开发环境配置一指禅

IDEA下载与安装 IDEA 全称 IntelliJ IDEA&#xff0c;是java编程语言的集成开发环境。 idea下载地址 。 JDK安装配置 JDK是 Java 语言的软件开发工具包&#xff0c;主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心&#xff0c;它包含了JAVA的运行环…

vue项目获取拼音首字母

工具包 pinyin-pro npm install pinyin-pro 官方地址 pinyin-pro | pinyin-pro性能优异、转换准确的 js 中文转拼音工具https://pinyin-pro.cn/示例代码(获取每个汉字的拼音首字母) import {pinyin} from pinyin-pro;function getPinyinInitial(name){if (name) {let py p…

aop监控spring cloud接口超时,并记录到数据库

引入pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0…

PlantUML简介

PlantUML简介 plantUML是一款开源的UML图绘制工具&#xff0c;支持通过文本来生成图形&#xff0c;使用起来非常高效。可以支持时序图、类图、对象图、活动图、思维导图等图形的绘制。你可以在IDEA中安装插件来使用PlantUML, 或者在Visual Studio Code中安装插件。 也可以在dra…

2024免费mac苹果电脑的清理和维护软件CleanMyMac X

对于 Mac 用户来说&#xff0c;电脑的清理和维护是一件让人头疼的事情。但是&#xff0c;有了 CleanMyMac X&#xff0c;这一切都将变得轻松愉快。CleanMyMac X 是一款专为 Mac 设计的电脑清理软件&#xff0c;它以其强大的功能和简单的操作&#xff0c;让无数用户为之倾倒。 C…

C语言学习DAY22

内存泄漏&#xff1a;开辟的内存空间不使用了&#xff0c;但不释放该内存空间。

AutoSAR(基础入门篇)13.3-Mcal Dio配置

目录 一、Dio port配置 二、Dio pin配置 一、Dio port配置 同之前的Port一样,双击进入Dio配置界面后会看到几乎差不多的配置界面。General和Port类似,我们不再赘述,主要讲解Dio的配置 1. 其实Dio并没有什么实质的作用,主要起到了一个重命名的功能。双击DioConfig_0进入下…

spring项目单元测试

单元测试 每个功能开发完&#xff0c;项目上线前都要做单元测试 引入依赖 AssertJ&#xff1a;断言 测试用例 编写测试用例要求&#xff1a;保证测试方法的独立性 当前测试方法不能依赖于别的测试方法&#xff0c;也不依赖于数据库中某条特定数据。 如A方法插入一条数据&a…

在网页上踢球:打造我自己的python(Django)足球网站

足球不仅仅是球场上的90分钟。它是一个不断发展的故事&#xff0c;一个全球球迷社群的粘合剂&#xff0c;一个数据和热情交织的世界。作为一名开发者和球迷&#xff0c;我决定将这两大爱好结合起来&#xff0c;用 Django 打造一个足球网站&#xff0c;让球迷们能够追踪他们最爱…

LeetCode --- 三数之和

题目描述 三数之和 代码解析 暴力 在做这一道题的时候&#xff0c;脑海里先想出来的是暴力方法&#xff0c;一次排序&#xff0c;将这个数组变为有序的&#xff0c;再通过三次for循环来寻找满足条件的数字&#xff0c;然后将符合条件的数组与之前符合条件的数组进行一一对比…

YOLOv9独家原创改进|使用HWD:Haar小波下采样模块

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、论文简介 最大池化或跨步卷积等下采样操作在卷积神经网络&#xff08;CNNs&#xff09;中广泛使用&#xff0c;以聚合局部特征&#xff0c;扩大感…

基于springboot+vue的客户关系管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Linux系统管理:虚拟机 Kali Linux 安装

目录 一、理论 1.Kali Linux 二、实验 1.虚拟机Kali Linux安装准备阶段 2.安装Kali Linux 2. Kali Linux 更换国内源 3. Kali Linux 设置固定IP 4. Kali Linux 开启SSH远程连接 5. MobaXterm远程连接 Kali Linux 三、问题 1.apt 命令 取代哪些 apt-get命令 一、理论…

ChatGPT支持下的PyTorch机器学习与深度学习技术应用

近年来&#xff0c;随着AlphaGo、无人驾驶汽车、医学影像智慧辅助诊疗、ImageNet竞赛等热点事件的发生&#xff0c;人工智能迎来了新一轮的发展浪潮。尤其是深度学习技术&#xff0c;在许多行业都取得了颠覆性的成果。另外&#xff0c;近年来&#xff0c;Pytorch深度学习框架受…

探索那些能唤起情感共鸣的壁纸

1、方小童在线工具集 网址&#xff1a; 方小童 该网站是一款在线工具集合的网站&#xff0c;目前包含PDF文件在线转换、随机生成美女图片、精美壁纸、电子书搜索等功能&#xff0c;喜欢的可以赶紧去试试&#xff01;

平台工程: 用Backstage构建开发者门户 - 2

本文介绍了如何使用开源Backstage构建自己的开发者门户&#xff0c;并基于此实践平台工程。本系列共两篇文章&#xff0c;这是第二篇。原文: Platform Engineering: Building Your Developer Portal with Backstage — Part 2 在本教程第一部分中我们了解了Backstage这个用于构…

Docker基础教程 - 1 Docker简介

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; 1 Docker简介 Docker是一个强大的容器化平台&#xff0c;让你能够更轻松地构建、部署和运行应用程序。 下面我们来学习 Docker。 1.1 Docker是什么 1 现在遇到的问题 每次部署一台服务器&…

Python学习 day07(JSON)

JSON 各种编程语言存储数据的容器不尽相同&#xff0c;在Python中有字典dict这样的数据类型&#xff0c;而其他语言可能没有对应的字典&#xff0c;为了让不同的语言都能够相互通用的传递数据&#xff0c;JSON就是一种非常良好的中转数据格式&#xff0c;如下&#xff1a; JSON…

广和通5G智能模组SC171支持Android、Linux和Windows系统,拓宽智能物联网应用

世界移动通信大会2024期间&#xff0c;广和通宣布&#xff1a;5G智能模组SC171除支持Android操作系统外&#xff0c;还兼容Linux和Windows系统&#xff0c;帮助更多智能终端客户快速迭代产品&#xff0c;拓宽智能化应用覆盖范围。 广和通SC171系列基于高通QCM6490物联网解决方案…