前言
在学完顺序表和链表这两种最基本的数据结构之后就要进入我们的栈和队列的学习了,首先我们来学习栈,而栈的存储方式一样有两种,一种是顺序存储,一种是链式存储,储存结构的不同使实现栈的基本算法也不同,今天我要给大家分享的的就是栈的顺序存储。
初识栈
栈也属于线性表,但是栈是操作受限的线性表,操作受限,就是栈的特点特点之一,在前面线性表的学习中我们知道,链表可以在表的两端甚至任何位置进行插入,删除,等操作,但栈却只能在固定的一端进行操作,意思就是栈的插入,删除等操作都只能在表的一个固定端点上进行,如下图:
如上图,我们可以看到插入,删除等操作只能在一侧进行, 所以向一个栈中插入新元素又称为压栈,入栈;同样的,栈数据的删除又可以称为出栈,弹栈,能够进行压栈,弹栈的一端自称为栈顶,不能的一端称为栈底,下面我们就来看一看应该怎么实现栈的顺序存储;
栈的创建
栈的创建,我们同样以头结点结构体的形式创建栈,头结点的结构体中保存一个数组和一个整型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语言学习半年,文章有什么不完善的地方还请见谅,欢迎大家对文章提出自己的看法,最后,感谢大家的阅读