数据结构---栈的概念及顺序栈入栈、出栈等操作的实现(C语言)


本文中所涉及的完整代码及测试代码等已提交至gitee,可以点击此链接查看参考。
因为本人是编程初学者,文中及代码中难免出现错误,请同志们批评指正!
在这里插入图片描述


🎄栈的基本概念

image.png
上图是一个羽毛球筒,它只有一端开口,羽毛球在其中挨个存放,如果我们想往里面放入一只羽毛球,只能从开口处放进去,而不能随意插入。如果我们想拿出一只羽毛球,也只能从开口拿到最靠近开口的那一个,而不能越过第一个去随便拿中间的。其实这就是对栈这种数据结构的一个形象描述。

我们先对栈下一个结论:栈(stack)是仅允许在表尾进行插入和删除操作的线性表。
我们把允许插入和删除的一端称为栈顶(top), 另一端称为栈底(bottom), 不含任何数据元素的栈称为空栈。栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构。

对于栈的定义如何理解呢?
首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。
它的特殊之处就在于限制了这个线性表的插入和删除位置,它始终只在栈顶进行。这也就使得栈底是固定的,最先进栈的只能在栈底。
栈的插入操作,叫作进栈,也称压栈、入栈。
栈的删除操作,叫作出栈,也有的叫作弹栈。

对于栈来讲,理论上线性表的操作特性它都具备,但是因为其结构的特殊性,所以插入删除这两个操作会与线性表有不同。但它到底还是一个线性表,因此根据存储结构,栈也分为顺序栈和链式栈,它们的基本思路和我们之前说的线性表和链表是几乎一样的。下面我们来看看顺序栈和链式栈的实现。


🎄顺序栈及其操作的实现

image.png

顺序表是用类似于数组的结构来实现的,顺序栈的实现也应该如此。观察上图,就是一个顺序栈的模型。
因为顺序栈中我们的栈的大小是动态的,所存储的元素个数也是动态的,因此我们需要一个变量top来代表栈顶,元素入栈则top+1,一个元素出栈则top-1。由此可以对比顺序表的结构定义初步构想出栈的结构定义:

typedef int data_t;

typedef struct
{
	data_t* data;//栈内数据
	int top;//栈顶位置下标,栈顶指针
	int cap;//栈中能容纳元素数量
}sqstack, * pstack;

与其他数据结构相同,我们需要实现以下操作:

  1. 顺序栈的初始化;
  2. 顺序栈入栈操作;
  3. 顺序栈出栈操作;
  4. 判断顺序栈是否空;
  5. 判断顺序栈是否满;
  6. 遍历打印顺序栈中元素;
  7. 清空顺序栈中元素;
  8. 计算顺序栈元素个数;
  9. 动态内存释放;

⭐1.顺序栈的初始化

对于顺序栈的创建与初始化,我们需要考虑使用malloc来申请动态内存空间来存放我们的栈及栈中数据。因此应该需要两次malloc:

  1. malloc申请动态内存空间来管理维护栈结构;
  2. malloc申请动态内存空间来管理维护栈中数据;
  3. 对申请的空间中的内容进行初始化:数据置空、top置-1、cap置初始值。

为了实现空间的有效利用,这里在为栈的数据申请空间的时候,应该由用户来指定这个栈中能存放多少个data_t类型的数据,即cap得值由用户指定,用多少就申请多少的空间。
top为什么要置为-1呢?因为top是栈顶指针,是栈顶元素得下标,如果栈中有一个元素,那应该是在下标为0的位置。没有元素,那top自然要置为-1。

//1. 顺序栈的初始化;
/*
* @return      init success:栈指针   init failed:NULL
* @para        maxlen:栈内元素最大数量由用户指定
*/
pstack sqstack_init(int maxlen)
{
	//1.给栈申请动态内存
	pstack s = (pstack)malloc(sizeof(sqstack));
	if (s == NULL)
	{
		printf("\nstack init failed\n");
		return NULL;
	}

	//2.给栈中的数据data申请动态内存:
	s->data = (data_t*)malloc(maxlen * sizeof(data_t));
	if (s->data == NULL)
	{
		printf("\nS->data malloc failed\n");
		free(s);
		s = NULL;
		return NULL;
	}

	//3.数据初始化:
	memset(s->data, 0, maxlen * sizeof(data_t));//栈中数据置0
	s->top = -1;
	s->cap = maxlen;

	return s;
}

⭐2.顺序栈入栈操作

入栈就是从栈顶向栈内存入一个元素,那么在存入之前应该先判断栈是不是存在,如果存在判断栈是不是满了,满了的话就不能再存入了。步骤如下:

  1. 判断栈是否存在;
  2. 判断栈是不是满了;
  3. 没满往里面存入数据:s->data[top] = val;
  4. 栈顶指针top+1;
//2. 顺序栈入栈操作;
/*
* @return      -1:failed     0:success
* @para        s:ptr to stack    val:data to push
*/
int sqstack_push(pstack s, data_t val)
{
	//1.判断栈存不存在:
	if (s == NULL)
	{
		printf("\nstack is not exist\n");
		return -1;
	}

	//2.判断栈满没满:
	if (s->top == s->cap - 1)
	{
		printf("\nstack is full\n");
		return -1;
	}

	//3.开始存:
	s->top++;//栈顶指针先+1,腾出一个空地方存数据
	s->data[s->top] = val;

	return 0;
}

⭐3.顺序栈出栈操作

和入栈的操作相反,先给当前栈顶元素置0,清除掉当前栈顶元素。然后让top–,即让栈顶下降一格,说明栈中元素少了一个。在执行上述操作之前,依旧需要判断栈存不存在,也要判断栈空不空,空了就不能再出栈了。

//3. 顺序栈出栈操作;
/*
* @return      -1:failed     
* @para        s:ptr to stack   
*/
data_t sqstack_pop(pstack s)
{
	//1.判断栈存不存在:
	if (s == NULL)
	{
		printf("\nstack is not exist\n");
		return -1;
	}

	//2.判断栈空不空:
	if (s->top == -1)
	{
		printf("\nstack is empty\n");
		return -1;
	}

	//弹出栈顶元素:
	data_t tmp = s->data[s->top];
	memset(&(s->data[s->top]), 0, sizeof(data_t));//清空
	s->top--;
	return tmp;//返回那个被弹出栈的元素
}

⭐4.判断顺序栈是否空

只需判断top的值即可。

//4. 判断顺序栈是否空;
int sqstack_is_empty(pstack s)
{
	//判断栈存不存在:
	if (s == NULL)
	{
		printf("\nstack is not exist\n");
		return -1;
	}

	if (-1 == s->top)
	{
		printf("\nstack is empty\n");
	}
	return 0;
}

⭐5.判断顺序栈是否满

同样判断cap和top的关系:

//5. 判断顺序栈是否满;
int sqstack_is_full(pstack s)
{
	//判断栈存不存在:
	if (s == NULL)
	{
		printf("\nstack is not exist\n");
		return -1;
	}

	if (s->cap - 1 == s->top)
	{
		printf("\nstack is full\n");
	}
	return 0;
}

⭐6.遍历打印顺序栈中元素

//6. 遍历打印顺序栈中元素;
/*
* @return      void 
* @para        s:ptr to stack   
*/
void sqstack_show(pstack s)
{
	//判断栈存不存在:
	if (s == NULL)
	{
		printf("\nstack is not exist\n");
		return ;
	}

	//判断栈空不空:
	if (-1 == s->top)
	{
		printf("\nstack is empty\n");
		return;
	}

	for (int i = 0; i <= s->top; i++)
	{
		printf("%d ", s->data[i]);
	}

	return;
}

⭐7.清空顺序栈中元素

和初始化一样,将data全部置0,将top置为-1

//7. 清空顺序栈中元素;
int sqstack_clear(pstack s)
{
	//判断栈存不存在:
	if (s == NULL)
	{
		printf("\nstack is not exist\n");
		return -1;
	}
	//判断栈空不空:
	if (-1 == s->top)
	{
		printf("\nstack is empty\n");
		return -1;
	}
	memset(s->data, 0, (s->top + 1) * sizeof(data_t));
	s->top = -1;
	return 0;
}

⭐8.计算顺序栈元素个数

返回top+1即可。


//8. 计算顺序栈元素个数;
int sqstack_len(pstack s)
{
	//判断栈存不存在:
	if (s == NULL)
	{
		printf("\nstack is not exist\n");
		return -1;
	}

	return s->top + 1;
}

⭐9.动态内存释放

这里注意的是,先申请的先释放,注意malloc和free的配对。几个malloc就应该几个free。

//9. 动态内存释放;
int sqstack_free(pstack s)
{
	//判断栈存不存在:
	if (s == NULL)
	{
		printf("\nstack is not exist\n");
		return -1;
	}

	if (s->data != NULL)
	{
		free(s->data);
		s->data = NULL;
	}
	free(s);
	s = NULL;
	return 0;
}
  • 8
    点赞
  • 47
    收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

羟基与苯

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值