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
    评论
顺序是一种基于数组实现的,它的特点是具有随机存取的特性。顺序的基本运算包括进、出和查看顶元素。进操作将元素插入到顶,出操作将顶元素删除并返回,查看顶元素操作返回顶的元素值,但不修改的状态。 在C语言中,顺序的存储结构可以使用一个一维数组来存放中的元素,同时使用一个指示器top来指示顶的位置。在进行进和出操作时,需要更新top的值,使其指向顶元素。 下面是一种常见的顺序的定义和基本操作的示例代码: ```c // 定义中元素的数据类型 typedef int StackElementType; // 定义顺序的存储结构 #define Stack_Size 100 // 的最大容量 typedef struct { StackElementType elem[Stack_Size]; // 用数组存放中元素 int top; // 顶指针 } SeqStack; // 初始化顺序 void Init_SeqStack(SeqStack *S) { S->top = -1; // 初始时为空,顶指针置为-1 } // 进操作 void Push_SeqStack(SeqStack *S, StackElementType x) { if (S->top == Stack_Size - 1) { printf("已满,无法进"); return; } S->top++; // 顶指针加1 S->elem[S->top] = x; // 将新元素放入顶位置 } // 出操作 StackElementType Pop_SeqStack(SeqStack *S) { if (S->top == -1) { printf("为空,无法出"); return -1; // 返回一个特殊值表示出错 } StackElementType x = S->elem[S->top]; // 获取顶元素的值 S->top--; // 顶指针减1 return x; // 返回顶元素的值 } // 查看顶元素 StackElementType GetTop_SeqStack(SeqStack *S) { if (S->top == -1) { printf("为空"); return -1; // 返回一个特殊值表示出错 } return S->elem[S->top]; // 返回顶元素的值 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值