数据结构——顺序栈与链式栈的实现

news2024/11/24 19:56:38

目录

一、概念

1、栈的定义

2、栈顶

3、栈底

二、接口

1、可写接口

1)数据入栈

2)数据出栈

3)清空栈

2、只读接口

1)获取栈顶数据

2)获取栈元素个数

3)栈的判空

三、栈的基本运算

四、顺序栈(Sequential Stack)实现

1、数据结构定义

2、创建栈

3、清空栈

4、判断栈是否为空

5、判断栈是否饱和

6、入栈

7、出栈

8、取栈顶元素

9、释放malloc申请的内存

打印栈中所有元素示例

五、栈的链表实现

1、数据结构定义

2、创建栈

3、清空栈

4、判断栈是否为空

5、入栈

6、出栈

7、取栈顶元素

8、释放malloc申请的内存

打印栈中所有元素示例

六、两种实现的优缺点

1、顺序表实现

2、链表实现


一、概念

1、栈的定义

   是仅限在 表尾 进行 插入 和 删除 的 线性表
   又被称为 后进先出 (Last In First Out) 的线性表,简称 LIFO 。

2、栈顶

   是一个线性表,我们把允许 插入 和 删除 的一端称为 栈顶

3、栈底

  和 栈顶 相对,另一端称为 栈底,实际上,栈底的元素我们不需要关心。

二、接口

1、可写接口

1)数据入栈

  栈的插入操作,叫做 入栈,也可称为 进栈、压栈。如下图所示,代表了三次入栈操作:

2)数据出栈

  栈的删除操作,叫做 出栈,也可称为 弹栈。如下图所示,代表了两次出栈操作:
在这里插入图片描述

3)清空栈

  一直 出栈,直到栈为空,如下图所示:

2、只读接口

1)获取栈顶数据

  对于一个栈来说只能获取 栈顶 数据,一般不支持获取 其它数据。

2)获取栈元素个数

  栈元素个数一般用一个额外变量存储,入栈 时加一,出栈 时减一。这样获取栈元素的时候就不需要遍历整个栈。通过 �(1)O(1) 的时间复杂度获取栈元素个数。

3)栈的判空

  当栈元素个数为零时,就是一个空栈,空栈不允许 出栈 操作。

三、栈的基本运算

创建空栈 : CreateStack (len)

清空栈 : ClearStack (S)

判断是否栈空 : EmptyStack (S)

判断是否栈满 : FullStack (S)

元素进栈 : PushStack (S,x)

元素出栈 : PopStack (S)

取栈顶元素 : GetTop (S)

四、顺序栈(Sequential Stack)实现

1、数据结构定义

对于顺序表,在 C语言 中表现为 数组,在进行 栈的定义 之前,我们需要考虑以下几个点:
  1)栈数据的存储方式,以及栈数据的数据类型;
  2)栈的大小;
  3)栈顶指针;

  • 我们可以定义一个  的 结构体,C语言实现如下所示:
typedef int datatype;
typedef struct node{     /*定义栈中数据元素的数据类型*/
	datatype *data;      /*用指针指向栈的存储空间*/
	int maxlen;          /*当前栈的最大元素个数*/
	int top;             /*指示栈顶位置(数组下标)的变量*/
}sqstack;                /*顺序栈类型定义*/

2、创建栈

C语言实现如下所示:

sqstack* stack_create(int len)
{
	sqstack *s;

	if((s=(sqstack *)malloc(sizeof(sqstack)))==NULL)
	{
		puts("malloc failed");
		return NULL;
	}
	if((s->data=(datatype *)malloc(len*sizeof(datatype)))==NULL)
		
	{
		puts("malloc failed");
		return NULL;
	}
	s->maxlen=len;
	s->top=-1;

	return s;
}

3、清空栈

C语言实现如下所示:

void stack_clear(sqstack* s)
{
	s->top = -1;
}

4、判断栈是否为空

C语言实现如下所示:

int stack_empty(sqstack* s)
{
	return (s->top==-1 ? 1:0);
}

5、判断栈是否饱和

C语言实现如下所示:

int stack_full(sqstack* s)
{
	return (s->top==(s->maxlen-1) ? 1:0);
}

6、入栈

C语言实现如下所示:

int stack_push(sqstack* s,datatype value)
{
	if(s->top==s->maxlen-1){
		puts("stack is full");
		return -1;
	}

	s->data[s->top+1]=value;
	s->top++;

	return 1;
}

7、出栈

C语言实现如下所示:

datatype stack_pop(sqstack* s)
{
	s->top--;
	return s->data[s->top+1];
}

8、取栈顶元素

C语言实现如下所示:

datatype stack_top(sqstack* s)
{
	return(s->data[s->top]);
}

9、释放malloc申请的内存

C语言实现如下所示:

void stack_free(sqstack *s)
{
	free(s->data);
	s->data=NULL;

	free(s);
	s=NULL;
}

打印栈中所有元素示例

C语言实现如下所示:

sqstack.h

#ifndef __LINKLIST_H__
#define __LINKLIST_H__

#include <stdio.h>
#include <stdlib.h>
typedef int datatype;

typedef struct node{
	datatype *data;
	int maxlen;
	int top;
}sqstack;

extern sqstack* stack_create(int len);
extern int stack_empty(sqstack* s);
extern int stack_full(sqstack* s);
extern void stack_clear(sqstack* s);
extern int stack_push(sqstack* s,datatype value);
extern datatype stack_pop(sqstack* s);
extern datatype stack_top(sqstack* s);
extern void stack_free(sqstack *s);

#endif

sqstack.c

#include "sqstack.h"

sqstack* stack_create(int len)
{
	sqstack *s;

	if((s=(sqstack *)malloc(sizeof(sqstack)))==NULL)
	{
		puts("malloc failed");
		return NULL;
	}
	if((s->data=(datatype *)malloc(len*sizeof(datatype)))==NULL)
		
	{
		puts("malloc failed");
		return NULL;
	}
	s->maxlen=len;
	s->top=-1;

	return s;
}

int stack_empty(sqstack* s)
{
	return (s->top==-1 ? 1:0);
}
int stack_full(sqstack* s)
{
	return (s->top==(s->maxlen-1) ? 1:0);
}
void stack_clear(sqstack* s)
{
	s->top = -1;
}
int stack_push(sqstack* s,datatype value)
{
	if(s->top==s->maxlen-1){
		puts("stack is full");
		return -1;
	}

	s->data[s->top+1]=value;
	s->top++;

	return 1;
}
datatype stack_pop(sqstack* s)
{
	s->top--;
	return s->data[s->top+1];
}
datatype stack_top(sqstack* s)
{
	return(s->data[s->top]);
}
void stack_free(sqstack *s)
{
	free(s->data);
	s->data=NULL;

	free(s);
	s=NULL;
}

test.c

#include "sqstack.h"

int main(int argc, const char *argv[])
{
	sqstack *s;
	int n=5;

	s=stack_create(n);

	stack_push(s,10);
	stack_push(s,20);
	stack_push(s,30);
	stack_push(s,40);
	stack_push(s,50);
	stack_push(s,60);
	
	while(!stack_empty(s))
	{
		printf("%d ",stack_pop(s));
	}
	putchar(10);

	stack_clear(s);
	stack_free(s);

	return 0;
}

Makefile

CC = gcc
CFLAGS =  -g -Wall

test:test.o sqstack.o
	$(CC) $(CFLAGS) -o $@ $^

.PHONY:clean
clean:
	rm  test *.o

-g : 产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项

-Wall : 表示允许发出gcc所有有用的报警信息

-c : 只是编译不链接,生成目标文件".o"

-o test : 表示把输出文件输出到file里

运行结果:

五、栈的链表实现

1、数据结构定义

对于链表,在进行 栈的定义 之前,我们需要考虑以下几个点:
  1)栈数据的存储方式,以及栈数据的数据类型;
  2)栈的大小;
  3)栈顶指针;

我们可以定义一个  的 结构体,C语言实现如下所示:

typedef int datatype;

typedef struct node{
	datatype data;
	struct node* next;
}listnode,*linklist;

2、创建栈

C语言实现如下所示:

linklist stack_create()
{
	linklist s;

	if((s=(linklist)malloc(sizeof(listnode)))==NULL){
		puts("malloc failed");
		return NULL;
	}
	s->next=NULL;

	return s;
}

3、清空栈

C语言实现如下所示:

void stack_clear(linklist s)
{
	linklist p;

	printf("clear:");
	p=s->next;
	while(p)
	{
		s->next=p->next;
		printf("%d ",p->data);
		free(p);
		p=s->next;
	}
	putchar(10);
}

4、判断栈是否为空

C语言实现如下所示:

int stack_empty(linklist s)
{
	return (s->next==NULL ? 1:0);
}

5、入栈

C语言实现如下所示:

int stack_push(linklist s,datatype value)
{
	linklist p;
	if((p=(linklist)malloc(sizeof(listnode)))==NULL)
	{
		puts("malloc failed");
		return -1;
	}

	p->data = value;
	p->next=s->next;
	s->next = p;

	return 0;
}

6、出栈

C语言实现如下所示:

datatype stack_pop(linklist s)
{
	linklist p;
	datatype ret;

	p=s->next;
	s->next=p->next;
	ret=p->data;

	free(p);
	p=NULL;

	return ret;
}

7、取栈顶元素

C语言实现如下所示:

datatype stack_top(linklist s)
{
	return (s->next->data);
}

8、释放malloc申请的内存

C语言实现如下所示:

void stack_free(linklist s)
{
	linklist p;

	printf("free:");
	p=s;
	while(p)
	{
		s=s->next;
		printf("%d ",p->data);
		free(p);
		p=s;
	}
	putchar(10);

}

打印栈中所有元素示例

C语言实现如下所示:

linkstack.h        

#ifndef __LINKLIST_H__
#define __LINKLIST_H__

#include <stdio.h>
#include <stdlib.h>
typedef int datatype;

typedef struct node{
	datatype data;
	struct node* next;
}listnode,*linklist;

extern linklist stack_create();
extern int stack_empty(linklist s);
extern void stack_clear(linklist s);
extern int stack_push(linklist s,datatype value);
extern datatype stack_pop(linklist s);
extern datatype stack_top(linklist s);
extern void stack_free(linklist s);

#endif

linkstack.c

#include "linkstack.h"

linklist stack_create()
{
	linklist s;

	if((s=(linklist)malloc(sizeof(listnode)))==NULL){
		puts("malloc failed");
		return NULL;
	}
	s->next=NULL;

	return s;
}
int stack_empty(linklist s)
{
	return (s->next==NULL ? 1:0);
}


int stack_push(linklist s,datatype value)
{
	linklist p;
	if((p=(linklist)malloc(sizeof(listnode)))==NULL)
	{
		puts("malloc failed");
		return -1;
	}

	p->data = value;
	p->next=s->next;
	s->next = p;

	return 0;
}

datatype stack_pop(linklist s)
{
	linklist p;
	datatype ret;

	p=s->next;
	s->next=p->next;
	ret=p->data;

	free(p);
	p=NULL;

	return ret;
}

datatype stack_top(linklist s)
{
	return (s->next->data);
}

void stack_clear(linklist s)
{
	linklist p;

	printf("clear:");
	p=s->next;
	while(p)
	{
		s->next=p->next;
		printf("%d ",p->data);
		free(p);
		p=s->next;
	}
	putchar(10);
}
void stack_free(linklist s)
{
	linklist p;

	printf("free:");
	p=s;
	while(p)
	{
		s=s->next;
		printf("%d ",p->data);
		free(p);
		p=s;
	}
	putchar(10);

}

test.c

#include "linkstack.h"

int main(int argc, const char *argv[])
{
	linklist s;
	
	s=stack_create();

	stack_push(s,10);
	stack_push(s,20);
	stack_push(s,30);
	stack_push(s,40);
	stack_push(s,50);
	stack_push(s,60);
	
#if 0
	while(!stack_empty(s))
	{
		printf("%d ",stack_pop(s));
	}
	putchar(10);
#endif
//	stack_clear(s);
	stack_free(s);
	return 0;
}

Makefile

CC = gcc
CFLAGS =  -g -Wall

test:test.o linkstack.o
	$(CC) $(CFLAGS) -o $@ $^

.PHONY:clean
clean:
	rm  test *.o

运行结果:

六、两种实现的优缺点

1、顺序表实现

  在利用顺序表实现栈时,入栈 和 出栈 的常数时间复杂度低,且 清空栈 操作相比 链表实现 能做到 O(1),唯一的不足之处是:需要预先申请好空间,而且当空间不够时,需要进行扩容,扩容方式本文未提及,可以参考大佬文章:《C/C++ 面试 100 例》(四)vector 扩容策略。

2、链表实现

  在利用链表实现栈时,入栈 和 出栈 的常数时间复杂度略高,主要是每插入一个栈元素都需要申请空间,每删除一个栈元素都需要释放空间,且 清空栈 操作是 O(n) 的,直接将 栈顶指针 置空会导致内存泄漏。好处就是:不需要预先分配空间,且在内存允许范围内,可以一直 入栈,没有顺序表的限制。

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

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

相关文章

【CISSP学习笔记】5. 安全架构和工程

该知识领域涉及如下考点&#xff0c;具体内容分布于如下各个子章节&#xff1a; 使用安全设计原理来研究、实施与管理工程过程理解安全模型的基本概念&#xff08;例如 Biba、Star Model、Bell-LaPadula 等模型&#xff09;基于系统安全要求选择控制措施理解信息系统 (IS) 的安…

智能对话意图分析服务接口

机器人聊天&#xff0c;智能助手&#xff0c;内容生成&#xff0c;智能办公&#xff0c;智能辅助&#xff0c;智能搜索 一、接口介绍 通过接收用户提出的问题、输入的图片和文档等需求&#xff0c;准确识别其对话意图&#xff0c;并触发相应的回复。同时&#xff0c;整合了AP…

ansible管理windows测试

一、环境介绍 Ansible管理主机&#xff1a; 系统: redhat7.6 Linux管理服务器需安装pywinrm插件 Windows客户端主机&#xff1a; 系统: Server2012R2 Windows机器需要安装或升级powershell4.0以上版本&#xff0c;Server2008R2默认的版本是2.0&#xff0c;因此必须升…

m1芯片电脑上的paragon15如何安装激活 m1芯片电脑上ntfs for mac如何安装

Paragon NTFS软件在M1芯片电脑上安装之后&#xff0c;最后一步会让我们“允许加载第三方内核扩展”&#xff0c;具体如下图所示。 图1&#xff1a;允许加载第三方内核扩展 按照图中提示“单击此处“&#xff0c;然后打开安全与隐私。接下来依次点击小锁标志进行解锁&#xff0c…

【零基础入门TypeScript】TypeScript - 概述

目录 什么是 TypeScript&#xff1f; TypeScript 的特点 TypeScript 和 ECMAScript 为什么使用 TypeScript&#xff1f; TypeScript 的组件 声明文件 JavaScript 是作为客户端语言引入的。Node.js 的发展也标志着 JavaScript 成为一种新兴的服务器端技术。然而&#xff0…

云原生十二问

一、什么是云原生&#xff1f; 云原生是在云计算环境中构建、部署和管理现代应用程序的软件方法。现代企业希望构建高度可扩展、灵活且具有弹性的应用程序&#xff0c;可以快速更新以满足客户需求。为此&#xff0c;他们使用现代工具和技术&#xff0c;这些工具和技术本质上支…

python 深度学习 记录遇到的报错问题11

本篇继python 深度学习 记录遇到的报错问题10-CSDN博客 六、ValueError: cannot convert float NaN to integer 报错&#xff1a; 原因&#xff1a;这个错误通常是因为在尝试将NaN值转换为整数时发生的。NaN表示“非数字”&#xff0c;它无法转换为整数。在 Python 中&#xf…

2023年度回顾:怿星科技的转型与创新

岁月不居&#xff0c;时节如流。随着2023年的落幕&#xff0c;怿星科技在这一年中不仅实现了自身的转型&#xff0c;还在技术创新、产品研发、行业合作和人才培养等方面取得了显著的成就。这一年&#xff0c;怿星科技正式完成了从服务型公司向产品型公司的战略转变&#xff0c;…

媒体捕捉-拍照

引言 在项目开发中&#xff0c;从媒体库中选择图片或使用相机拍摄图片是一个极为普遍的需求。通常&#xff0c;我们使用UIImagePickerController来实现单张图片选择或启动相机拍照。整个拍照过程由UIImagePickerController内部实现&#xff0c;无需我们关心细节&#xff0c;只…

让你的隧道代理HTTP使用更加顺畅高效

在数字世界的探险中&#xff0c;隧道代理HTTP是我们穿越网络限制的重要工具。但有时候&#xff0c;我们可能会遇到连接不稳定、速度慢等问题。如何让隧道代理HTTP使用更加顺畅高效&#xff1f;下面是一些建议和技巧。 一、选择合适的代理服务器 代理服务器的地理位置、性能和…

C#/.NET/.NET Core推荐学习书籍(23年12月更新)

前言 古人云&#xff1a;“书中自有黄金屋&#xff0c;书中自有颜如玉”&#xff0c;说明了书籍的重要性。作为程序员&#xff0c;我们需要不断学习以提升自己的核心竞争力。以下是一些优秀的C#/.NET/.NET Core相关学习书籍&#xff0c;值得.NET开发者们学习和专研。书籍已分类…

查看证书有效期的命令

后面的证书是我们当时创建证书的路径 cfssl-certinfo -cert /opt/etcd/certs/etcd.pem

服务雪崩简单的介绍

定义 服务雪崩效应是一种因“服务提供者的不可用”&#xff08;原因&#xff09;导致“服务调用者不可用”&#xff08;结果&#xff09;&#xff0c;并将不可用逐渐放大的现象。如下图所示&#xff1a; 上图中, A为服务提供者, B为A的服务调用者, C和D是B的服务调用者. 当A的…

精确率(Precision,P),召回率(Recall,R)以及F1值(F1-score,F1)

狗狗识别系统的例子&#xff1a; 假设我们有两个集合&#xff1a; 实际狗狗的集合&#xff08;实际真正是狗狗的图片&#xff09;&#xff1a;A我们识别为狗狗的集合&#xff08;我们认为是狗狗的图片&#xff09;&#xff1a;B 精确率&#xff08;Precision&#xff0c;P&am…

LeetCode刷题--- 第 N 个泰波那契数

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述动…

【十三】【动态规划】1745. 分割回文串 IV、132. 分割回文串 II、516. 最长回文子序列,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略&#xff0c;它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题&#xff0c;并将每个小问题的解保存起来。这样&#xff0c;当我们需要解决原始问题的时候&#xff0c;我们就可以直接利…

半年没发过文章,这个博主竟然...

目 录 前言这半年去干了什么&#xff1f;考研求职山东电建移动 论文大创课余 未来公务员继续考研就业 结语 前言 第一次写这样的记录性的文章&#xff0c;这篇文章可能不会有太过于华丽的辞藻&#xff0c;但是它将展现我个人的真实经历和内心感受。在过去的时间里&#xff0c;我…

WEB 3D技术 three.js通过光线投射 完成几何体与外界的事件交互

本文 我们来说 光线投射 光线投射技术是用于3维空间场景中的交互事件 我们先编写代码如下 import ./style.css import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";const scene new THRE…

Redis Cluster集群模式学习

Redis Cluster集群模式 Redis哨兵模式&#xff1a;https://blog.csdn.net/liwenyang1992/article/details/133956200 Redis Cluster集群模式示意图&#xff1a; Cluster模式是Redis3.0开始推出采用无中心结构&#xff0c;每个节点保存数据和整个集群状态&#xff0c;每个节点都…

【python】Python 3.11不支持Tix库

Tix库主要用于扩展Tkinter&#xff0c;但是Python 3.11 Tkinter已经不再支持Tix库。Tix模块提供了一些额外的部件和功能&#xff0c;但现在这些功能已经整合到了Tkinter库中。 一、如果在Python 3.11中想要使用Tix库&#xff0c;但发现它不再被内置支持&#xff0c;可以尝试以…