数据结构-王道-栈和队列

栈和队列

       栈(Stack):只允许在一端进行插入或者删除操作的线性表。首先栈是一种线性表,但是限定在这种线性表中只能在某一端进行插入和删除操作。
       栈顶:线性表(栈)允许进行插入和删除操作的一端。
       栈底:固定的,不允许进行插入和删除操作的另一端。
       空栈:不含任何元素的空表。

栈的顺序储存结构

       栈的顺序储存称为顺序栈,他是利用一组地址连续的储存单元存放自栈底到栈顶的数据元素,同时附设一个指针(top)指示当前栈顶的位置。
       栈的顺序储存类型可以描述为:

#define MaxSize 50 //定义栈中元素的最大个数
typedef struct
{
    int data[MaxSize];
    int top;
}SqStack;

       栈顶指针:S.top,初始设置为S.top=-1;栈顶元素:S.data[S.top]。
       进栈操作:栈不满时,栈顶指针先加1,再送值到栈顶空间。
       出栈操作:栈非空的时候,先取栈顶的元素,再将栈顶指针-1.
       栈空条件:S.top=-1;栈满条件:S.top==MaxSize-1;栈长S.top+1。


初始化

void InitStack(SqStack &S)
{
    S.top=-1;
}

栈是否为空?

bool StackEmpty(SqStack S)
{
    if(S.top==-1)
        return true;
    else
        return false;
}

压栈操作

bool Push(SqStack &S,int x)
{
    if(S.top==MaxSize-1)
        return false;
    S.data[++S.top]=x;// 先加 然后在赋值
    return true;
}

出栈操作

bool Pop(SqStack &S,int &x)
{
    if(S.top==-1)
        return false;
    x=S.data[S.top--];//先取值,然后再减
    return true;
}

得到栈顶元素

bool GetTop(SqStack S,int &x)
{
    if(S.top==-1)
        return false;
    x=S.data[S.top];
    return true;
}

注意:这里的栈顶指针指向的就是栈顶元素,所以进栈操作是\(S.data[++S.top]=x;\),出栈操作是\(x=S.data[S.top--];\)。如果栈顶指针指向栈顶元素的下一个位置,则入栈操作变为\(S.data[S.top++]=x;\),出栈操作变为\(x=S.data[--S.top]\)。相应的栈空,栈满条件也会发生变化。

共享栈

       利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一位数据空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸,如图所示

Alt text

       两个栈的站定指针都指向栈顶元素, \(top_0=-1\)\(0\)号栈为空, \(top_1=MaxSize\)\(1\)号栈为空;
\(top_1-top_0=1\)时,判断栈满。当0号栈进展时 \(top_0\)\(+1\)然后赋值, \(1\)好战进站时 \(top_1\)\(-1\)再赋值;出栈刚好相反。
       共享栈是为了更有效的利用储存空间,两个栈的空间互相调节,只有在整体储存空间都被栈满的时候才会发生上溢。其存取数据的时间复杂度均为 \(O(1)\),所以对存取效率没有什么影响。

栈的链式储存结构

       采用链式储存的栈通常称为链栈,链栈的优点是便于多个共享储存空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并规定所有操作都是在单链表的表头进行的。这里规定链栈没有头结点,Lhead指向栈顶元素。Alt text


       栈的链式存储类型可以描述为

typedef struct LinkNode
{
    int data;
    struct LinkNode *next;
}*LiStack;

       采用链式存储,便于节点的插入和删除。链栈的操作和链表类似。

注意一下卡特兰数\(\frac {1}{n+1}\ast C_n^{2n}\)。n个元素一次进栈,能得到几中不同的出栈序列。

队列

       队列(Queue):简称队,是一种操作受限的线性表只允许在表的一端进行插入,而在表的另一端进行删除操作。其操作特性为:FIFO。
       队头(Front):允许删除的一端,又称为队首。       队尾(Rear):允许插入的一端。
       空队列:不含任何元素的空表。

队列的顺序储存结构

队列的顺序储存

队列的顺序实现是指分配一块连续的储存单元存放队列中的元素,并且辐射两个指针front和rear分别指示队头元素和队尾元素的下一个位置,对于这种设置方式,参考下方图。

Alt text

队列的顺序储存类型可描述为:

#define MaxSize 50
typedef struct
{
    int data[MaxSize];
    int front,rear;
}SqQueue;
  • 初始状态(队空条件):\(Q.front==Q.rear==0\)
  • 进队操作:队不满的时候,先送值到队尾元素,再将队尾指针\(+1\)
  • 出队操作:队不空的时候,先取队头元素值,再将队头指针\(+1\)
           观察一下上面的,可以发现很尴尬的一个事情是到了(d)出队三次的时候虽然还有空间,但是已经不能继续储存了。

    循环队列

           前面的问题是一定要有解决方案的不然还搞个基儿。聪明的人们,想出来了一种自给自足的方法。将顺序队列臆造为一个环状的空间,即把存出队列元素的表从逻辑上看为一个环,称为循环队列。当队首指针\(Q.front=MaxSize-1\)
  • 初始时:\(Q.front=Q.rear=0\)
  • 队首指针进1:\(Q.front=(Q.front+1) \% MaxSize\)
  • 队尾指针进1:\(Q.rear=(Q.rear+1) \% MaxSize\)
  • 队列长度:\((Q.rear+MaxSize-Q,front)\%MaxSize\)

初始化。

void InitQueue(SqQueue &Q)
{
    Q.rear=Q.front=0;
}

判队空。

bool IsEmpty(SqQueue Q)
{
    if(Q.rear==Q.front)
        return true;
    else
        return false;
}

判队满。

bool IsFull(SqQueue Q)
{
    if((Q.rear+1)%MaxSize==Q.front)
        return true;
    else
        return false;
}

出队。

bool DeQueue(SqQueue &Q,int &x)
{
    if(IsEmpty(Q))
        return false;
    x=Q.data[Q.front];
    Q.front=(Q.front+1)%MaxSize;
    return true;
}

入队。

bool InQueue(SqQueue &Q,int x)
{
    if(IsFull(Q))
        return false;
    Q.data[Q.rear]=x;
    Q.rear=(Q.rear+1)%MaxSize;
    return true;
}

队列的链式存储结构

       队列的链式存储:队列链式表示称为链队列,它实际上是一个同时带有队头指针和队尾指针的单链表,尾指针指向队尾节点,即单链表的最后一个结点(注意与顺序存储的不同)。

队列的链式存储可描述为

#ifndef NULL
    #ifdef __cplusplus
        #define NULL    0
    #else  /* __cplusplus */
        #define NULL    ((void *)0)
    #endif  /* __cplusplus */
#endif  /* NULL */
typedef struct LinkNode // 搞一个单链表
{
    int data;
    struct LinkNode *next;
};
typedef struct LinkQueue// 搞一个包含两个单链表类型的指针。
{
    LinkNode *front,*rear;
};

初始化

void InitQueue(LinkQueue &Q)
{
    Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode));
    Q.front->next=NULL;
}

判断队空

bool IsEmpty(LinkQueue Q)
{
    if(Q.front==Q.rear)
        return true;
    else
        return false;
}

入队

void EnQueue(LinkQueue &Q,int x)
{
    LinkNode* s=(LinkNode*)malloc(sizeof(LinkNode));
    s->data=x;
    s->next=NULL;
    Q.rear->next=s;
    Q.rear=s;
}

出队

int DeQueue(LinkQueue &Q,int &x)
{
    if(Q.rear==Q.front->next)           // 如果删除的是最后一个节点,也就是Q.rear指向的节点。
        Q.rear=Q.front;                 // Q.rear 和 Q.front的值 应该相同。这样就空了。
    else
        if(Q.front==Q.rear)
            return false;
    x=Q.front->next->data;
    Q.front->next=Q.front->next->next;  // 删除该节点
    return true;
}
链式队列:初始化的时候front和rear是指向同一个位置的也就是指向头结点,这个时候的状态就是队空,front永远指向头指针,rear指向最后一个元素的位置。

@[括号匹配]

#include<stdio.h>
#include<stdlib.h>
#define MaxSize 50
#ifndef NULL
    #ifdef __cplusplus
        #define NULL    0
    #else  /* __cplusplus */
        #define NULL    ((void *)0)
    #endif  /* __cplusplus */
#endif  /* NULL */
#define MaxSize 50 //定义栈中元素的最大个数
typedef struct
{
    char data[MaxSize];
    int top;
}SqStack;
void InitStack(SqStack &S)
{
    S.top=-1;
}
bool StackEmpty(SqStack S)
{
    if(S.top==-1)
        return true;
    else
        return false;
}
bool Push(SqStack &S,char x)
{
    if(S.top==MaxSize-1)
        return false;
    S.data[++S.top]=x;// 先加 然后在赋值
    return true;
}
bool Pop(SqStack &S,char &x)
{
    if(S.top==-1)
        return false;
    x=S.data[S.top--];//先取值,然后再减
    return true;
}
bool GetTop(SqStack S,char &x)
{
    if(S.top==-1)
        return false;
    x=S.data[S.top];
    return true;
}
int main()
{
    char fu;
    SqStack S;
    InitStack(S);
    while(scanf("%c",&fu)!=EOF)
    {
        if(fu=='\n')
            break;
        if(StackEmpty(S))
        {
            Push(S,fu);
            continue;
        }
        else
        {
            char pi,temp;
            GetTop(S,pi);
            if(fu==')'||fu==']')
            {
                if(pi=='['&&fu==']')
                    Pop(S,temp);
                if(pi=='('&&fu==')')
                    Pop(S,temp);
            }
            else
                Push(S,fu);
        }
    }
    if(StackEmpty(S))
        printf("匹配成功\n");
    else
        printf("匹配失败\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/A-FM/p/9660206.html