栈(Stack)是编程中最常用的数据结构之一。

  栈的特点是“后进先出”,就像堆积木一样,堆的时候要一块一块堆到最上面,拆的时候需要从最上面一块一块往下拆。栈的原理也一样,只不过它的操作不叫堆和拆,而是叫入栈(或压栈)和出栈(或弹栈)。栈要求我们只能在栈顶(最上面的元素)处进行增加和删除。

  栈可以用顺序表示法(顺序栈)和链式表示法(链栈)。由于栈只需要在一端增删节点,不需要在中间某处增删节点,因此即使栈在应用中大多数做的是增删操作,顺序栈虽然在增删操作时略微逊色于链栈(因为可能会扩容),但其存储密度要高于链栈,因此二者在性能方面可以说是各有各的好处。

  下面的代码是使用 C语言 描述的链栈的代码。

  栈的头文件 Stack.h 中的代码:

/**
* 栈(链栈):
* 本程序中栈的存储方式:栈顶->节点->节点->...->栈底。即:栈顶是第一个元素
*/
#include <Constant.h> // 栈中存储的数据的类型
typedef int ElemType; // 栈中的节点的数据结构体
typedef struct StackNode {
ElemType value; // 栈节点中存储的数据的值
struct StackNode* nextNode; // 下一个节点
} StackNode; // 栈的数据结构体
typedef struct Stack {
StackNode* data; // 栈中存储的所有节点
int length; // 栈的长度
StackNode* topNode; // 栈顶元素节点
} Stack; // 初始化一个空栈
Status initStack(Stack* S) {
S->data = (StackNode*)malloc(sizeof(StackNode));
if(S->data == NULL) {
printf("初始化栈失败!\n");
return FAILURE;
}
S->length = ;
S->topNode = NULL;
return SUCCESS;
} // 销毁栈
Status destroyStack(Stack* S) {
StackNode* tmpNode;
if(S->data == NULL) {
printf("栈不存在,销毁失败!\n");
return FAILURE;
}
while(S->topNode != NULL && S->topNode != S->data) {
tmpNode = S->topNode;
S->topNode = S->topNode->nextNode;
free(tmpNode);
}
S->data = NULL;
S->length = ;
S->topNode = NULL;
return SUCCESS;
} // 清空栈
Status clearStack(Stack* S) {
StackNode* tmpNode;
if(S->data == NULL) {
printf("栈不存在,清空失败!\n");
return FAILURE;
}
if(S->topNode == NULL) {
return SUCCESS;
}
while(S->topNode != S->data) {
tmpNode = S->topNode;
S->topNode = S->topNode->nextNode;
free(tmpNode);
}
S->topNode = NULL;
S->length = ;
return SUCCESS;
} // 判断栈是否为空
Status isStackEmpty(Stack* S) {
if(S->data == NULL) {
printf("栈不存在!\n");
exit();
}
if(S->length == ) {
return TRUE;
}
return FALSE;
} // 获取栈中元素的长度
int getStackLength(Stack* S) {
if(S->data == NULL) {
printf("栈不存在!\n");
exit();
}
return S->length;
} // 查看栈顶元素的值
ElemType getTopElem(Stack* S) {
if(S->data == NULL) {
printf("栈不存在,获取元素失败!\n");
exit();
}
if(S->topNode == NULL) {
printf("栈是空栈,获取元素失败!\n");
exit();
}
return S->topNode->value;
} // 元素入栈
Status push(Stack* S, ElemType e) {
StackNode* tmpNode;
if(S->data == NULL) {
printf("栈不存在,元素入栈失败!\n");
return FAILURE;
}
tmpNode = (StackNode*)malloc(sizeof(StackNode));
if(tmpNode == NULL) {
printf("元素入栈失败!\n");
return FAILURE;
}
tmpNode->value = e;
S->length++;
if(S->topNode == NULL) {
S->topNode = tmpNode;
S->topNode->nextNode = S->data;
return SUCCESS;
}
tmpNode->nextNode = S->topNode;
S->topNode = tmpNode;
return SUCCESS;
} // 元素出栈
StackNode* pop(Stack* S) {
StackNode* tmpNode;
if(S->data == NULL) {
printf("栈不存在,元素出栈失败!\n");
exit();
}
if(S->topNode == NULL) {
printf("栈是空栈,元素出栈失败!\n");
return NULL;
}
tmpNode = S->topNode;
S->topNode = S->topNode->nextNode;
if(S->topNode == S->data) {
S->topNode = NULL;
}
tmpNode->nextNode = NULL;
S->length--;
return tmpNode;
} // 遍历栈中的元素
void traverseStack(Stack* S) {
StackNode* tmpNode;
if(S->data == NULL) {
printf("栈不存在,遍历失败!\n");
exit();
}
if(S->topNode == NULL) {
printf("栈是空栈,遍历失败!\n");
exit();
}
printf("遍历栈:");
tmpNode = S->topNode;
while(tmpNode != S->data) {
printf("%-4d", tmpNode->value);
tmpNode = tmpNode->nextNode;
}
printf("\n");
} // 栈的测试函数
int testStack() {
// 数据声明
Stack stack;
StackNode* node;
int i;
// 初始化栈
if(initStack(&stack) == SUCCESS) {
printf("初始化栈成功!\n");
}
// 判断栈是否是空栈
printf("栈是否为空栈?%s\n", isStackEmpty(&stack) == TRUE ? "是" : "否");
// 元素入栈
for(i = ; i <= ; i++) {
if(push(&stack, i) == SUCCESS) {
printf("元素%d入栈成功!\n", i);
}
}
// 遍历栈中的元素
traverseStack(&stack);
// 元素出栈
node = pop(&stack);
if(node != NULL) {
printf("元素%d成功出栈!\n", node->value);
}
// 遍历栈中的元素
traverseStack(&stack);
// 查看栈顶元素的值
printf("栈顶元素的值是:%d\n", getTopElem(&stack));
// 获取栈的长度
printf("栈的当前长度:%d\n", getStackLength(&stack));
// 清空栈
if(clearStack(&stack) == SUCCESS) {
printf("清空栈成功!\n");
}
// 销毁栈
if(destroyStack(&stack) == SUCCESS) {
printf("销毁栈成功!\n");
}
return ;
}

  常量类 Constant.h 中定义了一些常量,其代码如下:

#include <stdio.h>
#include <stdlib.h> #define TRUE 1
#define FALSE 0 #define SUCCESS 1
#define FAILURE 0 typedef int Status;

  主函数所在的文件 main.c 中的代码如下:

#include <Stack.h>

int main() {
testStack();
return ;
}

  运行结果如下:

初始化栈成功!
栈是否为空栈?是
元素1入栈成功!
元素2入栈成功!
元素3入栈成功!
元素4入栈成功!
元素5入栈成功!
遍历栈:5 4 3 2 1
元素5成功出栈!
遍历栈:4 3 2 1
栈顶元素的值是:4
栈的当前长度:4
清空栈成功!
销毁栈成功! Process returned 0 (0x0) execution time : 0.016 s
Press any key to continue.

【数据结构】之栈(C语言描述)的更多相关文章

  1. C语言学习书籍推荐《数据结构与算法分析:C语言描述(原书第2版)》下载

    维斯 (作者), 冯舜玺 (译者) <数据结构与算法分析:C语言描述(原书第2版)>内容简介:书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能.效率以及对运行 ...

  2. 数据结构与抽象 Java语言描述 第4版 pdf (内含标签)

    数据结构与抽象 Java语言描述 第4版 目录 前言引言组织数据序言设计类P.1封装P.2说明方法P.2.1注释P.2.2前置条件和后置条件P.2.3断言P.3Java接口P.3.1写一个接口P.3. ...

  3. 数据结构与算法分析——C语言描述 第三章的单链表

    数据结构与算法分析--C语言描述 第三章的单链表 很基础的东西.走一遍流程.有人说学编程最简单最笨的方法就是把书上的代码敲一遍.这个我是头文件是照抄的..c源文件自己实现. list.h typede ...

  4. 最小正子序列(序列之和最小,同时满足和值要最小)(数据结构与算法分析——C语言描述第二章习题2.12第二问)

    #include "stdio.h" #include "stdlib.h" #define random(x) (rand()%x) void creat_a ...

  5. 《数据结构与算法分析——C语言描述》ADT实现(NO.00) : 链表(Linked-List)

    开始学习数据结构,使用的教材是机械工业出版社的<数据结构与算法分析——C语言描述>,计划将书中的ADT用C语言实现一遍,记录于此.下面是第一个最简单的结构——链表. 链表(Linked-L ...

  6. 《数据结构与算法分析-Java语言描述》 分享下载

    书籍信息 书名:<数据结构与算法分析-Java语言描述> 原作名:Data Structures and Algorithm Analysis in Java 作者: 韦斯 (Mark A ...

  7. 《数据结构与算法分析:C语言描述_原书第二版》CH3表、栈和队列_reading notes

    表.栈和队列是最简单和最基本的三种数据结构.基本上,每一个有意义的程序都将明晰地至少使用一种这样的数据结构,比如栈在程序中总是要间接地用到,不管你在程序中是否做了声明. 本章学习重点: 理解抽象数据类 ...

  8. 《数据结构与算法分析——C语言描述》ADT实现(NO.01) : 栈(Stack)

    这次的数据结构是一种特殊的线性表:栈(Stack) 栈的特点是后入先出(LIFO),可见的只有栈顶的一个元素. 栈在程序中的地位非常重要,其中最重要的应用就是函数的调用.每次函数调用时都会创建该函数的 ...

  9. 用链表实现栈----《数据结构与算法分析----C语言描述》

    一.头文件: #ifndef _STACK_LINK_H_ #define _STACK_LINK_H_ struct stack_record; typedef struct stack_recor ...

  10. 读书笔记:《数据结构与算法分析Java语言描述》

    目录 第 3 章 表.栈和队列 3.2 表 ADT 3.2.1 表的简单数组实现 3.2.2 简单链表 3.3 Java Collections API 中的表 3.3.1 Collection 接口 ...

随机推荐

  1. 你不知道的Canvas(二)

    你不知道的Canvas(二) 一.色彩Colors 到目前为止,我们只看到过绘制内容的方法.如果我们想要给图形上色,有两个重要的属性可以做到:fillStyle 和 strokeStyle. fill ...

  2. CSP-S:追忆

    Warning:这一篇极其中二,开了那个大会莫名有感而发. 模拟测试17那套题啊... 开的这个大会为什么弄得我退役感如此强烈... 早就想收藏了,还是记下来吧 <入阵曲> 丹青千秋酿, ...

  3. python分支和循环结构

    本文收录在Python从入门到精通系列文章系列 1. 分支结构 1.1 应用场景 迄今为止,我们写的Python代码都是一条一条语句顺序执行,这种代码结构通常称之为顺序结构.然而仅有顺序结构并不能解决 ...

  4. 如何在vue-cli项目中结合mockjs模拟假数据

    1.前言 在如今前后端分离的开发方式已被广泛采用的今天,前端同学和后端同学各自独立开发,后端提供数据接口,前端调用接口获取数据渲染页面.但是在实际开发中,后端开发由于逻辑相对复杂接口迟迟提供不到位,而 ...

  5. JDK下载安装配置教程(详细)

    JDK下载安装配置教程(详细) 版权声明:本文为原创文章,转载请附上原文出处链接和本声明.https://www.cnblogs.com/mxxbc/p/11844885.html 因为最近需要在Wi ...

  6. ELK分布式日志+NLog在.NetCore中的应用

    一.ELK简介 ELK是Elasticsearch.Logstash和Kibana首字母的缩写.这三者均是开源软件,这三套开源工具组合起来形成了一套强大的集中式日志管理平台 Elasticsearch ...

  7. 两张图弄懂函数的递归(以golang为例)

    函数递归时要遵守的原则: 执行一个函数时,就要创建一个新的受保护的独立空间(新函数栈) 函数的局部变量是独立的,不会相互影响: 递归必须向退出递归的条件逼近,否则就会无限递归: 当一个函数执行完毕,或 ...

  8. netty服务端的创建

    服务端的创建 示例代码 netty源码中有一个netty-example项目,不妨以经典的EchoServer作为楔子. // 步骤1 EventLoopGroup bossGroup = new N ...

  9. [剑指offer]删除链表中重复的结点(把重复的都删掉,1个不留)

    ①题目 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5 处理后为 ...

  10. nuxt遇到的问题(一)window 或 document is not defined

    因为用了VUE做的官网,既然是官网了避免不了SEO的问题了(该死当初就不应该选择用vue) 很自然就是选择了使用nuxt.js来做ssr预渲染了. 因为网站不是响应式的,PC / 移动端要进行对应跳转 ...