出栈顺序的全部可能性公式_四、顺序栈

1. 栈的定义

栈的定义:限定仅在表尾进行插入和删除操作的线性表。同时因为只能在表尾进行操作,所以栈又称为后进先出的线性表。见下图,浅灰色的元素后进入栈结构,出栈的时候却是第一个出去。

5198997db13952fea34f07bc36da25da.png

我们针对栈结构元素的插入和删除,分别叫做“Push”压栈和“Pop”弹栈。

2. 顺序栈的插入和删除

既然栈是线性表,而线性表包括顺序表和链表,那么同样栈也包括顺序栈和链栈。顺序栈中我们定义一个top指针,其实这里只是个游标,对应着栈顶元素的下标,比如top是0,那栈顶元素下标就是0,表示只有一个0号元素,通常规定如果top等于-1,表示空栈。见下图所示,一个有5个元素空间的顺序栈结构,当top=1时,有两个元素,top=-1时,空栈,top=4时,满栈。

8dd5b53f9e667a47d960437cd6326ab1.png

那么进栈操作就很明显,只要移动我们的top游标即可,进一个top++,而删除的时候则top--

5226473d8ee93bf650058b276de04610.png

3. 代码实现

那么我们就来实现下顺序栈的push和pop,以及清空栈clear

还是先定义一下数据元素,包含一个id和一个name

typedef struct DataElement
{
	int id;
	const char* name;
}DataElement;

接着定义顺序栈结构,包括数组元素、top指针(游标)、数组长度

typedef struct SeqStack
{
	DataElement elements[MAX_SIZE];	//栈内元素数组
	int top;	//栈顶(数组中下标),如果为-1,表明栈是空的
	int length;	//当前栈的元素个数
}SeqStack;

然后我们来实现一下压栈push操作。注意:我们插入的元素下标是要将top加加后得到的值,因为top加加后才指向新的元素空间。

void PushSeqStack(SeqStack* seqStack, DataElement element)
{
	if (seqStack->top == MAX_SIZE)
	{
		printf("满栈,压栈失败!n");
		return;
	}
	seqStack->top++;
	seqStack->elements[seqStack->top] = element;
	seqStack->length++;
	return;
}

接着实现弹栈pop操作,同理我们需要先将top值减减。

void PopSeqStack(SeqStack* seqStack)
{
	if (seqStack->top == -1)
	{
		printf("空栈,弹栈失败!n");
		return;
	}
	seqStack->top--;
	seqStack->length--;
	return;
}

然后实现一下初始化函数,初始化数组的长度和top指针后,直接压栈即可。

void InitSeqStack(SeqStack* seqStack, int length, DataElement* dataArray)
{
	seqStack->length = 0;
	seqStack->top = -1;
	for (int i = 0; i < length; i++)
	{
		PushSeqStack(seqStack, dataArray[i]);
	}
}

接着实现清空栈,直接将top赋值-1,数组长度归零即可。

void ClearSeqStack(SeqStack* seqStack)
{
	seqStack->length = 0;
	seqStack->top = -1;
}

然后是“是否为空”函数,也很简单,只需判断top是否为-1

int IsEmpty(SeqStack* seqStack)
{
	if (seqStack->top == -1)
		return 1;
	return 0;
}

最后为了测试,实现一个打印顺序栈。这和遍历数组没多大区别。

void PrintSeqStack(SeqStack* seqStack)
{
	if (seqStack->top == -1)
	{
		printf("空栈!n");
		return;
	}
	for (int i = 0; i < seqStack->length; i++)
	{
		printf("%dt%sn", seqStack->elements[i].id, seqStack->elements[i].name);
	}
}

4. 测试代码

接着我们测试一下,先初始化待插入的数据元素

DataElement dataArray[] =
{
    { 1, "娜美"},
    { 2, "罗宾"},
    { 3, "大和"},
    { 4, "汉库克"}
};

然后实现测试函数,这次我们动态分配顺序栈空间,然后将4个元素全部压入栈中,接着将表尾元素弹栈,最后清空栈。

void TestSeqStack()
{
    SeqStack* seqStack = (SeqStack*)malloc(sizeof(SeqStack)); 
    int length = sizeof(dataArray) / sizeof(dataArray[0]);
    InitSeqStack(seqStack, length, dataArray);
    printf("压栈后:n");
    PrintSeqStack(seqStack);
    PopSeqStack(seqStack);
    printf("弹栈后:n");
    PrintSeqStack(seqStack);
    ClearSeqStack(seqStack);
    printf("清空栈后:n");
    PrintSeqStack(seqStack);
    free(seqStack);
}

编译运行,可以看到,弹栈后4号元素“汉库克”(下标为3的元素)被删除了。清空后也是没问题。

6b9cde2e03b00842b613bbe681f4e64e.png

5. 总结

优点:顺序栈在插入和删除时候不需要移动元素,只需移动top指针。

缺点:顺序栈和顺序表一样,都需要预先定好数组空间,不像链表那样机动。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值