几种栈(c语言)的一些基础操作~DS笔记④

几个定义先写在前面:

#define MAXSIZE 20
typedef int SElemType;/* SElemType类型根据情况而定,这里设为int */
typedef enum{ FALSE = 0, TRUE = 1 }Bool;

,一种常见的数据结构。它有许多应用,比如网页左上角的“前进”和“返回”,(也就是撤销上一步操作)等等。
它长什么样呢?
它很像一个数组,但不同的是,它的数据只能从一个开口进出。
比如,我们有ABCD四个元素,我们先让他们依次入栈,即压栈(push),再让他们依次出栈,即弹栈(pop),那么最终得到的顺序将变为DCBA。
这又张图可供参考。
stack
当然,我们也可以让它以ABCD的顺序近,并且以ABCD的顺序出。
怎么做?我们可以在把A压栈后,直接弹栈,再把B压栈,再直接弹栈……
也就是说压一个,弹一个,那么最终的出栈顺序自然是ABCD了。
对对对
这是一个用c语言写的

顺序栈

结构体

typedef struct Stack
{/* 顺序栈结构 */
 SElemType data[MAXSIZE];
 int top;
}SqStack;

这是关于顺序栈的一些基本操作:

Bool ClearStack(SqStack* s)
{	/* 把S置为空栈 */
 s->top = -1;
 return TRUE;
}

Bool StackEmpty(SqStack* s)
{	/* 若栈S为空栈,则返回TRUE,否则返回FALSE */
 if (s->top == -1)
  return TRUE;
 else
  return FALSE;
}

Bool GetTop(SqStack* s,SElemType* e)
{	/* 若栈不空,则用e返回S的栈顶元素,并返回TRUE;否则返回FALSE */
 if (s->top == -1)
  return FALSE;
 else
  *e = s->data[s->top];
 return TRUE;
}

int StackLength(SqStack* s)
{	/* 返回S的元素个数,即栈的长度 */
 return s->top + 1;
}

Bool visit(SElemType e)
{
 printf("%d ", e);
 return TRUE;
}

Bool StackTraverse(SqStack* s)
{	/* 从栈底到栈顶依次对栈中每个元素显示 */
 int i;
 i = 0;
 while (i <= s->top)
 {
  visit(s->data[i++]);
 }
 printf("\n");
 return TRUE;
}

当然最重要的还是压栈和弹栈操作了。
顺序栈压栈

Bool Push(SqStack* s, SElemType e)
{	/* 插入元素e为新的栈顶元素 */
 if (s->top == MAXSIZE - 1)	/* 栈满 */
 {
  return FALSE;
 }
 s->top++; 	/* 栈顶指针增加一 */
 s->data[s->top] = e; 	/* 将新插入元素赋值给栈顶空间 */
 return TRUE;
}

顺序栈弹栈

Bool Pop(SqStack* s, SElemType* e)
{/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回TRUE;否则返回FALSE */
 if (s->top == -1)
  return FALSE;
 *e = s->data[s->top];/* 将要删除的栈顶元素赋值给e */
 s->top--; /* 栈顶指针减一 */
 return TRUE;
}

“共享栈”

但其实顺序栈有时候并不完美,因为如果其中元素过少,那就会有很大的空间浪费。毕竟数组空间是开死的。
那如何更好的利用空间呢?
我们可以这么做:把两个栈口对口“接”起来,形成一个只有一个栈顶,但有两个栈底的变型栈。而且它的栈顶在中间摆动,位置不定。
这样,当其中一个栈空着不怎么用时,第二个栈就变“大”了。
在这里插入图片描述
在这里插入图片描述
下面是关于共享栈的c语言结构体

typedef struct DoubleStack
{/* 两栈共享空间结构 */
 SElemType data[MAXSIZE];
 int top1;  /* 栈1栈顶指针 */
 int top2;  /* 栈2栈顶指针 */
}SqDoubleStack;

下面是关于共享栈的压栈弹栈操作:

共享栈压栈

Bool PushDouble(SqDoubleStack* s, SElemType e, int stackNumber)
{/* 插入元素e为新的栈顶元素 */
 if (s->top1 + 1 == s->top2)//栈已满
 {
  return FALSE;
 }
 if (stackNumber == 1)
  s->data[++s->top1] = e;/* 先top1+1,再给数组元素赋值 */
 else if (stackNumber == 1)
  s->data[--s->top2] = e;/* 先top2-1,再给数组元素赋值 */
 return TRUE;
}

共享栈弹栈

Bool PopDouble(SqDoubleStack* s, SElemType* e, int stackNumber)
{
 if (stackNumber == 1)
 {
  if (s->top1 == -1) /* 栈1已经是空栈 */
   return FALSE;
  *e = s->data[s->top1--];/* 将栈1的栈顶元素出栈 */
 }
 else if (stackNumber == 2)
 {
  if (s->top2 == MAXSIZE) /* 栈2已经是空栈 */
   return FALSE;
  *e = s->data[s->top2++];/* 将栈2的栈顶元素出栈 */
 }
 return TRUE;
}

链栈

但是说到底,顺序栈都有一个空间是死的,不够灵活的弊端。
怎么才能想有多少空间,就有多少空间呢?
当然是链式存储。将栈结构和链式存储结合起来,也就构成了链栈。
这样,我们在压栈时,就申请一块新的结点;弹栈时,就释放一块结点。每次空间开辟都用malloc去实现,空间大小也就灵活起来了。
值得注意的是,我们的栈顶,也就是top指针指向的位置,是链表头。
在这里插入图片描述
下面是关于链栈的c语言结构体

typedef struct _StackNode
{/* 链栈节点 */
 SElemType data;
 struct _StackNode *next;
}StackNode,*LinkStackPtr;

typedef struct LinkStack
{/* 链栈结构 */
 LinkStackPtr top;
 int count;//节点数
}LinkStack;

下面是关于链栈的压栈弹栈操作:

链栈压栈

Bool PushLink(LinkStack* s, SElemType e)
{/* 插入元素e为新的栈顶元素 */
 LinkStackPtr ls = (LinkStackPtr)malloc(sizeof(StackNode));
 ls->data = e;
 ls->next = s->top;/* 把当前的栈顶元素赋值给新结点的直接后继 */
 s->top = ls; /* 将新的结点s赋值给栈顶指针*/
 s->count++;
 return TRUE;
}

链栈弹栈

Bool PopLink(LinkStack* s, SElemType* e)
{/* 若栈不空删除S的栈顶元素,用e返回其值,并返回TRUE;否则返回FALSE */
 LinkStackPtr p;
 if (LinkStackEmpty(s))//空栈
  return FALSE;
 *e = s->top->data;
 p = s->top;/* 将栈顶结点赋值给p */
 s->top = s->top->next;/* 使得栈顶指针下移一位,指向后一结点*/
 free(p); /* 释放结点p */
 s->count--;
 return TRUE;
}

这儿有一个有趣的网站,可以实现链栈的可视化压栈弹栈操作。
(在网页上面菜单栏选择栈)
https://visualgo.net/zh/list
好了就到这里了,谢观。
(:з)∠)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值