链栈的表示与实现(第三章)

链栈的表示与实现

 

栈也是线性表,是操作受限的线性表。栈的操作是线性表操作的子集。因此,也可以将线性表的结构作为栈的结构。

下面,就是把带头结点的线性单链表结构作为链栈的结构,这样,线性单链表的一些基本操作就可以直接用于链栈的操作了。

例如,初始化链表和初始化链栈的操作是一样的。需要注意的是,由于栈的操作被限定仅在栈顶进行,显然,令表头为栈顶可简化栈的操作。

 


typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
typedef int SElemType; /* 定义栈元素的类型 */

#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */

/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2 


/* --------------------------   链栈存储表示   -----------------------------*/

 /* 栈结点类型和链表结点类型一致  */
struct LNode
{
	SElemType data;
	struct LNode *next;
};
typedef struct LNode *LinkStack; /* LinkStack是指向栈结点的指针类型 */

/* ----------------------------------------------------------------------------*/


void print(SElemType c)
{
	printf("%d ", c);
}


/* 链栈的基本操作(9个) */

/* --------------------        基本操作的函数原型说明     ---------------------*/
Status InitStack(LinkStack *S);
Status DestroyStack(LinkStack *S);
Status ClearStack(LinkStack S);
Status StackEmpty(LinkStack S);
int StackLength(LinkStack S);
Status Push(LinkStack S, SElemType e);
Status Pop(LinkStack S, SElemType *e);
Status GetTop(LinkStack S, SElemType *e);
Status StackTraverse(LinkStack S, Status(*visit)(SElemType));


/* ---------------------------------             基本操作的实现         ------------------------------------*/


Status InitStack(LinkStack *S)
{ /* 操作结果:构造一个空链栈S */
	*S = (LinkStack)malloc(sizeof(struct LNode)); /* 产生头结点,并使S指向此头结点 */
	if (!*S) /* 存储分配失败 */
		exit(OVERFLOW);
	(*S)->next = NULL; /* 指针域为空 */
	return OK;
}

Status DestroyStack(LinkStack *S)
{ /* 初始条件:链栈S已存在。操作结果:销毁链栈S */
	LinkStack q;
	while (*S)
	{
		q = (*S)->next;
		free(*S);
		*S = q;
	}
	return OK;
}

Status ClearStack(LinkStack S) /* 不改变S */
{ /* 初始条件:链栈S已存在。操作结果:将S重置为空栈 */
	LinkStack p, q;
	p = S->next; /* p指向第一个结点 */
	while (p) /* 没到栈底 */
	{
		q = p->next;
		free(p);
		p = q;
	}
	S->next = NULL; /* 头结点指针域为空 */
	return OK;
}

Status StackEmpty(LinkStack S)
{ /* 初始条件:链栈S已存在。操作结果:若S为空表,则返回TRUE,否则返回FALSE */
	if (S->next) /* 非空 */
		return FALSE;
	else
		return TRUE;
}

int StackLength(LinkStack S)
{ /* 初始条件:链栈S已存在。操作结果:返回S中数据元素个数 */
	int i = 0;
	LinkStack p = S->next; /* p指向第一个结点 */
	while (p) /* 没到表尾 */
	{
		i++;
		p = p->next;
	}
	return i;
}

Status Push(LinkStack S, SElemType e)
{ /* 初始条件:链栈S已存在。操作结果:在S的栈顶插入新的数据元素e,作为栈顶的第一个元素 */
	LinkStack s;
	s = (LinkStack)malloc(sizeof(struct LNode)); /* 生成新结点 */
	s->data = e; /* 给结点赋值 */
	s->next = S->next; /* 插在表头 */
	S->next = s;
	return OK;
}

Status Pop(LinkStack S, SElemType *e)
{ /* 初始条件:链栈S已存在,且有不少于1个元素 */
  /* 操作结果:删除S的栈顶数据元素,并由e返回其值 */
	LinkStack p = S->next;
	if (p)
	{
		*e = p->data;
		S->next = p->next;
		free(p);
		return OK;
	}
	else
		return ERROR;
}

Status GetTop(LinkStack S, SElemType *e)
{ /* 返回栈顶元素的值 */
	LinkStack p = S->next;
	if (!p) /* 空表 */
		return ERROR;
	else /* 非空表 */
		*e = p->data;
	return OK;
}

Status StackTraverse(LinkStack S, Status(*visit)(SElemType))
{ //从栈底到栈顶依次对栈中每个元素调用函数visit()。 
	SElemType e;
	LinkStack temp, p = S;
	InitStack(&temp); //初始化temp栈 
	while (p->next)
	{
		GetTop(p, &e);
		Push(temp, e);
		p = p->next;
	}
	p = temp->next;
	while (p)
	{
		visit(p->data);
		p = p->next;
	}
	printf("\n");
	return OK;
}



/*  检验以上操作的主程序 */

void main()
{
	int j;
	LinkStack s;
	SElemType e;
	if (InitStack(&s))
		for (j = 1; j <= 5; j++)
			Push(s, 2 * j);
	printf("栈中的元素从栈底到栈顶依次为: ");
	StackTraverse(s, print);
	Pop(s, &e);
	printf("弹出的栈顶元素为%d\n", e);
	printf("栈空否: %d(1:空 0:否)\n", StackEmpty(s));
	GetTop(s, &e);
	printf("当前栈顶元素为%d,栈的长度为%d\n", e, StackLength(s));
	ClearStack(s);
	printf("清空栈后,栈空否: %d(1:空 0:否),栈的长度为%d\n", StackEmpty(s), StackLength(s));
	printf("是否销毁栈了: %d(1:是 0:否)\n", DestroyStack(&s));
}

 

运行结果:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值