C -- 栈

什么是栈(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);
}

测试接口

略。。。。
链表类型的也已经写过很多次了,这里就不测试了。
仅个人的一些想法,有错误的地方还请大佬指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值