A. 数据结构中什么叫做顺序栈
顺序栈
栈的顺序存储结构简称为顺序栈,它是运算受限的顺序表。
1、
顺序栈的类型定义
#define
StackSize
100
//假定预分配的栈空间最多为100个元素
typedef
char
DataType;//假定栈元素的数据类型为字符
typedef
struct{
DataType
data[StackSize];
int
top;
}SeqStack;
注意:
①顺序栈中元素用向量存放
②栈底位置是固定不变的,可设置在向量两端的任意一个端点
③栈顶位置是随着进栈和退栈操作而变化的,用一个整型量top(通常称top为栈顶指针)来指示当前栈顶位置
2、
顺序栈的基本操作
前提条件:
设S是SeqStack类型的指针变量。若栈底位置在向量的低端,即S->data[0]是栈底元素。
(1)
进栈操作
进栈时,需要将S->top加1
注意:
①S->top==StackSize-1表示栈满
②"
上溢
"现象--当栈满时,再做进栈运算产生空间溢出的现象。
上溢是一种出错状态,应设法避免。
(2)
退栈操作
退栈时,需将S->top减1
注意:
①S->top<0表示空栈
②"
下溢
"现象——当栈空时,做退栈运算产生的溢出现象。
下溢是正常现象,常用作程序控制转移的条件。
顺序栈在进栈和退栈操作时的具体变化情况【参见动画演示】
3、顺序栈的基本运算
(1)
置栈空
void
InitStack(SeqStack
*S)
{//将顺序栈置空
S->top=-1;
}
(2)
判栈空
int
StackEmpty(SeqStack
*S)
{
return
S->top==-1;
}
(3)
判栈满
int
StackFull(SeqStack
*SS)
{
return
S->top==StackSize-1;
}
(4)
进栈
void
Push(S,x)
{
if
(StackFull(S))
Error("Stack
overflow");
//上溢,退出运行
S->data[++S->top]=x;//栈顶指针加1后将x入栈
}
(5)
退栈
DataType
Pop(S)
{
if(StackEmpty(S))
Error("Stack
underflow");
//下溢,退出运行
return
S->data[S->top--];//栈顶元素返回后将栈顶指针减1
}
(6)
取栈顶元素
DataType
StackTop(S)
{
if(StackEmpty(S))
Error("Stack
is
empty");
return
S->data[S->top];
}
4、两个栈共享同一存储空间
当程序中同时使用两个栈时,可以将两个栈的栈底设在向量空间的两端,让两个栈各自向中间延伸。当一个栈里的元素较多,超过向量空间的一半时,只要另一个栈的元素不多,那么前者就可以占用后者的部分存储空间。
只有当整个向量空间被两个栈占满(即两个栈顶相遇)时,才会发生上溢。因此,两个栈共享一个长度为m的向量空间和两个栈分别占用两个长度为 └ m/2┘和┌m/2┐的向量空间比较,前者发生上溢的概率比后者要小得多。
B. 两栈共享空间
1.如果有两个相同类型的栈,我们为它们各自开辟了数组空间,极有可能 一个栈已经满了,再进栈就溢出了,而另一个栈还有很多存储空间空间 。
2.所以我们可以使用 一个数组来存储两个栈 。
3.具体做法如下:数组有两个端点,两个栈有两个栈底,让 一个栈的栈底为数组的始端,即下标为0处 , 另一个栈为数组的末端,即下标为数组长度n-1处
这样,两个栈如果增加元素,就是 两端点向中间延伸
与上一遍顺序栈的程序不同的是,此处采用下标记录栈顶位置,而非指针,且并没有指向栈顶的下一个存储空间
如下图所示:
测试:
C. 两栈共享一个存储空间,判定栈满的条件是什么
应该是top[1]=top[2] 吧,因为两个栈顶都对到一起了才能说明栈的存储已达到极限了,我是这么理解的。
D. 若栈采用顺序存储方式存储,现两栈共享空间
晕.这么简单的问题也拿出来问
1 2 3 .m
| |
那么当他们满的时候,两个指针相邻
那就是
top[1]+1=top[2]
top[1]在top[2]左边相邻了
E. 请问“多个栈共存时,最好用链式存储空间作为存储结构”,这是为什么啊
如果只有两个栈,则可以将一个放在数组的低空间,一个放在高空间,两者从两头向中间扩展,这样没有空间浪费
如果多于两个栈时,还是采用顺序存储,则一个满了另外栈空间虽然有空,但是必须要移动栈中元素才能使用别的浪费的空间,这样算法的效率就不高了,此时不如直接采用链接存储好了
F. 设有两个堆栈S1,S2都采用顺序栈方式,并且共享一个存储区,采用栈顶相向、迎面增长的存贮方式,
1
s1空:S1的栈顶等于栈底
s2空:s2的栈顶等于栈底
2
s1满:S1的栈顶等于S2的栈顶
s2满:S2的栈顶等于S1的栈顶
#include
#define
TYPE_S1
1
#define
TYPE_S2
-1
#define
STACK_SIZE
20
void
StackPush(int
**stackTop,
int
elmnt,
int
type)
{
**stackTop
=
elmnt;
*stackTop
+=
type;
}
void
main()
{
int
stack[STACK_SIZE]
=
{0};
int
*S1Top
=
&stack[0],
*S2Top
=
&stack[STACK_SIZE
-
1];
int
i,
input
=0;
for
(i
=
0;
i
<
20;
i++)
{
printf("请输入一个整数:");
scanf("%d",
&input);
if(input
%
2
==0)
{
StackPush(&S1Top,
input,
TYPE_S1);
}
else
{
StackPush(&S2Top,
input,
TYPE_S2);
}
if(S1Top
==
S2Top)
{
printf("堆栈已满\n");
break;
}
}
return;
}
G. 基本运算的栈的定义及基本运算
栈和队列是两种特殊的线性表,它们的逻辑结构和线性表相同,只是其运算规则较线性表有更多的限制,故又称它们为运算受限的线性表。栈和队列被广泛应用于各种程序设计中。 栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表。
(1)通常称插入、删除的这一端为栈顶(Top),另一端称为栈底(Bottom)。
(2)当表中没有元素时称为空栈。
(3)栈为后进先出(LastInFirstOut)的线性表,简称为LIFO表。
栈的修改是按后进先出的原则进行。每次删除(退栈)的总是当前栈中最新的元素,即最后插入(进栈)的元素,而最先插入的是被放在栈的底部,要到最后才能删除
【示例】元素是以a1,a2,…,an的顺序进栈,退栈的次序却是an,an-1,…,a1。 (1)InitStack(S)
构造一个空栈S。
(2)StackEmpty(S)
判栈空。若S为空栈,则返回TRUE,否则返回FALSE。
(3)StackFull(S)
判栈满。若S为满栈,则返回TRUE,否则返回FALSE。
注意:
该运算只适用于栈的顺序存储结构。
(4)Push(S,x)
进栈。若栈S不满,则将元素x插入S的栈顶。
(5)Pop(S)
退栈。若栈S非空,则将S的栈顶元素删去,并返回该元素。
(6)StackTop(S)
取栈顶元素。若栈S非空,则返回栈顶元素,但不改变栈的状态。
顺序栈
栈的顺序存储结构简称为顺序栈,它是运算受限的顺序表。
1、顺序栈的类型定义
#defineStackSize100//假定预分配的栈空间最多为100个元素
typedefcharDataType;//假定栈元素的数据类型为字符
typedefstruct{
DataTypedata[StackSize];
inttop;
}SeqStack;
注意:
①顺序栈中元素用向量存放
②栈底位置是固定不变的,可设置在向量两端的任意一个端点
③栈顶位置是随着进栈和退栈操作而变化的,用一个整型量top(通常称top为栈顶指针)来指示当前栈顶位置
2、顺序栈的基本操作
前提条件:
设S是SeqStack类型的指针变量。若栈底位置在向量的低端,即S->data[0]是栈底元素。
(1)进栈操作
进栈时,需要将S->top加1
注意:
①S->top==StackSize-1表示栈满
②上溢现象--当栈满时,再做进栈运算产生空间溢出的现象。
上溢是一种出错状态,应设法避免。
(2)退栈操作
退栈时,需将S->top减1
注意:
①S->toptop=-1;
}
(2)判栈空
intStackEmpty(SeqStack*S)
{
returnS->top==-1;
}
(3)判栈满
intStackFull(SeqStack*SS)
{
returnS->top==StackSize-1;
}
(4)进栈
voidPush(S,x)
{
if(StackFull(S))
Error(Stackoverflow);//上溢,退出运行
S->data[++S->top]=x;//栈顶指针加1后将x入栈
}
(5)退栈
DataTypePop(S)
{
if(StackEmpty(S))
Error(Stackunderflow);//下溢,退出运行
returnS->data[S->top--];//栈顶元素返回后将栈顶指针减1
}
(6)取栈顶元素
DataTypeStackTop(S)
{
if(StackEmpty(S))
Error(Stackisempty);
returnS->data[S->top];
}
4、两个栈共享同一存储空间
当程序中同时使用两个栈时,可以将两个栈的栈底设在向量空间的两端,让两个栈各自向中间延伸。当一个栈里的元素较多,超过向量空间的一半时,只要另一个栈的元素不多,那么前者就可以占用后者的部分存储空间。
只有当整个向量空间被两个栈占满(即两个栈顶相遇)时,才会发生上溢。因此,两个栈共享一个长度为m的向量空间和两个栈分别占用两个长度为└m/2┘和┌m/2┐的向量空间比较,前者发生上溢的概率比后者要小得多。
链栈
栈的链式存储结构称为链栈。
1、链栈的类型定义
链栈是没有附加头结点的运算受限的单链表。栈顶指针就是链表的头指针。
链栈的类型说明如下:
typedefstructstacknode{
DataTypedata
structstacknode*next
}StackNode;
typedefstruct{
StackNode*top;//栈顶指针
}LinkStack;
注意:
①LinkStack结构类型的定义是为了方便在函数体中修改top指针本身
②若要记录栈中元素个数,可将元素个数属性放在LinkStack类型中定义。
2、链栈的基本运算
(1)置栈空
VoidInitStack(LinkStack*S)
{
S->top=NULL;
}
(2)判栈空
intStackEmpty(LinkStack*S)
{
returnS->top==NULL;
}
(3)进栈
voidPush(LinkStack*S,DataTypex)
{//将元素x插入链栈头部
StackNode*p=(StackNode*)malloc(sizeof(StackNode));
p->data=x;
p->next=S->top;//将新结点*p插入链栈头部
S->top=p;
}
(4)退栈
DataTypePop(LinkStack*S)
{
DataTypex;
StackNode*p=S->top;//保存栈顶指针
if(StackEmpty(S))
Error(Stackunderflow.);//下溢
x=p->data;//保存栈顶结点数据
S->top=p->next;//将栈顶结点从链上摘下
free(p);
returnx;
}
(5)取栈顶元素
DataTypeStackTop(LinkStack*S)
{
if(StackEmpty(S))
Error(Stackisempty.)
returnS->top->data;
}
注意:
链栈中的结点是动态分配的,所以可以不考虑上溢,无须定义StackFull运算。
H. 1,2,3,4依次进栈,出栈随时,写一算法求出所有可能出栈序列
代码如下:
#define N 4
int m=0,a=0,b=N;/*m表示种数,a表示栈中元素个数,b表示外面还有需要进栈的个数*/
main()
{
inS(a,b);/*首先入栈*/
printf("%d",m);
getch();
}
int inS(int a,int b)/*入栈*/
{
a++;b--;/*入栈栈中元素+1,栈外元素-1 */
if(b>0)/*若栈外有元素,可以入栈*/
inS(a,b);
if(a>0)/*若栈中有元素,可以出栈*/
outS(a,b);
}
int outS(int a,int b)/*出栈*/
{
a--;/*出栈栈中元素-1*/
if(a==0&&b==0)/*若栈中元素和栈外元素都为0个*/
{
m++;/*则此种情况的序列满足条件,种数+1*/
return;
}
if(b>0)
inS(a,b);
if(a>0)
outS(a,b);
}
(8)三个栈共享一个顺序存储空间扩展阅读
栈的相关知识点:
顺序栈内容包含数据和栈顶指针(int),因此采用结构体。
注意:
1、初始时,top指向-1;
2、入栈时,先判断顺序栈是否已满(判断条件:top=maxsize-1);如果没满,则top++,并将元素值赋给s.top;
3、出栈时,先判断顺序栈是否已空(判断条件:top=-1);如果没空,则先返回栈顶元素,再top- -。
共享栈
两个顺序栈共享一个一维数组空间,而栈底位置相对不变,两个栈底分别设为一维数组的两端。
note:
(1)栈空:top1==-1&&top2==maxsize;
(2)栈满:top2-top1= 1(此时两个栈顶指针相邻);
(3)入栈:S.data[++top1]=x或S.data[–top2]=x;
(4)出栈:x=S.data[top1–]或x=S.data[top2++];
(5)共享栈可以更好的利用存储空间,整个存储空间被占满时发生上溢。
I. 两个栈共享一段内存区域是什么意思
当程序中同时使用两个栈时,可以将两个栈的栈底设在向量空间的两端,让两个栈各自向中间延伸。如下图所示:
当一个栈的元素较多,超过向量空间的一半时,只要另一个栈的元素不多,那么前者就可以占用后者的部分存储空间。
只有当整个向量空间被两个栈占满(即两个栈顶相遇)时,才会发生上溢,因此两个栈共享一个长度为m的向量空间
J. 栈的共享存储单元是什么
有时,一个程序设计中,需要使用多个同一类型的栈,这时候,可能会产生一个栈空间过小,发生溢出,而另一个栈空间过大,造成大量存储单元浪费的现象。为了充分利用各个栈的存储空间,这时可以采用多个栈共享存储单元,即给多个栈分配一个足够大的存储空间,让多个栈实现存储空间优势互补。
1.双栈为两个栈共同开辟一个存储空间,让一个栈的栈底为该空间的始端,另一栈的栈底为该空间的末端,当元素进栈时,都从两端向中间“增长”,这样能够使剩余的空间为任意一个栈所使用,即当一个栈的深度不足整个空间的一半时,另一个栈的深度可超过其一半,从而提高了存储空间的利用率。可以使用一个数组同时存两个栈,让一个栈的栈底为数组的始端,另一个栈的栈底为数组的末端,每个栈从各自的端点向中间延伸,双栈示意如图1所示。其中,MAXSTACKSIZE为整个数组空间的长度,栈1的底端固定在下标为0的一端,栈2的底端固定在下标为MAXSTACKSIZE-1的一端。top1和top2分别为栈1和栈2的栈顶指针,并约定栈顶指针指向当前元素,即栈1空的条件是top1=-1,栈1满的条件是top1==top2-1,栈2空的条件是top2=MAXSTACKSIZE,栈2满的条件是top2==top1+1。
图1两相栈共享存储单元示意