栈的简介
栈(Stack)是限定仅在表尾进行插入租删除操作的线性表。
允许插入和删除的一端称为栈顶(top),另-端称为栈底(bottom)
不含任何数据元素的栈称为空栈
栈又称为后进先出的线性表,简称LIFO结构
栈的插入操作,也叫做进栈,压栈,入栈
栈的删除操作,叫做出栈
以下是栈的示意图,
栈的C语言编写
因为栈也是线性表的一种,所以也包括两种类型,顺序栈和链式栈。
顺序栈
单链表在C语言下编写的结构代码如下,
#define MAXSIZE 128
typedef int data_t;
/* 1 */
/*typedef struct
{
data_t data[MAXSIZE];
int last;
}Sqstack,*Sqstacklist;*/
/*下面编写另一种形式的栈结构建立*/
/*这种建立方式会让后面的编程相较顺序表的编程来说变难
但是用户可以自主设定data中的数据容量*/
typedef struct
{
data_t *data;/*将数据由原来的数组转变设置为一个指向数据地址的指针*/
int maxlen;/*多加入一个参数,用于设定数据的最大长度,主要体现在malloc申请内存时*/
int top;/*指示栈顶的位置的变量,指定的是数组下标*/
}Sqstack;
下面我们将编写一些顺序表相关的函数,在编写时我们一般会创建三个文件,分别是sqlist.h,sqlist.c,test.c,其中sqlist.h用于编写一些数据结构的定义和函数结构,sqlist.c用于编写函数具体实现,test.c用于测试每个函数是否正确。
在sqlist.h文件中,编写的程序如下,
#define MAXSIZE 128
typedef int data_t;
/* 1 */
/*typedef struct
{
data_t data[MAXSIZE];
int last;
}Sqstack,*Sqstacklist;*/
/*下面编写另一种形式的栈结构建立*/
/*这种建立方式会让后面的编程相较顺序表的编程来说变难
但是用户可以自主设定data中的数据容量*/
typedef struct
{
data_t *data;/*将数据由原来的数组转变设置为一个指向数据地址的指针*/
int maxlen;/*多加入一个参数,用于设定数据的最大长度,主要体现在malloc申请内存时*/
int top;/*指示栈顶的位置的变量,指定的是数组下标*/
}sqstack;
sqstack * stack_creat(int len);
int stack_push(sqstack *s,data_t value);
int stack_empty(sqstack *s);
int stack_full(sqstack *s);
data_t stack_pop(sqstack *s);
data_t stack_top(sqstack *s);
int stack_clear(sqstack *s);
int stack_free(sqstack *s);
在sqlist.h文件中,我们编写相关函数的具体实现,以下是每个操作API函数的实现,
创建顺序栈
/*创建栈,len表示数据的长度*/
sqstack * stack_creat(int len)
{
sqstack *s;
/*申请内存*/
/*先为结构体申请内存*/
if((s = (sqstack*)malloc(sizeof(sqstack))) == NULL)
{
printf("malloc sqstack fail\n");
return NULL;
}
/*由于现在的数据是用指针存储,而上面申请时只是申请了结构体内三个元素的内存,所以我们还需要申请数据的内存*/
if((s->data = (data_t*)malloc(sizeof(data_t)*len)) == NULL)
{
printf("malloc data fail\n");
free(s->data);
return NULL;
}
/*赋初值*/
/*从s->data开始,每个部分都放0,放的长度len*sizeof(data_t),也就是把数据的初值都赋为0*/
memset(s->data,0,len*sizeof(data_t));
s->maxlen = len;
s->top = -1;
return s;
}
入栈
/*入栈函数*/
int stack_push(sqstack *s,data_t value)
{
if(s == NULL)
{
printf("stack is null\n");
return -1;
}
/*判断是否为满*/
if(s->top == s->maxlen-1)
{
printf("stack is full\n");
return -1;
}
s->top = s->top+1
s->data[s->top] = value;
return 0;
}
出栈
/*出栈*/
data_t stack_pop(sqstack *s)
{
data_t data;
if(s == NULL)
{
printf("stack is null\n");
return -1;
}
/*判断栈中是否有值,没有值无法进行*/
if(s->top == -1)
{
printf("stack is empty");
return 0;
}
data = s->data[s->top];
s->top--;
return s;
}
释放栈空间
/*释放栈空间*/
int stack_free(sqstack *s)
{
/*由于我们malloc申请了两个部分的空间,所以都要释放*/
/*并且我们得先释放结构体中的data_t* 的内存,在释放stack的内存*/
if(s->data != NULL)
free(s->data);
free(s);
}
简单查看函数
/*判断是否是空栈*/
int stack_empty(sqstack *s);
{
if(s == NULL)
{
printf("stack is null\n");
return -1;
}
/*三目运算表示,top等于-1返回1表示是空,否则返回0*/
return(s->top == -1?1:0);
}
/*判断是否满栈*/
int stack_full(sqstack *s)
{
if(s == NULL)
{
printf("stack is null\n");
return -1;
}
return(s->top == len-1?1:0);
}
/*查看栈顶元素*/
data_t stack_top(sqstack *s)
{
return s->data[s->top];
}
/*清除栈元素*/
int stack_clear(sqstack *s)
{
if(s == NULL)
{
printf("stack is null\n");
return -1;
}
/*由于清理元素不是释放内存,所以我们只需要调整top即可告诉用户链表无值*/
s->top = -1;
return 0;
}
链式栈
链式栈其实就是给单链表加一个限制,就是链表的插入和删除操作只允许在链表的头部进行,链表尾部就是栈底,头指针就是栈顶指针。
同样,链式栈我们依旧编写其相关函数进行学习,如下,
typedef int data_t;
typedef struct node
{
data_t data;
struct node* next;
}linknode,*linkstack;
linkstack stack_create();
int stack_push(linkstack s,data_t value);
data_t stack_pop(linkstack s);
int stack_empty(linkstack s);
int stack_top(linkstack s);
linkstack stack_free(linkstack);
创建链式栈
linkstack stack_create()
{
linkstack s;
s = (linkstack)malloc(sizeof(linknode));
if(s == NULL)
{
printf("malloc linkstack fail");
return NULL;
}
s->data = 0;
s->next = NULL;
return s;
}
入栈
/*入栈*/
int stack_push(linkstack s,data_t value)
{
linkstack p;
if(s == NULL)
{
printf("linkstack is null");
return -1;
}
p = (linkstack)malloc(sizeof(linknode));
if(p == NULL)
{
printf("malloc fail\n");
return -1;
}
/*先赋初值(习惯)*/
p->data = value;
p->next = NULL
p->next = s->next;
s->next = p;
return 0;
}
出栈
/*出栈*/
data_t stack_pop(linkstack s)
{
data_t data;
linkstack p;
if(s == NULL)
{
printf("linkstack is null");
return 0;
}
data = s->next->data;
p = s->next;
s->next = p;
/*删除就是把这个部分释放掉,且要将指针赋NULL,防止野指针*/
free(p);
p = NULL;
return data;
}
释放栈空间
/*释放栈的空间*/
linkstack stack_free(linkstack s)
{
linkstack p;
if(s == NULL)
{
printf("linkstack is null");
return NULL;
}
while(s != NULL)
{
p = s;
s = p->next;
free(s);
}
return NULL;
}
简单查看函数
/*判断栈是否为空栈*/
int stack_empty(linkstack s)
{
if(s == NULL)
{
printf("linkstack is null");
return -1;
}
return(s->next == NULL?1;0);
}
/*查看栈顶元素*/
data_t stack_top(linkstack s)
{
if(s == NULL)
{
printf("linkstack is null");
return -1;
}
return(s->next->data);
}
针对数据结构与算法的学习主要是从代码编程的角度进行学习,建议大家学习完相关理论知识后,还是自己进行敲一下代码,这样对数据结构的学习更有帮助!