栈(stack),先进后出(Last In First Out)LIFO
其实就当做一个容器,如篮子,箱子,瓶子。放东西进去,先放的在瓶底,最后拿出来。后放的在瓶口,先取出来。
(一)顺序栈
先看定义吧
typedef int datatype //栈的数据类型
#define maxsize 64 //栈的大小
typedef struct
{
datatype data[maxsize];
int top; //栈顶指针,其实就是栈里存了多少东西
}seqstack;
其实就是一个结构体里,成员是数组,我们通过结构体指针,来操作内存数据。
data[]里面存数据,
top做指标,好像一个浮标,涨到哪里了。这里需要着重理解一下,因为后面还有队列,它有两个指标front和rear。我认为top,front,rear,不能称为指针,是C语言意义上的指针,它们只是一个标记,我想称为指标,不要让指针把你吓跑了。
其实这个top指标是认为加在data数组上的,使它们相关联,我们通过top等于多少,知道这个栈是空的如:top=-1,用了多少,如:top=63,说明满栈了。top是人为加的,你也可以在函数里改。这里只不过要满足栈的定义先进后出,我们需要知道栈顶处于什么状态,举例使用:
建栈:
seqstack *p; //创建一个栈
p=(seqstack*)malloc(maxsize*sizeof(seqstack));//给它分配空间
p->top=-1;//标记一下,它是空的
我需要加一个元素入栈,如 5,
s->top++;//把标记s->top+1=0,说明有一个元素
s->data[s->top]=5;//把数据存进去,s->data[0]=5
再加一个 8
s->top++;//把标记s->top+1=1,说明有一个元素
s->data[s->top]=8;//把数据存进去,s->data[1]=5
一直加,直到s->top==63,那s->data[63].数组是不是已经满了,数组下标从0开始,从结构体定义知道它最大能存64个,也就是最大到s->top[63]。但电脑不会告诉你啊,你需要读取特征啊,特征就是s->top==63,说明已经满栈了。
前面已经知道,指针其实是带有指向性的地址,它的值是一个地址,而且是一个首地址,你可以通过这个首地址,来操作数据
data下标从0开始,最多能到63
栈顶指针从-1开始 -1为空 >0为非空
操作函数
stack.c
//创建一个空栈
seqstack * Creat_stack()
{
seqstack *p; //创建一个栈
p=(seqstack*)malloc(maxsize*sizeof(seqstack));
p->top=-1;
return p;
}
//置栈空
status Setnull(seqstack *s)
{
s->top=-1;
return TRUE;
}
//判栈空
status Empty(seqstack *s)
{
if(s->top>0)
return FALSE;
else
return TRUE;
}
//进栈
//首先判断栈是否满了
status Push(seqstack *s,int x)
{
if(s->top==maxsize-1)
{
printf("overflow");
return FALSE;
}
else
{
s->top++;
s->data[s->top]=x;
}
return TRUE;
}
//退栈
//首先判断栈是否空了,返回被删值
status Pop(seqstack *s)
{
if(Empty(s))
{
printf("underflow");
return FALSE;
}
else
{
s->top--;
return s->data[s->top+1];
}
}
//取栈顶
//首先判断栈是否空了,返回栈顶值
status Pop(seqstack *s)
{
if(Empty(s))
{
printf("stack is empty");
return FALSE;
}
else
{
return s->data[s->top];
}
}
stack.h
typedef int datatype; //栈的数据类型
#define status int //函数状态
#define TRUE 1
#define FALSE 0
#define maxsize 64 //栈的大小
typedef struct stack
{
datatype data[maxsize];
int top; //栈顶指针,其实就是栈里存了多少东西
}seqstack;
//创建一个栈
seqstack * Creat_stack();
//置栈空
status Setnull(seqstack *s);
//判栈空
status Empty(seqstack *s);
//进栈
//首先判断栈是否满了
status Push(seqstack *s,int x);
//退栈
//首先判断栈是否空了,返回被删值
status Pop(seqstack *s);
//取栈顶
//首先判断栈是否空了,返回栈顶值
status Pop(seqstack *s);
main.c
#include<stdio.h>
#include"stack.h"
int main()
{
int i=0;
//打算创建两个栈,p,q
seqstack *q;
//创建第一个栈q
q=Creat_stack();
for(i=0;i<maxsize;i++)
{
//把3入q栈,并打印OK
if(Push(q,3))
printf("OK\n");
}
return TRUE;
}
观察地址和内存的分配
栈q首地址 0x00242f20
64个int类型数据数组data,256字节+1个int类型top,4字节
int 4个字节,4个地址,64+1=65个int,65x4=260字节,260地址
首地址即数据data的首地址
top的地址,243020-242f20=256
top四个字节,它的地址是,首地址+260-4(同一为十六进制)=242f20+104-4=243020
栈空间的尾地址是 243024
(二)链栈
不要恋战,。。。。。。。。。
如果前面顺序栈,都能理解这里链栈,那就是链了,单链表的链。但这个单链表要满足LIFO,就是给它加上限制而已。
然后既然是单链表,则没有个数的限制,动态产生的。malloc函数。
先看定义吧
typedef struct node
{
datatype data;
struct node *next;
}Linklist;
Linklist *top;
我把它归到了单链表里。只不过是头插法的单链表,尾结点指向空。top做栈顶指针,也是栈的入口。
当top==NULL说明空栈。
实现以下建栈,入栈出栈
//链栈建栈,入栈与出栈
//建栈(栈顶指针是结点的指针域,如果为NULL,则为空栈)
//采用头插法建立链栈,其实就是单链表
//建立一个结点存入数据,指针域指向空结点
//返回栈顶指针
Linklist * creat_linkstack(int x)
{
//p为数据结点,top栈顶指针
Linklist *p,*top;
top=NULL;
p=(Linklist *)malloc(sizeof(Linklist));//生成新节点
p->data=x;
p->next=top; //指向空结点
return p; //返回栈顶指针
}
//入栈
Linklist * pushlstack(Linklist * s,int x)
{
Linklist *p;
p=(Linklist *)malloc(sizeof(Linklist));//生成新节点
p->data=x;
p->next=s;//新节点指向原结点
return p;
}
//出栈
Linklist * poplstack(Linklist * s)
{
Linklist * p;
if(s->next==NULL)
{
printf("under flow");
return NULL;
}
else
{
p=s->next;//指向下一个节点
free(s);//
return p;
}
}
验证OK