初阶数据结构 栈

简介: 初阶数据结构 栈

一. 栈的基本介绍


1. 基本概念


栈是一种线性表 是一种特殊的数据结构


栈顶:进行数据插入和删除操作的一端


另一端叫做栈底


压栈:插入数据叫做压栈 压栈的数据在栈顶


出栈: 栈的删除操作叫做出栈 出栈操作也是在栈顶


栈遵循一个原则 叫做后进先出


(比如说子弹的弹夹 其实就是一种设计好的栈结构)


画图表示如下


a643314ab8124872937ee947a185a9a9.png

2. 代码结构 (动态数组实现)


因为数组模式相对于链表模式来说 尾插的操作消耗更好些 cpu缓存命中率也更高一些


此外因为静态的数组不能变更空间大小 所以说我们这里用动态数组的代码来实现一下


typedef int StackType;
struct Stack
{
  StackType* a;  //储存数据的大小
  int Top;       //栈顶
  int Capacity;  //数组容量大小 
};

595711d72c3a4c869e143ec87a5ac434.png


二. 接口函数实现

1. 初始化栈

这个很简单 初始化栈里面的三个值就好

dbd91b1388eb40f4aad9379f9a9b8406.png

代码表示如下


void StackInit(ST* p)
{
  p->a = NULL;
  p->Top = 0;
  p->Capacity = 0;
}


我们这里要注意Top为0的时候我们需要先赋值再++


2. 压栈


这里我们需要考虑一个问题


我们压栈的时候是否空间满了呢?


所以在压栈之前我们先写一个Cheak函数来看看栈空间是否满了


  if (p->Top==p->Capacity)
  {
    int NewCapacity = p->Capacity == 0 ? 4: p->Capacity * 2;
    StackType* Tmp = realloc(p->a,NewCapacity*sizeof(StackType));
    if (Tmp==NULL)
    {
      perror("StackPush realloc");
    }
    else
    {
        //记得要更新容量数据 
        p->Capacity =Newcapacity;
      p->a = Tmp;
    }
  }


之后我们开始写压栈操作


整体代码表示如下


void StackPush(ST* p, StackType x)
{
  assert(p);
  if (p->Top==p->Capacity)
  {
    int NewCapacity = p->Capacity == 0 ? 4: p->Capacity * 2;
    StackType* Tmp = realloc(p->a,NewCapacity*sizeof(StackType));
    if (Tmp==NULL)
    {
      perror("StackPush realloc");
    }
    else
    {
      p->a = Tmp;
    }
  }
  p->a[p->Top] = x;
  p->Top++;
}

3. 出栈


这个很简单 只需要考虑一个问题


是否删除了过多的数据导致错误


代码表示如下


void StackPop(ST* p)
{
  assert(p);
  assert(p->Top > 0);
  p->Top--;
}


我们可以看到 删除两个数据并没有什么问题

bc13afc27e4a49aab8d2e6c8c2aa29cc.png


可是 当我们继续删除数据的时候

0a912c9a97d94bb59bc5cafa88188231.png

这里出现了断言错误


4. 打印数据


栈的打印数据和我们以前学的其他数据的打印不同!!!


打印出一个数据之后必须要进行出栈操作才可以


代码表示如下


void StackPrint(ST* p)
{
  assert(p);
  while (p->Top>0)
  {
    printf("%d  ", p->a[p->Top - 1]);
    StackPop(p);
  }
}


显示效果如下

c4c561bdb5da47b09a740a506d7be73f.png


5. 找到个数


这个很简单 返回Top的


int StackSize(ST* p)
{
    assert(p);
  return p->Top;
}

6. 判断是否为空


这个也很简单 两行代码搞定


bool StackEmpty(ST* p)
{
  assert(p);
  return p->Top==0;
}


7. 摧毁栈


void StackDestroy(ST* p)
{
  assert(p);
  free(p->a);
  p->a == NULL;
  p->Capacity = 0;
  p->Top = 0;
}


释放开辟出的内存空间 之后再指针置空就可以


这个也很简单 这里就不过多介绍了


三. 两道简单的题目


题目一


一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的

顺序是( )。


A 12345ABCDE

B EDCBA54321

C ABCDE12345

D 54321EDCBA


答案是B 遵循后进先出的原则


题目二


若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()

A 1,4,3,2 B 2,3,4,1

C 3,1,4,2 D 3,4,2,1


首先来看A选项


我们先压栈1 再出栈1 压栈 2 3 4 再依次出栈就可以 没问题


B选项


我们先压栈 1 2 出栈2 再压栈3 4 再依次出栈就可以 没有问题


C选项


我们先压栈123 出栈3 之后再出栈1 这个就不对了 要想出栈1 必须先出栈2


所以答案是C


D选项


我们先压栈 1 2 3 再出栈3 然后压栈4 再依次出栈就可以 没有问题


以上就是本篇博客的全部内容啦 由于博主才疏学浅 所以难免会出现纰漏


希望大佬们看到错误之后能够不吝赐教 在评论区或者私信指正 博主一定及时修正


那么大家下期再见咯


相关文章
|
23天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
111 9
|
14天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
22 1
|
16天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
19天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
21天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
47 4
|
26天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
数据结构(栈与列队)
数据结构(栈与列队)
20 1
|
1月前
|
存储 JavaScript 前端开发
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
71 1
|
1月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
17 0
|
1月前
探索顺序结构:栈的实现方式
探索顺序结构:栈的实现方式