数据结构--栈的实现(C语言)

声明

以下内容仅供学习,如有侵权,联系作者删除。
参考文献:王道考研系列数据结构、B站up主:C语言技术网
链接: C语言技术网

一 栈的基本概念

1.栈的定义

栈(Stack):只允许在一端进行插入或删除的线性表。
栈顶(Top):线性表允许进行插入和删除的那一端。
栈底(Bottom):固定的,不允许进行插入和删除的另一端。
空栈:不含任何元素的空表。

2.栈的基本操作

由以下代码给出。

二 栈的顺序存储结构

代码.

/*
 * 程序名:seqstack1.c,此程序演示顺序栈的实现,数据元素是整数。
 * 作者:jack 日期:20210616
 * 参考作者:C语言技术网(www.freecplus.net), B站UP主:C语言技术网
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXSIZE 10       // 顺序栈的最大长度。

typedef int ElemType;   // 自定义顺序栈的数据元素为整数。

typedef struct
{
	ElemType data[MAXSIZE];  // 用数组存储顺序栈中的元素。
	int top;                 // 栈顶指针,从0到MAXSIZE-1,-1表示空栈。
							 // 也可以从1到MAXSIZE,0表示空栈。
}Seqstack, *PSeqStack;

// 顺序栈SS的初始化操作。
void InitStack(PSeqStack SS);

// 清空顺序栈。
void ClearStack(PSeqStack SS);

// 求顺序栈的长度,返回值:栈SS中元素的个数。
int Length(PSeqStack SS);

// 判断顺序栈是否已满,返回值:1-已满,0-未满或失败。
int IsFull(PSeqStack SS);

// 判断顺序栈是否为空,返回值:1-空,0-非空或失败。
int IsEmpty(PSeqStack SS);

// 元素入栈,返回值:0-失败;1-成功。
int Push(PSeqStack SS, ElemType *ee);

// 元素出栈,返回值:0-失败;1-成功。
int Pop(PSeqStack SS, ElemType *ee);

// 获取栈顶元素,返回值:0-失败;1-成功。
// 只查看栈顶元素的值,元素不出栈。
int GetTop(PSeqStack SS, ElemType *ee);

// 打印顺序栈中全部的元素。
void PrintStack(PSeqStack SS);

// 销毁顺序栈SS。
void DestroyStack(PSeqStack SS);

int main()
{
	Seqstack S;  // 创建顺序栈。

	InitStack(&S);

	printf("栈的长度是%d\n", Length(&S));
	ElemType e;     // 创建一个数据元素。

	printf("元素(1、2、3、4、5、6、7、8、9、10)入栈。\n");
	e = 1;  Push(&S, &e);
	e = 2;  Push(&S, &e);
	e = 3;  Push(&S, &e);
	e = 4;  Push(&S, &e);
	e = 5;  Push(&S, &e);
	e = 6;  Push(&S, &e);
	e = 7;  Push(&S, &e);
	e = 8;  Push(&S, &e);
	e = 9;  Push(&S, &e);
	e = 10; Push(&S, &e);

	printf("栈的长度是%d\n", Length(&S));

	// 只查看栈顶元素的值,元素不出栈。
	if (GetTop(&S, &e) == 1)  printf("栈顶的元素值为%d\n", e);

	PrintStack(&S);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);

	// 当所有元素出栈后
	
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);
	if (Pop(&S, &e) == 1)  printf("出栈的元素值为%d\n", e);

	return 0;
}

// 顺序栈SS的初始化操作。
void InitStack(PSeqStack SS)
{
	ClearStack(SS); // 清空顺序栈。
}

// 清空顺序栈。
void ClearStack(PSeqStack SS)
{
	if (SS == NULL) return; // 检查空指针。
	SS->top = -1;  // 栈顶指针置为-1。
	memset(SS->data, 0, sizeof(ElemType)*MAXSIZE);
}

// 求顺序栈的长度,返回值:栈SS中元素的个数。
int Length(PSeqStack SS)
{
	if (SS == NULL) return 0; // 检查空指针。
	return SS->top + 1;
}

// 判断顺序栈是否已满,返回值:1-已满,0-未满或失败。
int IsFull(PSeqStack SS)
{
	if (SS == NULL) return 0;  // 检查空指针。

	if (SS->top >= MAXSIZE - 1) return 1;

	return 0;
}

// 判断顺序栈是否为空,返回值:1-空,0-非空或失败。
int IsEmpty(PSeqStack SS)
{
	if (SS == NULL) return 0;  // 检查空指针。

	if (SS->top == -1) return 1;
	return 0;
}

// 元素入栈,返回值:0-失败;1-成功。
int Push(PSeqStack SS, ElemType *ee)
{
	if ((SS == NULL) || (ee == NULL)) return 0;  // 检查空指针。

	if (IsFull(SS) == 1)
	{
		printf("顺序栈已满,不能插入。\n"); return 0;
	}

	SS->top++;  // 栈指针先加1。
	memcpy(&SS->data[SS->top], ee, sizeof(ElemType));  // 用数组的下标访问。
	return 1;
}

// 元素出栈,返回值:0-失败;1-成功。
int Pop(PSeqStack SS, ElemType *ee)
{
	if ((SS == NULL) || (ee == NULL)) return 0;  // 检查空指针。

	if (IsEmpty(SS) == 1) { printf("栈为空。\n"); return 0; }

	memcpy(ee, SS->data + SS->top, sizeof(ElemType));  // 采用指针运算也可以。
	SS->top--;  // 栈指针1。

	return 1;
}

// 获取栈顶元素,返回值:0-失败;1-成功。
// 只查看栈顶元素的值,元素不出栈。
int GetTop(PSeqStack SS, ElemType *ee)
{
	if ((SS == NULL) || (ee == NULL)) return 0;  // 检查空指针。

	if (IsEmpty(SS) == 1) { printf("栈为空。\n"); return 0; }

	memcpy(ee, SS->data + SS->top, sizeof(ElemType));  // 采用指针运算也可以。

	return 1;
}

// 打印顺序栈中全部的元素。
void PrintStack(PSeqStack SS)
{
	if (SS == NULL) return;  // 检查空指针。

	if (SS->top == -1) { printf("栈为空。\n"); return; }

	int kk;
	for (kk = 0; kk <= SS->top; kk++)
	{
		printf("SS[%d],value=%d\n", kk, SS->data[kk]);     // 用数组的下标访问。
		// printf("SS[%d],value=%d\n",kk,*(SS->data+kk));   // 采用指针运算也可以。
	}
}

// 销毁顺序栈SS。
void DestroyStack(PSeqStack SS)
{
	// 静态顺序栈无需释放内存,不需要销毁操作。

	ClearStack(SS); // 清空顺序栈。

	return;
}

顺序栈运行结果如下:
visual studio 2017

三 栈的链式存储结构

代码.

/*
* 程序名:seqstack1.c,此程序演示链栈的实现,数据元素是整数。
* 作者:jack 日期:20210616
* 参考作者:C语言技术网(www.freecplus.net), B站UP主:C语言技术网
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef int ElemType;    // 自定义链栈的数据元素为整数。

typedef struct SNode
{
   ElemType data;       // 链栈中的元素。
   struct SNode *next;  // 指向下一个结点的指针。
}SNode, *LinkStack;

// 链栈SS的初始化操作,分配头结点,返回头结点的地址。
SNode *InitStack();

// 销毁链栈SS。
void DestroyStack(LinkStack SS);

// 元素入栈,返回值:0-失败;1-成功。
int Push(LinkStack SS, ElemType *ee);

// 元素出栈,返回值:0-失败;1-成功。
int Pop(LinkStack SS, ElemType *ee);

// 求链栈的长度,返回值:栈SS中元素的个数。
int  Length(LinkStack SS);

// 清空链栈。
void Clear(LinkStack SS);

// 判断链栈是否为空,返回值:1-空,0-非空或失败。
int  IsEmpty(LinkStack SS);

// 打印链栈中全部的元素。
void PrintStack(LinkStack SS);

// 获取栈顶元素,返回值:0-失败;1-成功。
// 只查看栈顶元素的值,元素不出栈。
int GetTop(LinkStack SS, ElemType *ee);

int main()
{
   LinkStack S;     // 创建链栈。

   S = InitStack();  // 初始化链栈。

   printf("栈的长度是%d\n", Length(S));

   ElemType e;     // 创建一个数据元素。

   printf("元素(1、2、3、4、5、6、7、8、9、10)入栈。\n");
   e = 1;  Push(S, &e);
   e = 2;  Push(S, &e);
   e = 3;  Push(S, &e);
   e = 4;  Push(S, &e);
   e = 5;  Push(S, &e);
   e = 6;  Push(S, &e);
   e = 7;  Push(S, &e);
   e = 8;  Push(S, &e);
   e = 9;  Push(S, &e);
   e = 10; Push(S, &e);

   printf("栈的长度是%d\n", Length(S));

   if (GetTop(S, &e) == 1)  printf("栈顶的元素值为%d\n", e);

   PrintStack(S);

   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);

   // 当所有元素出栈后
   
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);
   if (Pop(S, &e) == 1)  printf("出栈的元素值为%d\n", e);

   // 销毁链栈SS。
   DestroyStack(S); S = 0;  // 销毁链栈后把SS置为空,防止野指针。

   return 0;
}

// 链栈SS的初始化操作,分配头结点,返回头结点的地址。
SNode *InitStack()
{
   SNode *head = (SNode *)malloc(sizeof(SNode));  // 分配头结点。

   if (head == NULL) return NULL;  // 内存不足,返回失败。

   head->next = NULL;  // 头结点的下一结点暂时不存在,置空。

   return head;
}


// 清空链栈。
void Clear(LinkStack SS)
{
   // 清空链栈SS是指释放链栈全部的结点,但不包括头结点。
   if (SS == NULL) return;  // 检查空指针。

   SNode *tmp1;
   SNode *tmp2 = SS->next;  // 保留头结点,从头结点的下一个结点开始释放。

   while (tmp2 != NULL)
   {
   	tmp1 = tmp2->next;
   	free(tmp2);
   	tmp2 = tmp1;
   }

   SS->next = NULL; // 这行代码一定不能少,否则会留下野指针。

   return;
}

// 求链栈的长度,返回值:栈SS中元素的个数。
int  Length(LinkStack SS)
{
   if (SS == NULL) return 0; // 检查空指针。

   SNode *pp = SS->next;  // 头结点不算,从第1个结点开始。

   int length = 0;

   while (pp != NULL) { pp = pp->next; length++; }

   return length;
}

// 销毁链栈SS。
void DestroyStack(LinkStack SS)
{
   // 销毁链栈SS是指释放链栈全部的结点,包括头结点。
   SNode *tmp;

   while (SS != NULL)
   {
   	tmp = SS->next;  // tmp保存下一结点的地址。
   	free(SS);      // 释放当前结点。
   	SS = tmp;        // SS指针移动到下一结点。
   }

   // SS=NULL;   // SS在本函数中相当于局部变量,就算置空了也不会影响调用者传递的SS,
   					  // 所以SS=NULL没有意义。

   return;
}

// 判断链栈是否为空,返回值:1-空,0-非空或失败。
int IsEmpty(LinkStack SS)
{
   if (SS == NULL) return 0;   // 检查空指针。

   if (SS->next == NULL) return 1;

   return 0;
}

// 打印链栈中全部的元素。
void PrintStack(LinkStack SS)
{
   if (SS == NULL) return; // 检查空指针。

   if (SS->next == NULL) { printf("栈为空。\n"); return; }

   int kk = 0;
   SNode *pp = SS->next;  // 从第1个结点开始。

   while (pp != NULL)
   {
   	printf("SS[%d],value=%d\n", kk++, pp->data);
   	pp = pp->next;
   }
}

// 元素出栈,返回值:0-失败;1-成功。
int Pop(LinkStack SS, ElemType *ee)
{
   if ((SS == NULL) || (ee == NULL)) return 0;  // 检查空指针。

   if (SS->next == NULL) { printf("栈为空。\n"); return 0; }

   SNode *tmp = SS->next;

   memcpy(ee, &tmp->data, sizeof(ElemType));

   SS->next = tmp->next;

   free(tmp);

   return 1;
}

// 获取栈顶元素,返回值:0-失败;1-成功。
// 只查看栈顶元素的值,元素不出栈。
int GetTop(LinkStack SS, ElemType *ee)
{
   if ((SS == NULL) || (ee == NULL)) return 0;  // 检查空指针。

   if (SS->next == NULL) { printf("栈为空。\n"); return 0; }

   memcpy(ee, &SS->next->data, sizeof(ElemType));

   return 1;
}

// 元素入栈,返回值:0-失败;1-成功。
int Push(LinkStack SS, ElemType *ee)
{
   if ((SS == NULL) || (ee == NULL)) return 0;  // 检查空指针。

   SNode *tmp = (SNode *)malloc(sizeof(SNode));  // 分配一个结点。
   if (tmp == NULL) return 0;  // 内存不足,返回失败。

   // 考虑数据元素为结构体的情况,这里采用了memcpy的方法而不是直接赋值。
   memcpy(&tmp->data, ee, sizeof(ElemType));

   // 处理next指针。
   tmp->next = SS->next;
   SS->next = tmp;

   return 1;
}

链栈运行结果如下:
在这里插入图片描述

四 小结

1.代码复制后,就可以跑起来。
2.先讲到这里。后续剖析函数调用栈以及栈的一些应用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值