C语言数据结构篇——栈的顺序存储

简介: C语言数据结构篇——栈的顺序存储

前言


在学完顺序表和链表这两种最基本的数据结构之后就要进入我们的栈和队列的学习了,首先我们来学习栈,而栈的存储方式一样有两种,一种是顺序存储,一种是链式存储,储存结构的不同使实现栈的基本算法也不同,今天我要给大家分享的的就是栈的顺序存储。


初识栈


栈也属于线性表,但是栈是操作受限的线性表,操作受限,就是栈的特点特点之一,在前面线性表的学习中我们知道,链表可以在表的两端甚至任何位置进行插入,删除,等操作,但栈却只能在固定的一端进行操作,意思就是栈的插入,删除等操作都只能在表的一个固定端点上进行,如下图:


149caa00d21e4521ad0c877052d3affc.png


如上图,我们可以看到插入,删除等操作只能在一侧进行, 所以向一个栈中插入新元素又称为压栈,入栈;同样的,栈数据的删除又可以称为出栈,弹栈,能够进行压栈,弹栈的一端自称为栈顶,不能的一端称为栈底,下面我们就来看一看应该怎么实现栈的顺序存储;


栈的创建


栈的创建,我们同样以头结点结构体的形式创建栈,头结点的结构体中保存一个数组和一个整型top,如下:


#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define maxsize 1024//栈的容量(自定义)
#define INFINITY 99999//随便定一个数,待会需要
typedef struct
{
    int data[maxsize];//该数组用来存放栈的数据
    int top;//数组中栈顶元素的下标(即最后一个元素下标)
}seqstack;//定义别名方便使用


这样一个栈就创建好了,下面就可以直接使用了 ;


栈的初始化


我们上面说了头结点中的top代表栈顶元素在数组中的下标 ,所以初始化时就不能把top赋值成自然数,所以我们把top赋值为-1,这样就完成了栈的初始化


void initstack(seqstack* stack)//初始化栈
{
    stack->top=-1;
}


判断栈为空


判断栈是否为空也很简单,要判断栈为空就判断栈是否为初始状态,而上面我们也进行了栈的初始化,所以栈是否等于-1就可以作为判断栈是否为空的依据,具体代码如下:


int isempty(seqstack* stack)//判断栈为空
{
    if(stack->top==-1)
    {
        return 1;//栈为空
    }
    return 0;//栈不为空
}


获取栈顶元素


因为我们是用数组来存放栈的数据的,所以要获取栈顶元素,就是获取数组中位于栈顶元素的下标,由上面的结构示意图可以看出来,栈底指的就是数组的第一个元素的位置,栈底指的就是数组最后一个元素,而头结点结构体中的top正是数组中最后一个元素的下标,所以获取栈顶元素是不是也很简单了呢?具体代码如下:


int seqstack_top(seqstack* stack)//获取栈顶元素
{
    if(isempty(stack)==0)//栈不为空
    {
        return stack->data[stack->top];
    }
    return INFINITY;//返回无穷大,不能返回-1,有可能栈的顶端元素就是-1
}


弹出栈顶元素


弹出栈顶元素就是我们的弹栈,压栈,意思就是弹出栈顶元素,使栈顶元素的后面一个元素成为栈顶元素,对应到数组中的实际操作其实就是删除数组的最后一个元素,所以也是比较简单的,具体代码如下:


int seqstack_pop(seqstack* stack)//弹出栈顶元素
{
    if(isempty(stack)==0)
    {
        return stack->data[stack->top--];
    }
    return INFINITY;//与获取栈顶元素同理
}


压入栈顶元素


压入栈顶元素就是我们称的压栈,入栈,即吧压入的数据放到栈顶的前面,使之称为新的栈顶,而数组上的意思就是在数组最后一个数据上再加一个数据,具体代码如下:


void seqstack_push(seqstack* stack,int val)//压栈(入栈)
{
    if(stack->top>=maxsize-1)栈已满则无法进行压栈
    {
        return;//退出程序
    }
    stack->top++;//此时栈顶改变,所以top指向新的栈顶下标
    stack->data[stack->top]=val;//入栈
}


销毁栈


销毁栈就不多说了,直接上代码:


void seqstack_destory(seqstack* stack)
{
    if(isempty(stack)==0)
    {
        free(stack);
    }
}


当然,为了方便使用,我们还可以建立一个遍历打印(即输出)栈的函数,代码如下:


void seqstack_print(seqstack* stack)
{
    for(int i=0;i<=stack->top;i++)
    {
        if(i%5==0)
        {
            printf("\n");
        }
        printf("%d ",stack->data[i]);
    }
    printf("\n");
}


以上就是栈的一些基本操作,我们都以函数的形式封装完了。


完整代码  


下面我们就随便写点数据将这些函数都用起来,就是完整代码啦,代码如下:


#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define maxsize 1024//栈的容量
#define INFINITY 99999//随便定一个数
typedef struct
{
    int data[maxsize];//定义一个数组
    int top;//栈顶元素的下标
}seqstack;
void initstack(seqstack* stack)//初始化栈
{
    stack->top=-1;
}
int isempty(seqstack* stack)//判断栈为空
{
    if(stack->top==-1)
    {
        return 1;//栈为空
    }
    return 0;//栈不为空
}
int seqstack_top(seqstack* stack)//获取栈顶元素
{
    if(isempty(stack)==0)//
    {
        return stack->data[stack->top];
    }
    return INFINITY;//返回无穷大,不能返回-1,有可能栈的顶端元素就是-1
}
int seqstack_pop(seqstack* stack)//弹出栈顶元素
{
    if(isempty(stack)==0)
    {
        return stack->data[stack->top--];
    }
    return INFINITY;
}
void seqstack_push(seqstack* stack,int val)//压栈(入栈)
{
    if(stack->top>=maxsize-1)
    {
        return;//退出程序
    }
    stack->top++;//指向栈顶
    stack->data[stack->top]=val;//入栈
}
void seqstack_destory(seqstack* stack)
{
    if(isempty(stack)==0)
    {
        free(stack);
    }
}
void seqstack_print(seqstack* stack)
{
    for(int i=0;i<=stack->top;i++)
    {
        if(i%5==0)
        {
            printf("\n");
        }
        printf("%d ",stack->data[i]);
    }
    printf("\n");
}
int main()
{
    srand((unsigned)time(0));//以时间为种子获取随机数
    seqstack stack;
    initstack(&stack);
    printf("请输入栈的初始数据个数\n");
    int number;
    scanf("%d",&number);
    for(int i=0;i<number;i++)//将随机数压栈
    {
        seqstack_push(&stack,rand()%1000);
        //rand可以按顺序读取srand通过种子获得的随机数
        //“%1000”是因为我想将随机数的值控制在0到1000
    }
    //获取栈顶元素
    printf("栈顶元素:%d\n",seqstack_top(&stack));
    printf("栈中的元素");
    seqstack_print(&stack);
    seqstack_pop(&stack);//出栈
    printf("出栈后栈中的元素");
    seqstack_print(&stack);
    printf("请输入要压栈的元素\n");
    int input;
    scanf("%d",&input);
    seqstack_push(&stack,input);//入栈
    printf("压栈后栈中的元素");
    seqstack_print(&stack);
    seqstack_destory(&stack);
    return 0;
}


随便写点数据运行一下就是下面这个效果啦


请输入栈的初始数据个数

10

栈顶元素:629

栈中的元素

340 937 63 665 546

729 904 922 326 629

出栈后栈中的元素

340 937 63 665 546

729 904 922 326

请输入要压栈的元素

9999

压栈后栈中的元素

340 937 63 665 546

729 904 922 326 9999


大一学生,c语言学习半年,文章有什么不完善的地方还请见谅,欢迎大家对文章提出自己的看法,最后,感谢大家的阅读


相关文章
|
10月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
223 0
栈区的非法访问导致的死循环(x64)
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
900 77
|
10月前
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
343 11
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
存储 算法 C++
【C++数据结构——图】图的邻接矩阵和邻接表的存储(头歌实践教学平台习题)【合集】
本任务要求编写程序实现图的邻接矩阵和邻接表的存储。需掌握带权有向图、图的邻接矩阵及邻接表的概念。邻接矩阵用于表示顶点间的连接关系,邻接表则通过链表结构存储图信息。测试输入为图的顶点数、边数及邻接矩阵,预期输出为Prim算法求解结果。通关代码提供了完整的C++实现,包括输入、构建和打印邻接矩阵与邻接表的功能。
678 10
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
438 7
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
1207 10
下一篇
开通oss服务