栈和线性表很相似,不仅有顺序存储表示也有链式存储表示,而且其创建删除都一样。只是栈的操作方面有如下的特点:
(01) 栈中数据是按照"后进先出(LIFO, Last In First Out)"方式进出栈的。
(02) 向栈中添加/删除数据时,只能从栈顶进行操作。
栈通常包括的三种操作:push、peek、pop。
push -- 向栈中添加元素。
peek -- 返回栈顶元素。
pop -- 返回并删除栈顶元素的操作。
一:顺序存储表示
栈的示意图
1:栈的顺序存储结构表示:
#define STACKINITSIZE 100
#define STACKINCREMENT 10
typedef struct{
SElemType *base;
SElemType *top;
int stacksize;
}SqStack;
这里需要注意的一点是:顺序存储只需要创建依次结构体,而这个结构体里面的指针不是指向该类型的结构体的(与链表不同),而是只想SElemType类型的数组的!创建的一个数组的信息,全在这个结构体里面表示。
2:栈的初始化
Stack stack_init(SqStack *S)
{
S->base = (SElemType *)malloc(STACKINITSIZE * sizeof(SElemType));
if(!(S->base))
exit(-1);
S->top = S->base;
S->stacksize = STACKINITSIZE;
return 1;
}
3:取得栈顶元素
由于栈顶指针top指向栈顶元素的下一个位置,因此取元素、插入元素以及删除元素都要留意数组索引的变化。同时还要判断栈是否为空,或者是否已满,然后再进行操作。
Status get_top(SqStack S,SElemType *e)
{
if(S->top == S->base)
return 0;
*e = *(S->top - 1);
return 1;
}
4:插入元素
Status push(SqStack *S,SElemType e)
{
//判断元素空间十分充足
if(S->top - S->base >= S->stacksize){
S->base = (SElemType *)realloc(S->base,
(S->stacksize + STACKINCREMENT)*sizeof(SElemType));
if(!(s->base))
exit(-1);
S->top = S->base + S->stacksize;
S->stacksize += STACKINCREMENT;
}
*(S->top) = e;
S->top++;
return 1;
}
5:删除元素
Status pop(SqStack *S,SElemType *e)
{
if(S->top == S->base)
return 0;
*e = *(--S->top);
return 1;
}
评注:
栈、队列等其实就是一种工具,看你如何去用,如何去实现。这方式就有很多了。比如也可以用下面的方式来声明一个栈
#define MAXSIZE 200
struct seqstack
{
Elemtype data[MAXSIZE];
int top;
};
struct seqstack *s; //定义一个指向顺序栈的指针
二:链式存储表示
当我们建立链表的时候,可以再表头插入结点也可以在表尾插入结点。那么在实现栈的时候,我们选择在表头插入结点,就能很好的实现我们想要的操作。但是,这里不需要头结点,只需要一个头指针就可以了。
1:单链表的结点
// 单向链表的“节点”
struct node {
int val;
struct node* next;
};
// 单向链表的“表头”
static struct node *phead=NULL;
2:创建结点(这里不用初始化,单链表时有表头,需要初始化)
// 创建节点,val为节点值
static struct node* create_node(int val)
{
struct node *pnode=NULL;
pnode = (struct node*)malloc(sizeof(struct node));
if (!pnode)
return NULL;
pnode->val = val;
pnode->next = NULL;
return pnode;
}
3:插入和删除的实现
// 将val插入到链表的表头位置
static struct node* push(int val)
{
struct node *pnode = NULL;
pnode = create_node(val);
pnode->next = phead;
phead = pnode;
return phead;
}
// 删除链表的表头
static int pop()
{
if (!phead)
{
printf("remove failed! link is empty!");
return -1;
}
int ret;
struct node *pnode;
ret = phead->val;
pnode = phead;
phead = phead->next;
free(pnode);
return ret;
}
栈的链式存储实现代码
#include <stdio.h>
#include <malloc.h>
/**
* C 语言: 单向链表实现的栈,只能存储int数据。
*
* @author skywang
* @date 2013/11/07
*/
// 单向链表的“节点”
struct node {
int val;
struct node* next;
};
// 单向链表的“表头”
static struct node *phead=NULL;
// 创建节点,val为节点值
static struct node* create_node(int val)
{
struct node *pnode=NULL;
pnode = (struct node*)malloc(sizeof(struct node));
if (!pnode)
return NULL;
pnode->val = val;
pnode->next = NULL;
return pnode;
}
// 销毁单向链表
static int destroy_single_link()
{
struct node *pnode=NULL;
while (phead != NULL) {
pnode = phead;
phead = phead->next;
free(pnode);
}
return 0;
}
// 将val插入到链表的表头位置
static struct node* push(int val)
{
struct node *pnode = NULL;
pnode = create_node(val);
pnode->next = phead;
phead = pnode;
return phead;
}
// 删除链表的表头
static int pop()
{
if (!phead)
{
printf("remove failed! link is empty!");
return -1;
}
int ret;
struct node *pnode;
ret = phead->val;
pnode = phead;
phead = phead->next;
free(pnode);
return ret;
}
// 返回链表的表头节点的值
static int peek()
{
if (!phead)
{
printf("peek failed! link is empty!");
return -1;
}
return phead->val;
}
// 返回链表中节点的个数
static int size()
{
int count=0;
struct node *pnode=phead;
while (pnode != NULL) {
pnode = pnode->next;
count++;
}
return count;
}
// 链表是否为空
static int is_empty()
{
return phead==NULL;
}
// 打印“栈”
static void print_single_link()
{
if (is_empty())
{
printf("stack is Empty\n");
return 0;
}
printf("stack size()=%d\n", size());
struct node *pnode=NULL;
while (phead != NULL) {
printf("%d\n", phead->val);
pnode = phead;
phead = phead->next;
free(pnode);
}
}
void main()
{
int tmp=0;
// 将10, 20, 30 依次推入栈中
push(10);
push(20);
push(30);
//print_single_link(); // 打印栈
// 将“栈顶元素”赋值给tmp,并删除“栈顶元素”
tmp = pop();
printf("tmp=%d\n", tmp);
//print_single_link(); // 打印栈
// 只将“栈顶”赋值给tmp,不删除该元素.
tmp = peek();
printf("tmp=%d\n", tmp);
//print_single_link(); // 打印栈
push(40);
print_single_link(); // 打印栈
// 销毁栈
destroy_single_link();
}
三:双向链表实现的栈,能存储任意类型的数据
推荐看:栈的图文解析
另外推荐:栈的顺序存储和链式存储