数据结构之数组对栈的实现

简介: 数据结构之数组对栈的实现

1.什么是栈

栈是一种特殊的线性表,其中只允许固定的一端进行插入与删除,进行输出插入删除的那一端我们称为栈顶,与之相反的一端称为栈底。在栈中,元素遵循先进后出的原则即LIFO(last in first out)。

栈因为是一种操作受到限制的线性表:栈的特点是先进后出,类似于堆盘子,先放到地上的盘子最后被取走。栈的操作有两种:入栈和出栈。入栈就是把元素放到栈顶,出栈就是把栈顶元素取出来。我们也可以想象成弹夹,先装的子弹最后射出,后装的先射出。

0b5253ce42ce469190cc6d0cf6c41fff.png

2.栈的基本操作

对于栈,我们对他的操作只有入栈与出栈,就栈里的元素,增加与删除,需要注意的是因为规定的特殊结构

压栈,也称入栈,进栈,(增加元素)


d817baf6972946b7a129f8525d1fe789.png


出栈(删除元素)


47daad3450b045c48caf35cfbc83dad9.png

因为这种特殊的结构,我们会发现在操作时栈底的元素永远也不可能在他的前一个出栈,无论何时出栈还是入栈。

82f3f0737798483dba7d3c73dc39efbd.png


3.栈的实现

栈的实现也是多种多样:

1.数组实现:数组实现优点较为明显,我们可以下标访问每个栈中的元素,且结构简单,空间利用率高,唯一的缺点是当容量不足时我们需要扩容。

2..单链表实现:单链表也可以实现栈这种结构,但需要注意我们在出栈与入栈的时候,是需要知道为节点的前一个元素,而单链表是无法直接访问的,需要遍历时间复杂度为O(n),于是我们在实现时,是利用头节点作为栈顶的,入栈即就是头插的方式可以实现栈的结构,对于入栈与出栈时间复杂度为O(1),不过单链表在访问栈中的元素时时间复杂度还是O(n).

3.双链表实现:最不建议的一种实现方式,因为对于双链表不仅增加了节点里的指针,结构更复杂,空间利用也不高,且也就是双链表的头插方式实现的,相对于前两种实现,没这个必要。

所以今天我们就用优点较为明显的数组来实现栈,我们也会发现栈的实现其实是非常简单的。

1.结构体与函数接口

我们在定义栈的结构体时,发现还是跟顺序表的定义一样,不过表示实际元素大小我们这里用top表示,即我们称为栈顶也是大小,同时给出总容量。

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>
#define DATAtype int 
typedef struct Stack
{
  DATAtype* a;//实现栈的数组
  int top;//记录栈顶
  int capacity;//总空间
}ST;
void Stackinit(ST**p);//初始化栈
void Stackdetroy(ST** p);//销毁栈
void Stackpush(ST** p, DATAtype x);//入栈
void Stackpop(ST** p);//出栈
int Stacksize(ST** p);//栈大小的返回
bool Stackempety(ST** p);//栈判空

2.初始化栈

我们这里初始化栈有 5个元素的大小空间,需要注意的是top的定义,因为在每次入栈之后top++,在进行打印时我们需要给它在减1,实现坐标的对应。top是当前元素的后一个元素的位置坐标,我们将这里定义为负1,打印时刚好打印a[0]元素,在进行迭代。

void Stackinit(ST* p)
{
  (p)->a = (DATAtype*)malloc(sizeof(DATAtype) * 5);
  (p)->capacity = 5;
  (p)->top = -1;//记录栈中数组位置
}

3.销毁栈

直接判空后free,在置为空。实现简单,不做赘述

//销毁栈
void Stackdetroy(ST* p)
{
  assert(p);
  free((p)->a);
  (p)->a = NULL;
  (p)->capacity = 0;
  (p)->top = 0;
}

4.入栈

入栈首先要对容量判断。因此这里还需要实现容量判断并扩容的操作,这里我直接定义一个函数。

入站的具体操作很简单,赋值并加加。

判断容量:

void chckcapacity(ST* p)
{
  //若容量不够,则扩容
  if ((p)->top == (p)->capacity)
  {
    DATAtype*tmp= (DATAtype*)realloc((p)->a,sizeof(DATAtype) * (p)->capacity * 2);
    if (tmp == NULL)
    {
      printf("realloc fail");
      return;
    }
    (p)->a = tmp;
    (p)->capacity = (p)->capacity * 2;
    printf("容量不够,已自动扩容,当前容量:%d\n", (p)->capacity);
  }
}

入栈:

void Stackpush(ST* p, DATAtype x)
{
  //检查容量
  chckcapacity(p);
  (p)->a[(p)->top] = x;
  (p)->top++;
}

5.出栈

操作也是简单,只要让数组访问不到即可,直接减减。

//出栈
void Stackpop(ST*p)
{
  (p)->top--;
  assert((p)->top);
  assert(p);
  //检查是否过量出栈
}

6.返回栈元素数量大小

很简单,返回top即可

//返回大小
int Stacksize(ST* p)
{
  assert(p);
  return (p)->top;
}

7.判空

bool Stackempety(ST* p)
{
  assert(p);
  if ((p)->top == NULL)
  {
    return true;
  }
  else
  {
    return false;
  }
}

8.打印栈

这个操作在定义top时需要注意一下,top是指向当前栈顶的下面那一个元素,在迭代打印时,注意访问是否越界的问题。

oid stackprintf(ST* p)
{
  assert(p);
  while ((p)->top>=0)
  {
    printf("%d->", (p)->a[(p)->top-1]);
    (p)->top--;
  }
}


相关文章
|
2月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
42 1
|
2天前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
112 75
|
2天前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
24 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
2天前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
27 9
|
2天前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
22 7
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
78 5
|
2月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
63 4
|
2月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
2月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
57 0