【数据结构】栈的两种实现方式和基本操作

栈的特性

栈是一种只限定在表尾进行插入和删除操作的线性表,允许插入和删除的一段称作栈顶(top),另一端称为栈底,不含任何数据元素的称为空栈,栈的特性是后进先出

栈模型
栈的存储方式有两种,一种是顺序栈一种是链表栈
顺序栈利用一组地址连续的存储单元存放自栈底到栈顶的元素,同时附设一个指针(top)指示当前栈顶的位置。

#define MaxSize 100 //定义栈中元素的最大个数
typedef struct Stack {
    int data[MaxSize]; //存放栈中的元素
    int top; 		   //栈顶指针
}Stack;

链表栈常采用单链表实现,并且所有操作都是在单链表的表头进行。

typedef struct StackNode{
    int data; //数据域
    struct LinkNode *next; //指针域
}StackNode; 

本文介绍顺序栈的实现和链表栈的实现,其中链表栈和单链表差不多,可参考此文

栈的数组实现

  • 初始化栈
    void InitStack(Stack* stack);
  • 判断空栈
    bool isEmpty(Stack* stack);
  • 进栈
    void Push(Stack* stack, int x);
  • 出栈
    void Pop(Stack* stack,int *x);
  • 读栈顶元素
    int GetTop(Stack* stack);
  • 遍历栈
    void Print(Stack stack);
  • 销毁栈
    void Destroy(Stack* stack);

初始化栈

将栈顶指针设置为-1就可以了(空栈)。

void InitStack(Stack* stack)
{
	stack->top = -1;
}

判断空栈

栈顶指针为-1就是空栈,大于-1就不是空栈。

bool isEmpty(Stack* stack)
{
	if (stack->top == -1)
		return true;
	else
		return false;
}

读栈顶元素

int GetTop(Stack* stack)
{
	if (isEmpty(stack))
	{
		printf("栈空\n");
		return -1;
	}
	else
		return stack->data[stack->top];
}

遍历栈

注意:遍历栈如果像我这样写,参数要注意不可是Stack*stack,不然遍历之后栈就空了。

void Print(Stack stack)
{
	while (stack->top != -1)
	{
		printf("%4d", stack->data[stack->top--]);
	}
	printf("\n");
}

销毁栈

栈的销毁令S.top = -1即可

void Destroy(Stack* stack)
{
	stack->top = -1;
}

进栈

进栈的时候栈顶指针先上移,然后在放入元素

void Push(Stack* stack, int x)
{
	if (stack->top == MaxSize - 1)
	{
		printf("栈已经满了\n");
		return;
	}
	stack->data[++stack->top] = x;
}

出栈

出的时候栈顶指针下移一位即可

void Pop(Stack* stack,int* x)
{
	if (stack->top ==  - 1)
	{
		printf("栈已经空了\n");
		return;
	}
	*x=stack->data[stack->top--] ;
}

测试
在这里插入图片描述

栈的链表实现

typedef struct Node
{
	int element;
	ptrToNode next;
}Node;
typedef struct Node* ptrToNode;
typedef ptrToNode Stack;
  • 判断是否为空栈
    int IsEmpty(Stack s);
  • 创建一个栈
    Stack CreatStack();
  • 销毁一个栈
    void DestroyStack(Stack s);
  • 清空栈
    void MakeEmpty(Stack s);
  • 进栈
    void Push(int x, Stack s);
  • 出栈
    void Pop(Stack s);
  • 显示栈顶元素
    int Top(Stack s);
  • 打印栈的所有元素
    void ShowStack(Stack s);

判断空栈

int IsEmpty(Stack s)
{
	return s->next==NULL;
}

s不是栈顶元素,s是链表的表头,第一个元素是表头后的元素s->next。

创建一个空栈

Stack CreatStack()
{
	Stack s;
	s = malloc(sizeof(Node));
	if (s == NULL)
		printf("创建栈失败\n");
	else
		s->next = NULL;
	//MakeEmpty(s);
	return s;
}

进栈

元素的进栈操作就相当于单链表的头插法。

void Push(int x, Stack s)
{
	ptrToNode tempNode;
	tempNode = malloc(sizeof(Node));
	if (tempNode == NULL)
		printf("创建临时节点失败\n");
	else
	{
		tempNode->element = x;
		tempNode->next = s->next;
		s->next = tempNode;
	}
}

出栈

出栈操作就相当于单链表的头删操作。

void Pop(Stack s)
{
	ptrToNode firstNode;
	if (IsEmpty(s))
		printf("这是一个空栈\n");
	else
	{
		firstNode = s->next;
		s->next = s->next->next;
		free(firstNode);
	}
}

清空栈

连续将栈顶元素弹出,直到为空栈

void MakeEmpty(Stack s)
{
	if (s == NULL)
		printf("请先使用CreateStack()创建一个栈\n");
	else
	{
		while (!IsEmpty(s))
		{
			Pop(s);
		}
	}
}

总结

在本篇文章中,我们详细探讨了两种实现栈的方法:循序栈和链表栈。

循序栈的优点在于其实现简单且效率高。然而,它的缺点在于需要预先确定栈的最大容量,这限制了它的灵活性。如果栈的实际大小超过了最大容量,将会导致栈溢出。

链表栈的优点在于其灵活性。由于链表节点的内存空间是动态分配的,所以链表栈的大小只受限于可用内存的大小。此外,链表栈还可以方便地进行扩容和缩容。然而,链表栈的缺点在于其实现相对复杂。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值