数据结构学习记录07——栈的定义及实现

1.栈的定义及性质

  栈是一种特殊的线性表,是限定仅在表尾进行插入或删除操作的线性表。
  栈仅能在线性表的一端进行操作,因此,对于栈来说,栈顶(Top)是允许操作的一端,栈底(Bottom)是不允许操作的一端。
  栈的性质可以用四个字来概括,那就是后进先出(LIFO),Last In First Out,如下图所示。
在这里插入图片描述

2.栈的操作

  栈的实现方式通常有两种方法,分别是顺序结构和链式结构,因此,为了实现代码的复用,我们首先分别将之前写的链表的顺序存储结构和链式存储结构的头文件和.c文件加入到工程中。

2.1.创建栈

  在创建顺序栈之前,先对数据进行封装。

typedef void SeqStack;

  接着通过调用之前的顺序链表的创建函数来创建顺序栈,代码为:

SeqStack* SeqStack_Create(int capacity)
{
	return SeqList_Create(capacity);
}

  在创建链式栈之前,也要先对数据进行封装。

typedef void LinkStack;

  与顺序栈类似,调用之前单链表的创建函数来创建链式栈,

LinkStack* LinkStack_Create()
{
	return LinkList_Create();
}

2.2.销毁栈

  销毁顺序栈直接调用顺序链表的销毁函数,

void SeqStack_Destroy(SeqStack* stack)
{
	SeqList_Destroy(stack);
}

  链式栈的销毁就不能直接free掉,而是要先清空,再进行free操作。

void LinkStack_Destroy(LinkStack* stack)
{
	LinkStack_Clear(stack);
	LinkList_Destroy(stack);
}

2.3.清空栈

  对于顺序栈而言,我们可以直接调用顺序链表中的清空函数,

void SeqStack_Clear(SeqStack* stack)
{
	SeqList_Clear(stack);
}

  对于链式栈而言,由于每一个元素都是malloc得到的,直接清空会产生内存泄漏。

void LinkStack_Clear(LinkStack* stack)
{
	//由于链式栈中的每一个元素都是malloc得到的,直接clear会产生内存泄露
	while(LinkStack_Size(stack) > 0)
	{
		LinkStack_Pop(stack);
	} 
}

2.4.进栈

  进栈相当于将元素插入到栈顶的位置,对于顺序栈而言,我们可以直接调用顺序链表里的插入元素函数。

int SeqStack_Push(SeqStack* stack, void* item)
{
	return SeqList_Insert(stack, item, SeqList_Length(stack));
}

对于链式栈而言,我们要动态地申请表头结点,进行合法性判断以后开始进栈,

int LinkStack_Push(LinkStack* stack, void* item)
{
	TLinkStackNode* node = (TLinkStackNode*)malloc(sizeof(TLinkStackNode));		//动态地申请表头结点	
	int ret = (node != NULL) && (item != NULL);
	
	if (ret)
	{
		node -> item = item;
		ret = LinkList_Insert(stack, (LinkListNode*)node, 0);					//开始压栈 
	} 
	
	if (!ret)																	//如果压栈未成功
	{
		free(node);
	} 
	
	return ret;
}

2.5.出栈

  对于顺序栈,我们通过调用顺序表中的删除函数来实现其出栈,

void* SeqStack_Pop(SeqStack* stack)
{
	return SeqList_Delete(stack, SeqList_Length(stack) - 1);
}

  对于链式栈,我们调用单链表的删除函数来实现其出栈,

void* LinkStack_Pop(LinkStack* stack)
{
	TLinkStackNode* node = (TLinkStackNode*)LinkList_Delete(stack, 0);
	void* ret = NULL;
	
	if (node != NULL)															//如果出栈的元素为空 
	{
		ret = node -> item;														//返回元素的地址
		free(node); 
	}
	
	return ret;
}

2.6.获取栈顶元素

  对于顺序栈而言,

void* SeqStack_Top(SeqStack* stack)
{
	return SeqList_Get(stack, SeqList_Length(stack) - 1);
}

  对于链式栈而言,

void* LinkStack_Top(LinkStack* stack)
{
	TLinkStackNode* node = (TLinkStackNode*)LinkList_Get(stack, 0);
	void* ret = NULL;
	
	if (node != NULL)															
	{
		ret = node -> item;														//返回元素的地址
	}
	
	return ret;
}

2.7.获取栈的大小

  对于顺序栈而言,

int SeqStack_Size(SeqStack* stack)
{
	return SeqList_Length(stack);
}
int SeqStack_Capacity(SeqStack* stack)
{
	return SeqList_Capacity(stack);
}

  对于链式栈而言,

int LinkStack_Size(LinkStack* stack)
{
	return LinkList_Length(stack);	
}

3.测试

  我们首先对顺序栈进行测试,

#include <stdio.h>
#include <stdlib.h>
#include "SeqStack.h"

int main(int argc, char *argv[]) 
{
	SeqStack* stack = SeqStack_Create(20);
	int a[10] = {0};
	int i;
	
	for (i = 0; i < 10; i++)
	{
		a[i] = i;
		SeqStack_Push(stack, a + i);
	} 
	
	printf("Top: %d\n", *(int*)SeqStack_Top(stack));
	printf("Capacity: %d\n", SeqStack_Capacity(stack));
	printf("Length: %d\n", SeqStack_Size(stack));
	
	while(SeqStack_Size(stack) > 0)
	{
		printf("Pop: %d\n", *(int*)SeqStack_Pop(stack));
	}
	
	return 0;
}

  得到的结果为:
在这里插入图片描述
  接着对链式栈进行测试,

#include <stdio.h>
#include <stdlib.h>
#include "LinkStack.h"

int main(int argc, char *argv[]) 
{
	LinkStack* stack = LinkStack_Create();
	int a[10] = {0};
	int i;
	
	for (i = 0; i < 10; i++)
	{
		a[i] = i;
		LinkStack_Push(stack, a + i);
	}
	
	printf("Top: %d\n", *(int*)LinkStack_Top(stack));
	printf("Size: %d\n", LinkStack_Size(stack));
	
	LinkStack_Clear(stack);
	
	while(LinkStack_Size(stack) > 0)
	{
		printf("Pop: %d\n", *(int*)LinkStack_Pop(stack));
	}
	
	LinkStack_Destroy(stack);
	
	return 0;
}

  得到的结果为:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值