c语言实现栈(顺序栈,链栈)

news2024/11/24 0:59:23

在这里插入图片描述

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:讲解用c语言实现:“数据结构之"栈”,分别从"顺序栈"和"链栈"的接口讲解.
金句分享:
✨不是每一场雨后都有彩虹,但是晴天总是会到来!✨

前言

目录

  • 前言
    • "栈"的常见接口实现
  • 一、顺序栈
      • "顺序栈"的类型定义
      • 1.1 初始化栈
      • 1.2 入栈(压栈,向"栈"中插入数据)
      • 1.3 "出栈",删除"栈"中的数据
      • 1.4 判空(判断"栈"是否为空)
      • 1.5 打印"栈顶"元素
      • 1.6 返回"栈顶"元素
      • 1.7 "栈"的销毁
  • 二、链栈
    • "链栈"的类型定义
      • 2.1 初始化"链栈"
      • 2.2 入栈(压栈,向"栈"中插入数据)
      • 2.3 "出栈",删除"栈"中的数据
      • 2.4 判空(判断"栈"是否为空)
      • 2.5 打印"栈顶"元素
      • 2.6 返回"栈顶"元素
      • 2.7 返回"链栈"的长度(有效数据的个数)
      • 2.8 "链栈"的销毁
  • 总结:
  • 总代码
    • "顺序栈"总代码
      • 声明区(stack.h)
      • 接口实现区( stack.c)
      • 测试区(test.c)
    • "链栈"总代码:
      • 声明区(SLStack.h)
      • 接口实现区(SLStack.c)
      • 测试区(test.c)

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

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

出栈:栈的删除操作叫做出栈。出数据也在栈顶

在这里插入图片描述

"栈"的常见接口实现

  • InitST:初始化栈
  • STPush:入栈
  • STPop:出栈
  • STEmpty:判空(判断是否为空栈)
  • PrintSTTop:打印栈顶元素
  • STTop:返回栈顶元素(返回值类型:stacktype)

一、顺序栈

"顺序栈"的类型定义

如果友友们学过顺序表,这种类型可以随便拿捏.😄😄

代码:

typedef struct stack
{
	stacktype* data;//一个指向连续内存空间的指针
	int top;//记录栈顶元素的下标
	int capacaity;
}ST;

在这里插入图片描述

1.1 初始化栈


top指针:
由于数组的下标是从0开始,所以我们初始化"栈"时,可以将top指针(栈顶指针)初始化为-1,这样即可代表"栈"中无数据.

capacaity :
同顺序表一样,我们可以设置初始最大容量,后续不够可以扩容.

void InitST(ST* ps)
{
	assert(ps);
	ps->top = -1;//此时栈中无数据
	ps->capacaity = 4;//设置初始最大容量
	ps->data = (stacktype*)malloc(ps->capacaity * sizeof(stacktype));

}

此处初始化后:
在这里插入图片描述

1.2 入栈(压栈,向"栈"中插入数据)

学到这里(顺序表和链表),对于"栈"的压栈操作很简单.

  1. 由于是顺序表实现,所以在进行插入操作之前要先进行"判满"操作,如果栈满了,要进行扩容.
  2. top是指向栈顶下标,需要将其往后移动一位,使其指向待插入位置.
  3. 将新元素插入.此时刚好top为新的栈顶的下标.

图解:
在这里插入图片描述

代码:

void STPush(ST* ps, stacktype x)//压栈
{
	assert(ps);
	if (ps->top+1 == ps->capacaity)//检查"栈"满
	{
		ps->capacaity *= 2;//扩容
		ST* tmp = (stacktype*)realloc(ps->data, ps->capacaity * sizeof(stacktype));
		if(tmp == NULL)
		{
			printf("增容失败\n");
		}
		ps->data = tmp;
	}
	//将"栈顶指针"指向待插入位置
	ps->top++;
	//将元素压栈
	ps->data[ps->top] = x;
	
}

1.3 “出栈”,删除"栈"中的数据

步骤:

  1. 删除数据时,需要判断"栈"是否为空.
  2. 将top向前(下)移动一位,即表示有效数据位减1.

代码:

void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	ps->top--;
}

1.4 判空(判断"栈"是否为空)

当栈为空时,top为初始状态-1.

bool STEmpty(ST* ps)//判断是否为空栈,是空返回真
{
	assert(ps);
	if (ps->top == -1)
	{
		return true;
	}
	return false;
}

1.5 打印"栈顶"元素

void PrintSTTop(ST* ps)
{
	assert(ps);
	printf("%d", ps->data[ps->top]);
}

1.6 返回"栈顶"元素

stacktype STTop(ST* ps)//返回栈顶元素
{
	assert(ps);
	return ps->data[ps->top];
}

1.7 "栈"的销毁

栈的销毁操作,因为malloc开辟出来的是连续的空间,所以只需要释放一次即可.

void STDestory(ST* ps)
{
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->top = -1;
	ps->capacaity = 0;
}

二、链栈

"链栈"的类型定义

typedef int stacktype;
// 链栈的类型
typedef struct SLStackNode
{
    stacktype data;
    struct SLStackNode* next;
}SLStackNode;

其实我们不难发现,"链栈"的类型与单链表很相似,通过对"栈"的基本知识了解,"栈"只在一端进行"插入"和"删除"操作,为了用单链表实现这一要求.

同时为了提高效率:

链表分析
尾插,尾删效率低,因为需要找尾巴
头插,头插效率高,只需要改变头指针的指向


综上:我们利用不带头单链表的"头插(入栈)和头删(出栈)"来完成栈的各项基本操作.并且"栈"不需要进行随机访问其中的元素,只能从栈顶访问,链表是可以完成的.

2.1 初始化"链栈"

对于链表实现的栈,如果不带头结点:
我们不需要特意去写一个初始化函数.只需要创建一个栈顶指针,将其初始化指向NULL即可.(下面的代码是采用这种形式)

//创建一个栈顶指针,并完成初始化
SLStackNode* SLStack = NULL;

如果是带头结点的单链表:
我们可以定义一个初始化函数,申请一个头结点(头结点的数据域不存数据),将头结点返回.

//stack.c
SLStackNode* InitStack()
{
	SLStackNode* newnode = (SLStackNode*)malloc(sizeof(SLStackNode));
	if (newnode == NULL)
	{
		perror("newnode malloc fail");
	}
	return newnode;
}

//test.c
SLStackNode* SLStack = InitStack();

2.2 入栈(压栈,向"栈"中插入数据)

步骤:(与单链表的头插类似)

  1. 创建一个新节点.
  2. 将新节点的next指针指向原"栈"的顶点
  3. 更新栈顶指针(将栈顶指针指向新节点)

图解:
在这里插入图片描述

代码:

//入栈
void STPush(SLStackNode** pps, stacktype x)//压栈.相当于链表的头插
{
	assert(pps);
	//获取新的结点
	SLStackNode* newnode = BuyNode(x);
	newnode->next = *pps;//将新节点的next指针指向原"栈"的顶点
	*pps = newnode;//更新栈顶
}

2.3 “出栈”,删除"栈"中的数据

步骤:(与链表的头删操作类似)

  1. 判空,防止空链栈的删除操作
  2. 记录原栈顶元素的地址.
  3. 更新栈顶.(将栈顶指针指向原栈顶的下一个结点↓).
  4. 释放原栈顶空间

图解:
在这里插入图片描述

void STPop(SLStackNode** pps)//出栈
{
	assert(pps);//二级指针不可能为空,如果为空就一定是传错了
	assert(*pps);//防止空链栈的删除操作
	SLStackNode* head = *pps;//记录栈顶元素的地址
	*pps = (*pps)->next;//更新栈顶,即原来栈顶的下一个结点
	free(head);//释放原栈顶空间
}

2.4 判空(判断"栈"是否为空)

链栈(不带头版本的)的初始状态是栈顶指针指向NULL.

bool STEmpty(SLStackNode* ps)//判断是否为空栈
{
	if (ps == NULL)
	{
		return true;
	}
	else
		return false;
}

2.5 打印"栈顶"元素

栈顶元素即,栈顶指针指向的结点的数据域.

void PrintSTTop(SLStackNode* ps)//打印栈顶元素
{
	assert(ps);
	printf("%d ", ps->data);
}

2.6 返回"栈顶"元素

stacktype STTop(SLStackNode* ps)//返回栈顶元素
{
	assert(ps);
	return ps->data;
}

2.7 返回"链栈"的长度(有效数据的个数)

遍历这个栈即可求出栈的长度.(但其实一般情况下,栈是不允许遍历的,栈顶元素不出去,我们原则上不能访问栈顶下面的元素).

代码:

int LengthStack(SLStackNode* ps)
{
	int count = 0;
	if (ps == NULL)//如果栈顶指针指向NULL,表示栈中没有元素
	{
		return 0;
	}
	SLStackNode* tail = ps;//代替头指针遍历
	while (ps)
	{
		count++;//如果该结点不为空,则有效数据个数+1
		ps = ps->next;
	}
	return count;//返回有效数据的个数
}

2.8 "链栈"的销毁

与"链表"销毁类似.

void STDestory(SLStackNode* ps)//栈的销毁
{
	SLStackNode* del = ps;
	SLStackNode* next = ps;//用于记录下一个结点
	while (next)
	{
		next = next->next;
		free(del);
		del = next;

	}
	//保持习惯置空
	next == NULL;
	del = NULL;
}

总结:

虽然链表和顺序表可以实现"栈",并且效率上,二者差距不大.

但是如果了解过寄存器的小伙伴,应该知道,如果数据在物理上是连续存储的,更加有利于数据的读取.

寄存器:

寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。

因为cpu不是直接从硬盘读取数据的(嫌弃硬盘太慢了),而是通过寄存器(访问速度很快).

数据先被加载到缓存,此时如果数据在物理上是连续存储的,则在加载数据到缓存时,刚好将后面要读的数据也读走了,这样再读下一个数据时,就不需要再去硬盘读了.

🌰栗子:
在这里插入图片描述
在这里插入图片描述

综上,还是稍微建议使用顺序栈有一点点优势.

希望这篇文章对大家有帮助。欢迎小伙伴们私信提意见和提问哦!
最后,小伙伴们的点赞就是给牛牛最大的支持,能不能给牛牛来一个一键三连呢?谢谢支持。
在这里插入图片描述

总代码

"顺序栈"总代码

声明区(stack.h)

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
typedef  int stacktype;
typedef struct stack
{
	stacktype* data;
	int top;
	int capacaity;
}ST;
void InitST(ST* ps);
void STPush(ST* ps, stacktype x);//压栈
void STPop(ST* ps);//出栈
void PrintSTTop(ST* ps);//打印栈顶元素

bool STEmpty(ST* ps);//判断是否为空栈
stacktype STTop(ST* ps);//返回栈顶元素
void STDestory(ST* ps);//栈的销毁

接口实现区( stack.c)

#include "stack.h"
//初始化栈
void InitST(ST* ps)
{
	assert(ps);
	ps->top = -1;
	ps->capacaity = 4;
	ps->data = (stacktype*)malloc(ps->capacaity * sizeof(stacktype));

}

//压栈
void STPush(ST* ps, stacktype x)
{
	assert(ps);
	if (ps->top+1 == ps->capacaity)
	{
		ps->capacaity *= 2;
		ST* tmp = (stacktype*)realloc(ps->data, ps->capacaity * sizeof(stacktype));
		if(tmp == NULL)
		{
			printf("增容失败\n");
		}
		ps->data = tmp;
	}
	ps->top++;
	ps->data[ps->top] = x;
	
}

//出栈
void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	ps->top--;
}

//打印栈顶元素
void PrintSTTop(ST* ps)
{
	assert(ps);
	printf("%d", ps->data[ps->top]);
}

//判断是否为空栈,是空返回真
bool STEmpty(ST* ps)
{
	assert(ps);
	if (ps->top == -1)//如果"栈"为空,则栈顶的下标为-1;
	{
		return true;
	}
	return false;
}

//返回栈顶元素
stacktype STTop(ST* ps)
{
	assert(ps);
	return ps->data[ps->top];//反追栈顶元素
}

//栈的销毁
void STDestory(ST* ps)
{
	assert(ps);
	free(ps->data);//释放栈空间
	ps->data = NULL;
	ps->top = -1;
	ps->capacaity = 0;
}

测试区(test.c)

#include "stack.h"
void test1()
{
	ST st1;
	InitST(&st1);
	STPush(&st1, 1);//压栈
	STPush(&st1, 2);//压栈
	STPush(&st1, 3);//压栈
	STPush(&st1, 4);//压栈
	int a=STTop(&st1);
	printf("栈顶元素为%d\n", a);
	while (!STEmpty(&st1))
	{
		PrintSTTop(&st1);//打印栈顶元素
		STPop(&st1);
	}

	STDestory(&st1);
	
}
int main()
{
	test1();
	return 0;
}

"链栈"总代码:

声明区(SLStack.h)

#pragma once

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

typedef int stacktype;
// 链栈的类型
typedef struct SLStackNode
{
    stacktype data;
    struct SLStackNode* next;
}SLStackNode;


//SLStackNode* InitStack();

void STPush(SLStackNode** pps, stacktype x);//压栈
void STPop(SLStackNode** pps);//出栈
void PrintSTTop(SLStackNode* ps);//打印栈顶元素

bool STEmpty(SLStackNode* ps);//判断是否为空栈
stacktype STTop(SLStackNode* ps);//返回栈顶元素

int LengthStack(SLStackNode* ps);//返回栈的长度

void STDestory(SLStackNode* ps);//栈的销毁

接口实现区(SLStack.c)

#include "SLStack.h"

//SLStackNode* InitStack()
//{
//	SLStackNode* newnode = (SLStackNode*)malloc(sizeof(SLStackNode));
//	if (newnode == NULL)
//	{
//		perror("newnode malloc fail");
//	}
//	return newnode;
//}

SLStackNode* BuyNode(stacktype x)//创建新结点
{
	SLStackNode* newnode = (SLStackNode*)malloc(sizeof(SLStackNode));
	assert(newnode);//防止申请结点失败
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}


//入栈
void STPush(SLStackNode** pps, stacktype x)//压栈.相当于链表的头插
{
	assert(pps);
	//获取新的结点
	SLStackNode* newnode = BuyNode(x);
	newnode->next = *pps;
	*pps = newnode;
}

void STPop(SLStackNode** pps)//出栈
{
	assert(pps);//二级指针不可能为空,如果为空就一定是传错了
	assert(*pps);//防止空链栈的删除操作
	SLStackNode* head = *pps;//记录栈顶元素的地址
	*pps = (*pps)->next;//将栈顶向下移动一位
	free(head);//释放栈顶空间
}

void PrintSTTop(SLStackNode* ps)//打印栈顶元素
{
	assert(ps);
	printf("%d ", ps->data);
}

bool STEmpty(SLStackNode* ps)//判断是否为空栈
{
	if (ps == NULL)
	{
		return true;
	}
	else
		return false;
}

stacktype STTop(SLStackNode* ps)//返回栈顶元素
{
	assert(ps);
	return ps->data;
}

int LengthStack(SLStackNode* ps)
{
	int count = 0;
	if (ps == NULL)
	{
		return 0;
	}
	SLStackNode* tail = ps;
	while (ps)
	{
		count++;
		ps = ps->next;
	}
	return count;
}

void STDestory(SLStackNode* ps)//栈的销毁
{
	SLStackNode* del = ps;
	SLStackNode* next = ps;//用于记录下一个结点
	while (next)
	{
		next = next->next;
		free(del);
		del = next;

	}
	//保持习惯置空
	next == NULL;
	del = NULL;
}

测试区(test.c)

#include "SLStack.h"

void test1()
{
	SLStackNode* SLStack = NULL;
	//SLStackNode* SLStack = InitStack();

	STPush(&SLStack, 1);//压栈
	STPush(&SLStack, 2);//压栈
	STPush(&SLStack, 3);//压栈
	STPush(&SLStack, 4);//压栈
	STPush(&SLStack, 5);//压栈
	STPush(&SLStack, -1);//压栈
	STPush(&SLStack, -2);//压栈
	int a = STTop(SLStack);
	printf("栈顶元素为%d\n", a);

	int length = LengthStack(SLStack);
	printf("链表的长度为:%d\n", length);

	while (!STEmpty(SLStack))
	{
		PrintSTTop(SLStack);//打印栈顶元素
		STPop(&SLStack);
	}
	
	STDestory(SLStack);

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

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

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

相关文章

区间预测 | MATLAB实现QRCNN-BiGRU卷积双向门控循环单元分位数回归时间序列区间预测

区间预测 | MATLAB实现QRCNN-BiGRU卷积双向门控循环单元分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRCNN-BiGRU卷积双向门控循环单元分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 1.Matlab实现基于QRCNN-BiGRU分位数回…

MySQL视图与联集

一、VIEW&#xff08;视图&#xff09; 1、 概念 可以被当作是虚拟表或存储查询 视图跟表格的不同是&#xff0c;表格中有实际储存资料&#xff0c;而视图是建立在表格之上的一个架构&#xff0c;它本身并不实际储存资料。 临时表在用户退出或同数据库的连接断开后就自动消…

DIY技巧:微星B760主板13600K降压教程 CPU温度暴降25℃

前段时间微星B600/700系主板更新了最新的BIOS&#xff0c;最新的BIOS更新&#xff1b;额105微码&#xff0c;让用户能直接在BIOS中对13代带K处理器进行降压&#xff0c;十分方便&#xff0c;今就带大家体验一下微星B760迫击炮主板的降压流程&#xff0c;其他微星B600/700系主板…

43岁,年薪200万的高管,被裁了!这4条职场潜规则,你越早知道越好

作者| Mr.K 编辑| Emma 来源| 技术领导力(ID&#xff1a;jishulingdaoli) 我的一位老朋友S总&#xff0c;是某世界500强外企中国区运营总监&#xff0c;光年薪就200万&#xff0c;还不包括福利、股票的部分&#xff0c;他比我略长一两岁&#xff0c;我们人生经历相似&#xf…

一文搞懂Go错误链

0. Go错误处理简要回顾 Go是一种非常强调错误处理的编程语言。在Go中&#xff0c;错误被表示为实现了error接口的类型的值&#xff0c;error接口只有一个方法&#xff1a; type error interface {Error() string } 这个接口的引入使得Go程序可以以一致和符合惯用法的方式进行错…

Python实现哈里斯鹰优化算法(HHO)优化LightGBM回归模型(LGBMRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 2019年Heidari等人提出哈里斯鹰优化算法(Harris Hawk Optimization, HHO)&#xff0c;该算法有较强的全…

有主题的图文内容创作 | AIGC实践

话说&#xff0c;昨天我发布了第一篇&#xff0c;内容由ChatGPT和Midjourney协助完成的文章&#xff1a;胡同与侏罗纪公园的时空交错 | 胡同幻想 在这篇文章中&#xff0c;大约70%图文内容由ChatGPT和Midjourney输出。我个人参与的部分&#xff0c;主要是提出指令&#xff08;P…

Monaco Editor编辑器教程(三一):在编辑器中实现模拟调试的交互

前言 最近有小伙伴咨询如何在编辑中实现 像vscode调试代码那样,可以打断点,可以高亮当前运行的一行。这样的需求并不多见,如果要做,那肯定是对编辑器做一个深层次的定制。一般很少很少会实现这种在浏览器中调试。 目前我还没见过,如果有遇到过的朋友可以指点一下。我去学…

Cesium AI GPT 文档 源码 ChatGPT问答

我用Cesium104.0的 源码 | 文档 | 3DTiles标准 作为上下文语料定制了一个智能Cesium专家问答助手 语料: 3D Tiles Specificationhttps://cesium.com/downloads/cesiumjs/releases/1.104/Build/CesiumUnminified/Cesium.jshttps://github1s.com/CesiumGS/cesium/blob/HEAD/Doc…

redis中的管道

Redis 管道 文章目录 1. 前言2. Redis 管道3. 小总结 1. 前言 通过一个问题引出 我们接下来要学习的 Redis 管道 : 提问 : 如何优化频繁命令往返造成的性能瓶颈 ? 另外 &#xff1a; 关于上面这个问题的由来 也可以简单的说一说 上面所说的思路 其实就是管道的概念 &#xff0…

读俞敏洪的书

没有认真写过一篇关于书籍的读后感文章&#xff0c;但在读完俞敏洪老师这本书后&#xff0c;想推荐给大家&#xff0c;也想分享下我的想法。 几周前&#xff0c;我在微信读书首页看到了俞敏洪老师的读书推荐 《在绝望中寻找希望》——俞敏洪写给迷茫不安的年轻人 有好几个晚上&…

电池只能充电500次?别太荒谬!收下这份真正的充电秘籍

我们的生活已经离不开电子设备了&#xff0c;而电子设备嘛&#xff0c;又离不开给它们提供能源的电池。在网上有许许多多的“延长电池寿命小技巧”&#xff0c;比如“新买的电子设备&#xff0c;第一次充电之前要把电都放完”“笔记本电脑一直插着电源可以保护电池”“长期不用…

区分COCO数据集的coco minival和coco test-dev、conda常用命令和python -m 的作用

1、COCO数据集的测试集coco minival和coco test-dev: 两个数据集在官方网站对应的内容如下所示&#xff1a; COCO数据集官网&#xff1a;https://cocodataset.org/#download 两个数据集的区分参考网址&#xff1a;https://zhuanlan.zhihu.com/p/533676547 2、conda常用命令…

linux中epoll+socket实战

目录 参考前言案例 一、epoll的基本使用首先是epoll_create函数&#xff1a;然后是epoll_ctl函数&#xff1a;最后是epoll_wait函数&#xff1a;关于ET&#xff08;边沿触发&#xff09;、LT&#xff08;水平触发&#xff09;两种工作模式可以得出这样的结论: 二、使用代码简易…

基于html+css的图展示71

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

某音X-Bogus算法研究 2023-05-15

本文以教学为基准&#xff0c;研究JavaScript算法及反爬策略、本文提供的可操作性不得用于任何商业用途和违法违规场景。 如有侵权&#xff0c;请联系我进行删除。 今天我们分析一下douyin个人主页数据获取。 大多数小伙伴应该都知道想要拿到douyin的数据也不是那么容易的&a…

近世代数 笔记与题型连载 第十三章(环与域)

文章目录 基本概念1.环1.1.环的定义1.2.环的性质1.3.几种特殊的环1.4.子环 2.域2.1.域的定义2.2.环与域的同态 相关题型1.验证一个代数系统是否是一个环2.判断一个代数系统是否是整环3.判断一个代数系统是否是另一个代数系统的子环4.判断一个代数系统是否是域 基本概念 1.环 …

sed编辑器命令

sed编辑器 sed是一种流编辑器&#xff0c;流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。 sed编辑器可以根据命令来处理数据流中的数据&#xff0c;这些命令要么从命令行中输入&#xff0c;要么存储在一个命令文本文件中。 sed 的工作流程主要包括读取…

Nat. Commun | 中国海洋大学张伟鹏组揭示海洋生物被膜群落硫氧化主要菌群及其作用机制...

海洋生物被膜玫瑰杆菌的厌氧硫氧化机制 Anaerobic thiosulfate oxidation by the Roseobacter group is prevalent in marine biofilms Article&#xff0c;2022-04-11&#xff0c;Nature Communications&#xff0c;[IF 17.7] DOI&#xff1a;10.1038/s41467-023-37759-4 原文…

Apache Hive函数高阶应用、性能调优

Hive的函数高阶应用 explode函数 explode属于UDTF函数&#xff0c;表生成函数&#xff0c;输入一行数据输出多行数据。 功能&#xff1a; explode() takes in an array (or a map) as an input and outputs the elements of the array (map) as separate rows.--explode接收…