hello 啊大家,我又回来了,今天我们继续更新数据结构,我们今天讲解栈,栈这个东西是数据结构的重点,每一个程序都用到了栈(程序在操作系统中的存储,变量的存储位置,函数的存储位置等等)我们来深入浅出的讲解栈。我们先来抽象的想象一下,栈是一种先进后出的结构,把东西存入栈中时,先进去的后面出来,就像你往一个箱子里面放书,先放进去的时在最底下,最后面才能拿出来,有了这种思想我们的栈就是这种结构,先进后出,第一次存进去的东西就存在栈底,就像放书纸箱的箱底。哪有栈顶吗,当然是有的,这里等会再说。
通俗来说栈是限定仅在表尾进行插入和删除操作的线性表。
先进后出、后进先出
栈顶:允许操作的一端
栈底:不允许操作的一端
1 定义
栈(Stack)是一种抽象的数据结构,它遵循后进先出(LIFO, Last In First Out)的原则。也就是说,最后放入栈中的元素最先被取出。栈分为顺序栈 链式栈。
2 栈的基本操作
1. 入栈、压栈:将一个元素放入栈顶。
2. 出栈、弹栈:从栈顶移除一个元素。
3. 取栈顶元素:查看栈顶元素但不移除它。
4. 判断栈是否为空:检查栈中是否有元素。
栈的基本函数操作;
1.创建 CreateSeqStack
2.销毁 DestroySeqStack
3.判断是否为空栈 IsEmptySeqStack
4.判断是否为满栈 IsFullSeqStack
5.压栈 PushSeqStack
6.出栈 PopSeqStack
接下来我们一一介绍(这里的栈是线性栈(顺序栈))
typedef struct{
char name[32];
char sex;
int age;
int score;
}DATATYPE;
typedef struct
{
DATATYPE* head;
int tlen;
int top;// clen
}SeqStack;
SeqStack* CreateSeqStack(int size);
int DestroySeqStack(SeqStack*ss);
int PushSeqStack(SeqStack*ss,DATATYPE*data);
int PopSeqStack(SeqStack*ss);
int IsEmptySeqStack(SeqStack*ss);
int IsFullSeqStack(SeqStack*ss);
int GetSizeSeqStack(SeqStack*ss);
DATATYPE*GetTopSeqStack(SeqStack*ss);
int show(SeqStack * ss);
这些是.h里面的文件,多文件编程,把这些声明定义和其他的范围分开,首先我们先定义一个数据的结构体,里面存有一个学生的信息,姓名,性别,年龄,成绩。栈结构体中存有数据类型的指针和总长度和栈顶位置也就是现在数据的位置。下面声明函数。
SeqStack *CreateSeqStack(int size)
{
SeqStack * ss = (SeqStack*)malloc(sizeof(SeqStack));
if(NULL == ss)
{
perror("CreateSeqStack malloc err");
return NULL;
}
ss->head = (DATATYPE*)malloc(sizeof(DATATYPE)*size);
if(NULL ==ss->head)
{
perror("CreateSeqStack error malloc2");
return NULL;
}
ss->tlen = size;
ss->top = 0;
return ss;
}
int DestroySeqStack(SeqStack *ss)
{
free(ss->head);
free(ss);
return 0;
}
上面两个是创建栈函数和销毁栈函数。第一个是创建栈的函数返回值是栈指针类型的,参数是size就是你想定义的栈的大小,定义一个栈的指针开到堆上,错误判断,让后指针的头指针指向在堆上大小为data*size大小。总大小tlen等于size,top等于0,放回这个指针,栈就创建好了。
销毁也很简单,把栈的头指针传进去,然后free掉,在把这个指针free掉就行了,应为头指针指向的是一起的。
int IsEmptySeqStack(SeqStack *ss)
{
return 0 == ss->top;
}
int IsFullSeqStack(SeqStack *ss)
{
return ss->top == ss->tlen;
}
DATATYPE *GetTopSeqStack(SeqStack *ss)
{
if(IsEmptySeqStack(ss))
{
return NULL;
}
return &ss->head[ss->top-1];
}
这上面是三个辅助函数,第一个是判断栈是否为空,只需要放回这个栈的top就行了如果为0就是空。第二个是判满函数,如果是满的栈的tlen和top是一起相等的,也很简单。第三个函数是得到栈的top数据的函数,直接放回top-1的地址就行了,数组要减一。相信你们很快能动,这三个简单。
int PushSeqStack(SeqStack *ss, DATATYPE *data)
{
if(NULL == ss ||NULL ==data)
{
fprintf(stderr,"SeqStack or data is null \n");
return 1;
}
if(IsFullSeqStack(ss))
{
fprintf(stderr,"PushSeqStack full\n");
return 1;
}
memcpy(&ss->head[ss->top],data,sizeof(DATATYPE));
ss->top++;
return 0;
}
int PopSeqStack(SeqStack *ss)
{
if(NULL == ss )
{
fprintf(stderr,"SeqStack is null \n");
return 1;
}
if(IsEmptySeqStack(ss))
{
fprintf(stderr,"PopSeqStack is empty \n");
return 1;
}
ss->top--;
return 0;
}
这两个函数是入栈和出栈的函数,入栈参数有两个一个是你要操作的栈,一个是data数据包的指针(这个在函数外初始化),出错判断,然后利用memcpy函数将数据复制到栈顶,然后再将top++,这样就入栈操作结束了,其实没啥东西,就一个复制和++。出栈的话将要操作的栈传进去,错误判断,将top指针减减就行,虽然空间存在但是下一次入栈操作会减这段空间的值富凯掉就不需要清空,当然了也可以清空一下,利用memcpy请0.不过多此一举。这样就结束了,函数很少,操作简单,我把主函数给大家展示一下,今天的课可以可以轻松结束。
#include <stdio.h>
#include "seqstack.h"
#include <string.h>
#include <stdio.h>
int main()
{
DATATYPE data[5]={
{"faker",'m',28,100},
{"gumayusi",'m',24,95},
{"zues",'m',20,90},
{"keria",'m',24,88},
{"oner",'f',23,85},
};
SeqStack* ss = CreateSeqStack(10);
PushSeqStack(ss,&data[0]);
PushSeqStack(ss,&data[1]);
PushSeqStack(ss,&data[2]);
PushSeqStack(ss,&data[3]);
PushSeqStack(ss,&data[4]);
int i = 0 ;
for(i=0;i<5;i++)
{
DATATYPE* tmp = GetTopSeqStack(ss);
printf("name:%s score:%d\n",tmp->name,tmp->score);
PopSeqStack(ss);
}
printf("Hello World!\n");
return 0;
}
定义一个data的结构体数组,把数据都存进去,创建一个栈,利用入栈函数把他存进去,现在数据就存进去了,要验证是否存进去得把数据一个一个出栈查看,弄一个for循环data一个指针变量指向top,让后输出他的数据,再把栈出一个,让后就循环查看就行了,这个只是验证,相信大家可以很快理解。打印helloworld是为了防止程序段错误。好的,今天的课结束,下课!