什么是栈(stack)?
栈,也是一种链表系列的另一种数据结构。和队列恰恰相反。
- 队列(Queue)First in first out,即先进先出,通俗点说就是只能从尾添加,从头开始删。
- 栈(Stack)Last in first out, 即后入先出,通俗点说就是从尾部添加(入栈),只能从尾部开始删除(出栈)。
其实之前学到过一个函数,好像是叫atexit(),参数是一系列函数指针,这个函数的执行就有点像栈的方式,后入列的先执行。(这个说法可能不是很准确)
设计实现一个 Stack ADT
此处再补充一下ADT的概念:
- ADT(Abstrac Data Type),抽象数据类型,指类型的属性和相关操作的抽象描述,这种描述不依赖于特定的实现和编程语言;
以下描述重要步骤,完整Stack.h以及实现Stack.c见文末。
第一步:
- 基本定义
typedef struct _item
{
/* unknown */
}Item;
/* 定义基本单元节点 */
typedef struct _node
{
Item item;
struct _node * next;
}Node;
/* 定义栈类型 */
typedef struct _stack
{
Node * head;
Node * tail;
int size;
}Stack;
- 当然我们也可以写成另一种形式:(相应的其余部分实现会有细微差别,当然也差不多),总之,包括数据Item的定义以及我们要实现的结构的定义。
typedef struct _item
{
/* unknown */
}Item;
/* 定义基本单元节点 */
typedef struct _node
{
Item item;
struct _node * next;
}Node,* head,* tail;
第二步:
- 描述接口,定义接口
/* 定义接口 */
//操作:初始化一个stack
//前置条件:一个指向栈的指针
//后置条件:将栈初始化为空
void InitializeStack(Stack * st);
//操作:确定栈是否为空
//前置条件:一个已初始化的栈的指针
//后置条件:如果为空返回true,否则返回false
bool StackIsEmpty(const Stack * st);
//操作:确定栈是否已满
//前置条件:一个已经初始化的栈的指针
//后置条件:如果栈已满,返回true,否则返回false
bool StackIsFull(const Stack * st);
//操作:入栈
//前置条件:一个已经初始化的栈的指针
//后置条件:将item添加到栈中,如果成功添加,返回true,否则返回false
bool AddToStack(Stack * st, Item item);
//操作:出栈
//前置条件:一个已经初始化的栈的指针
//后置条件:将末尾item弹出,如果成功出栈,返回true,否则返回false
bool OutOneInStack(Stack * st);
//操作:清空栈
//前置条件:一个已经初始化的栈的指针
//后置条件:将栈中item依次弹出,重置Stack类型
void ClearStack(Stack * st);
先简单定义这些,需要别的可以再添加;
第三步:
- 实现接口
static void CopyToStack(Node * p, Item item)
{
p->item = item;
}
void InitializeStack(Stack * st)
{
st->head = st->tail = NULL;
st->size = 0;
}
bool StackIsEmpty(const Stack * st)
{
return st->size == 0;
}
bool StackIsFull(const Stack * st)
{
return st->size == MAXSIZE;
}
bool AddToStack(Stack * st, Item item)
{
//栈已满,提前返回
if(StackIsFull(st))
return false;
Node * pnew = (Node *) malloc (sizeof(Node));
//未分配到,提前返回
if(pnew == NULL)
return false;
pnew->next = NULL;
CopyToStack(pnew,item); //用一个静态函数完成向pnew中添加新item的功能
if(st->head == NULL) //添加第一个
st->head = st->tail = pnew;
else //添加后续
st->tail = st->tail->next = pnew;
st->size++;
return true;
}
bool OutOneInStack(Stack * st)
{
//栈为空,提前返回
if(StackIsEmpty(st))
return false;
Node * p;
if(st->size == 1) //出最后一个,头尾都要指向NULL
{
free(st->tail);
st->head = st->tail = NULL;
}else{ //出栈后还有item,头不动
//找栈尾的上一个
for(p = st->head;p->next != st->tail;p = p->next)
;
p->next = NULL;
free(st->tail);
st->tail = p;
}
st->size--;
return true;
}
void ClearStack(Stack * st)
{
if(StackIsEmpty(st))
fprintf(stderr, "Can't clear a empty stack!\n", );
while(!StackIsEmpty(st))
OutOneInStack(st);
}
“Stack.h”
//Stack.h
#ifndef STACK_H_
#define STACK_H_
#include <stdbool.h>
#define MAXSIZE 10 //栈最大存储数量
/* 定义数据属性 */
typedef struct _item
{
/* unknown */
}Item;
/* 定义基本单元节点 */
typedef struct _node
{
Item item;
struct _node * next;
}Node;
/* 定义栈类型 */
typedef struct _stack
{
Node * head;
Node * tail;
int size;
}Stack;
/* 定义接口 */
//操作:初始化一个stack
//前置条件:一个指向栈的指针
//后置条件:将栈初始化为空
void InitializeStack(Stack * st);
//操作:确定栈是否为空
//前置条件:一个已初始化的栈的指针
//后置条件:如果为空返回true,否则返回false
bool StackIsEmpty(const Stack * st);
//操作:确定栈是否已满
//前置条件:一个已经初始化的栈的指针
//后置条件:如果栈已满,返回true,否则返回false
bool StackIsFull(const Stack * st);
//操作:入栈
//前置条件:一个已经初始化的栈的指针
//后置条件:将item添加到栈中,如果成功添加,返回true,否则返回false
bool AddToStack(Stack * st, Item item);
//操作:出栈
//前置条件:一个已经初始化的栈的指针
//后置条件:将末尾item弹出,如果成功出栈,返回true,否则返回false
bool OutOneInStack(Stack * st);
//操作:清空栈
//前置条件:一个已经初始化的栈的指针
//后置条件:将栈中item依次弹出,重置Stack类型
void ClearStack(Stack * st);
#endif
Stack.c
//Stack.c
#include <stdio.h>
#include <stdlib.h>
#include "Stack.h"
static void CopyToStack(Node * p, Item item)
{
p->item = item;
}
void InitializeStack(Stack * st)
{
st->head = st->tail = NULL;
st->size = 0;
}
bool StackIsEmpty(const Stack * st)
{
return st->size == 0;
}
bool StackIsFull(const Stack * st)
{
return st->size == MAXSIZE;
}
bool AddToStack(Stack * st, Item item)
{
//栈已满,提前返回
if(StackIsFull(st))
return false;
Node * pnew = (Node *) malloc (sizeof(Node));
//未分配到,提前返回
if(pnew == NULL)
return false;
pnew->next = NULL;
CopyToStack(pnew,item); //用一个静态函数完成向pnew中添加新item的功能
if(st->head == NULL) //添加第一个
st->head = st->tail = pnew;
else //添加后续
st->tail = st->tail->next = pnew;
st->size++;
return true;
}
bool OutOneInStack(Stack * st)
{
//栈为空,提前返回
if(StackIsEmpty(st))
return false;
Node * p;
if(st->size == 1) //出最后一个,头尾都要指向NULL
{
free(st->tail);
st->head = st->tail = NULL;
}else{ //出栈后还有item,头不动
//找栈尾的上一个
for(p = st->head;p->next != st->tail;p = p->next)
;
p->next = NULL;
free(st->tail);
st->tail = p;
}
st->size--;
return true;
}
void ClearStack(Stack * st)
{
if(StackIsEmpty(st))
fprintf(stderr, "Can't clear a empty stack!\n", );
while(!StackIsEmpty(st))
OutOneInStack(st);
}
测试接口
略。。。。
链表类型的也已经写过很多次了,这里就不测试了。
仅个人的一些想法,有错误的地方还请大佬指正。