大话西游之王道考研数据结构第三讲---栈

                                               第三讲---栈

  • 复习

上次我们讲到了线性表的链式表示,这里我们做一个简单的复习:

线性表的链式表示有哪些特点?

  • 访问方面
  • 存储方面
  • 不同操作的复杂度方面

线性表有几种表示方式?

链表中你能想到几种结构?(最简单的有单链表,还有什么链表,分别有什么特点)

链表的插入、删除中,不同链表结构下,在p结点后面、前面插入一个结点s的操作是什么?

一、栈

:  只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表,但是限定这种线性表只能在某一端进行插入和    删除操作。

栈顶:线性表允许进行插入和删除的那一端。

栈底:固定的,不允许进行插入和删除的另一端。

空栈:不含任何元素的空表。

举个栗子:

         上次一将到唐僧成立了一家传销公司,后来公安局不允许他这么干,所以改成了下线也可以知道上线的模式。如此一来,公司就很透明了。唐僧决定应该组织一次团建,来团结人心,所以他们决定去春游~

         非常不幸,春游的路上有一口枯井(栈),里面什么都没有(空栈)。唐僧这个人已经飘飘然不行了,所以完全没有注意到枯井。所以,咔~唐僧(栈底)掉下去了。然后猴哥说,师傅你别怕,我来救你-----咔,猴哥主动跳下去了(唐僧:woxxxxx~)。八戒一看,哇,猴哥这么会拍马屁,我也拍一个,咔~八戒跳下去了(唐僧激动的说不出话来)。然后,沙僧和小白龙(栈顶)也相继跳下去了。所以现在是这个状态:

可以看到:

1.这口枯井只能从上面跳下来,不能从下面钻出去….

(只允许在一端进行插入或删除操作)

2.如果唐僧想出去,先得马马出去,沙僧出去,八戒出去,猴哥出去,他才能出去。

(后进先出)

二、栈的基本操作(请坐下):

         1.老规矩,我们先看下他的结构体:

#define MaxSize 50 //最大栈的容量(井里最多放50人)
typedef struct{
    int data[MaxSize]; //我们用线性表的顺序表示方式去存取内容
    //当然,你也可以用链式表示存储,如果你不嫌麻烦的话
    //顺序表示有个好处,因为我们只涉及到尾部的增加和删除
    //所以增删都是0(1)
    int top;//用来表示当前栈顶的位置
}SqStack;

2.InitStack(&S):初始化栈

void InitStack(SqStack &S){
    S.top = -1;//用-1表示栈为空的状态

}

3.StackEmpty(S):判断S是否是空栈

bool StackEmpty(SqStack S){
    if(S.top == -1){
        return true;//注意,空的时候返回的是true
    }
    return false;
}

4.Push(&S,x):将x进栈

bool Push(SqStack &S,int x){
    //1.判断
    if(S.top == MaxSize-1){//想想为什么有-1
        //如果你想写的更好的话
        //栈满时候,我们一般会用remalloc扩加,并修改MaxSzie
        //这里一般不作扩加要求
        return false;
    }
    //2.修改
    S.top++;//比如初始化是top=-1,++以后top=0
    
    //3.赋值
    //这样我们才能放在第0个下标(第一个位子)上
    S.data[top] = x;
    //4.返回true
    return true;
}

5.Pop(&S,&x):将栈顶元素出栈并赋值给x

bool Pop(SqStack &S,int &x){
    //想想为什么x要加地址符
    //1.判断
    if(S.top == -1){
        return false;//如果是空栈的话,就出不了了
    }
    //2.赋值
    x = S.data[top];
    //3.修改
    top--;
    //4.返回成功
    return true;
}

6.GetTop(S,&x):将栈顶元素赋值给x(想想和5的区别):

bool Pop(SqStack S,int &x){
    //1.判断
    if(S.top == -1){
        return false;//如果是空栈的话,就出不了了
    }
    //2.赋值
    x = S.data[top];
    //3.返回成功
    return true;
}

7.GetNum(S):获取栈内元素个数(我自己加的,有助于理解top):

int GetSum(SqStack S){
    return S.top+1;
    //想想为什么要加+1    
    //同样是加1
    //为什么不是++S.top
    //或者为什么不是S.top++
}

三、共享栈和栈的链式存储结构

1.共享栈

我们发现,一个栈开辟50的初试空间,但是有很多时间用不了这么多,但是我们又担心那些极少数用到40多空间的情况。所以我们可以创建一个共享栈来解决问题,共享栈相当于一个T型的井:

这种情况下,栈的一些操作就需要发生变化了:

1.S1进栈:top1++,S1出栈:top1--;

2.S2进栈:top2--,S2出栈:top2++;

3.S1元素个数:top1 +1,s2元素个数:MaxSize-top2(这个比较难算,举个栗子就出来了);

4.S1栈空:top=-1,S2栈空:top=MaxSize;

5.栈满:top1 = top2-1;

2.栈的链式表示

这个比较好理解,因为顺序表示在栈满时候就加不进去了,而链式表示可以随便加。就比较方便操作。要注意的是链栈是采用不带头结点的头插法的。因为我们存储的是链表的头结点,每次都得遍历到最后一个结点。可以想想有没有解决的思路。这个一般不考。

四、习题

8.向一个栈顶指针为top的链栈中插入一个x结点,则执行()

因为链栈采用的是不带头结点的头插法。所以top指的就是栈顶元素,插入一个结点x,x->next =top。而这时候x为栈顶元素,所以要更新top,即top=x;

9.链栈执行Pop操作,并将出栈的元素存在x中,应该执行()

因为链栈采用的是不带头结点的头插法。所以top指的就是栈顶元素,Pop指的是返回栈顶元素,并将出栈。所以x = top->data,可以将栈顶元素存在x中。出栈的话,因为是头插法,所以top = top->next;

10.经过一下栈的操作后,变量x的值为()

InitStack(st);Push(st,a);Push(st,b);Pop(st,x);Top(st,x);

Push(st,a)后,栈内有a;Push(st,b)后,栈内有b,a(b在栈顶);Pop(st,x)表示把栈顶元素赋值给x,然后出栈,这时栈内只剩a,x = b;Top(st,x)表示把栈顶元素赋值给x,这时候x = a;

11.3个不同的元素依次进栈,能得到()种不同的出栈序列

这个就是死记硬背的东西,考试时候,如果数目小的话,可以硬枚举,公式考试前记一记就好了,也不太会考这么偏的。

24.设栈的初试状态为空,当字符序列“n 1 _”作为栈的输入时,输出长度为3,且可用作C语言标识符的序列有()个

这种情况,一共三个,所以可以暴力枚举,枚举的话可以主要看n的位置,我们先看栈能输出哪几种:

a)最后输出是nxx时候,可以发现“n 1 _ ” 和“n _ 1”,都可以通过栈输出出来,

b)最后输出是xnx时候,也就是n是第二个输出的,可以想到,第一个输出的只能是1,所以结果只能是“1 n _”

c)最后输出是xxn时候,n是最后一个输出的,结果可能是 “1 _ n”、“ _ 1 n”

OK,所有可能的结果都找出来了,我们看看:

“n 1 _ ” ,“n _ 1”,“1 n _”,“1 _ n”,“ _ 1 n”

可以看到,“1 n _”,“1 _ n”不可以,其他都可以,选C

27.判断共享栈满的条件是 top2 = top1 +1

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/zhangbaodan1/article/details/81257153
今日推荐