【数据结构和算法】了解认识栈,并实现栈的相关函数(下)

简介: 【数据结构和算法】了解认识栈,并实现栈的相关函数(下)

三、完整代码实现

1.链表实现栈

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
//创建基础结构
typedef struct node {
  int data;
  struct node* next;
}ST;
//栈实际上就是一个只能进行头插头删的单向链表
//创建栈的头尾结点 结构体
typedef struct stack {
  struct node* top;//栈顶元素地址
  struct node* bottom;//栈底元素地址
  int size;//栈的元素个数
};
//表示每一个栈都是struct stack* 类型的,栈中的每一个怨怒是都是struct node *类型的  不仅需要为栈分配内存,还需要为压入栈中的元素分配内存
/*
node中的next指针用于让栈中上面的节点连接到下面的节点,stack中的top和bottom分别存放当前栈顶元素的地址和栈底元素的后一个位置的地址(NULL),
因为是用于指向栈中节点的指针,所以得是struct node* 类型。*/
//初始化栈
struct stack* create_stack()
{
  struct stack* s = (struct stack*)malloc(sizeof(struct stack));
  s->size = 0;
  s->bottom = s->top = NULL;
  return s;
}
//一开始栈是空的所以 size为0  top  bottom是NULL
//创建新的结点
struct node* create_node(int data) {
  struct node* newnode = (struct node*)malloc(sizeof(struct node));
  newnode->next = NULL;
  newnode->data = data;
  return newnode;
}
//入栈
//入栈首先要将准备入栈的元素封装成结点,和链表没有差别
void stackPush(struct stack* s, int x) {
  ST* newnode = create_node(x);
  newnode->next = s->top;
  s->top = newnode;
  s->size++;
}
//出栈
void stackPop(struct stack* s, int* x) {
//判断是否为空栈   如果是 空栈的话就  使得输出 Pop failed
  if (s->size == 0) {
    printf("Pop failed\n");
    exit(-1);
  }
  //创建结点临时变量  赋值得到栈顶元素
  ST* tmp = s->top;
  *x = tmp->data;//得到数值
  s->top = tmp->next;
  s->size--;
}
//查看栈顶元素
void stackTop(struct stack* s, int* x) {
  if (s->size == 0) {
    printf("空栈~~\n");
    exit(-1);
  }
  *x = s->top->next->data;
}
//清空栈
void make_stack_empty(struct stack* s) {
  s->size = 0;
  s->bottom = s->top ;
  //将栈底等于栈顶就可以  然后将size为0
}
void stackPrint(struct stack* s) {
  //打印栈表
  ST* list = s->top;
  printf("top -> ");
  while (list!=NULL) {
    printf("%d -> ", list->data);
    list = list->next;
  }
}
int main()
{
  struct stack *s = create_stack();
  stackPush(s, 1);
  stackPush(s, 2);
  stackPush(s, 3);
  stackPush(s, 4);
  stackPush(s, 5);
  stackPrint(s);
  int a = 0;
  stackPop(s,&a);
  printf("\n%d\n", a);
  stackPrint(s);
  return 0;
}

2.数组(顺序表)实现栈

#define _CRT_SECURE_NO_WARNINGS
#include"steck.h"
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
//栈是限定在一个表里面的一段进行插入删除操作的线性表
// 数据进出的顺序为先进后处
// 应用场景:网页浏览的时候的后退  编辑软件的撤销
// 
//创建栈  两个方式:数组(顺序表)和 单链表
//1.数组:选用数组用来做栈的存储结构,只需要在数组末尾进行操作即可,完美避开数组操作中挪动数据缺陷
      //   显然是可以用数组来做栈的存储结构
//2.单链表  :因为栈是吸纳星表的一段进行操作,所以一般是用链表头进行操作
//进行头插头删  是用链表更好 效率更高
//1.用数组的方式
typedef int StackDataType;
typedef struct Stcak {
    StackDataType* data;
    int top;
    int capacity;   //数据域和元素个数
}ST;
//初始化
void StackInit(ST* ps) {
    ps->data = (StackDataType*)malloc(sizeof(StackDataType) * 4);
    if (ps->data == NULL) {
        printf("malloc failed\n");
        exit(-1);
    }
    ps->top = 0;
    ps->capacity = 4;
}
//压栈
void StackPush(ST* ps, int x) {
    assert(ps);//断言
    //满了就扩容
    if (ps->top == ps->capacity) {
        StackDataType* tmp = (StackDataType*)realloc(ps->data, sizeof(StackDataType) * ps->capacity * 2);
        if (tmp == NULL) {
            printf("realloc failed\n");
            exit(-1);
        }
        else {
            ps->data = tmp;
            ps->capacity *= 2;
        }
    }
    ps->data[ps->top] = x;
    ps->top++;
}
//出栈
void StackPop(ST* ps) {
    //出栈是将最后一个元素放出来  先进后出
    assert(ps);
    assert(ps->top > 0);//断言进行判断是否栈为空  即top!=0
    ps->top--;
    //直接减减就可以  没有了对应元素 的数据  如果再次压栈的话 会把之前的数据进行更改
}
//取得栈顶元素
StackDataType StackTop(ST* ps) {
    assert(ps);
    assert(ps->top > 0);
    return ps->data[ps->top - 1];//因为top栈顶始终要保持比元素个数大一,保证压栈的时候先压栈然后再加加
//所以取栈顶元素 的时候 top-1
}
//销毁栈
void StackDestory(ST* ps) {
    assert(ps);
    free(ps->data);
    //释放数组data的空间
    ps->data = NULL;
    ps->top = ps->capacity = 0;
}
//求栈中元素个数
int StackSize(ST* ps) {
    assert(ps);
    return ps->top;
}
//判断是否为空
bool StackEmpty(ST* ps) {
    assert(ps);
    return ps->top == 0;
}
void StackPrint(ST* ps) {
    //打印栈表
    assert(ps);
    for (int i = 0; i < ps->top; i++) {
        printf("%d ", ps->data[i]);
    }
    printf("\n");
}
int main()
{
    ST s;
    ST *ps=&s;
  /*  StackInit(&ps);
    StackPush(&ps, 1);
    StackPush(&ps, 2);
    StackPush(&ps, 3);
    StackPush(&ps, 4);
    StackPush(&ps, 5);
    StackPrint(&ps);*/
    StackInit(ps);
    StackPush(ps, 1);
    StackPush(ps, 2);
    StackPush(ps, 3);
    StackPush(ps, 4);
    StackPush(ps, 5);
    StackPop(ps);//出栈成功
    StackPrint(ps);
    printf("%d \n", StackTop(ps));//取得栈顶元素
    printf("%d \n", StackSize(ps));//获得栈表元素个数
    StackDestory(ps);
    StackPrint(ps);//销毁栈表成功
    return 0;
}

总结

栈是限定在一个表里面的一段,对其进行插入删除操作的线性表,数据进出的顺序为先进后处,应用场景:网页浏览的时候的后退  编辑软件的撤销,实际上栈的功能就这样,学会顺序表以及链表的使用,对于栈来讲,只是懂得头擦头删,理解概念了,就好掌握并实现栈。

下文,我们会讲解一下队列,和栈相似,但是另有不同,敬请期待吧,感谢大家支持!!!

相关文章
|
4月前
|
算法 机器人 定位技术
【VRPTW】基于matlab秃鹰算法BES求解带时间窗的骑手外卖配送路径规划问题(目标函数:最优路径成本 含服务客户数量 服务时间 载量 路径长度)(Matlab代码实现)
【VRPTW】基于matlab秃鹰算法BES求解带时间窗的骑手外卖配送路径规划问题(目标函数:最优路径成本 含服务客户数量 服务时间 载量 路径长度)(Matlab代码实现)
142 0
|
3月前
|
机器学习/深度学习 传感器 算法
基于matlab瞬态三角哈里斯鹰算法TTHHO多无人机协同集群避障路径规划(目标函数:最低成本:路径、高度、威胁、转角)(Matlab代码实现)
基于matlab瞬态三角哈里斯鹰算法TTHHO多无人机协同集群避障路径规划(目标函数:最低成本:路径、高度、威胁、转角)(Matlab代码实现)
145 1
|
4月前
|
机器学习/深度学习 算法 数据挖掘
【配送路径规划】基于螳螂虾算法MShOA求解带时间窗的骑手外卖配送路径规划问题(目标函数:最优路径成本 含服务客户数量 服务时间 载量 路径长度)研究(Matlab代码实现)
【配送路径规划】基于螳螂虾算法MShOA求解带时间窗的骑手外卖配送路径规划问题(目标函数:最优路径成本 含服务客户数量 服务时间 载量 路径长度)研究(Matlab代码实现)
174 0
|
4月前
|
算法 Python
【配送路径规划】基于遗传算法求解带时间窗的电动汽车配送路径规划(目标函数:最小成本;约束条件:续驶里程、额定载重量、数量、起始点)研究(Matlab代码实现)
【配送路径规划】基于遗传算法求解带时间窗的电动汽车配送路径规划(目标函数:最小成本;约束条件:续驶里程、额定载重量、数量、起始点)研究(Matlab代码实现)
146 0
|
5月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
170 1
|
5月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
159 0
|
6月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
131 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
9月前
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
297 10
 算法系列之数据结构-二叉树
|
9月前
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
255 3
 算法系列之数据结构-Huffman树