zoukankan      html  css  js  c++  java
  • 数据结构-王道-栈和队列

    栈和队列

           栈(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](http://pfap49gih.bkt.clouddn.com/1537035762554.png)
           两个栈的站定指针都指向栈顶元素,$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](http://pfap49gih.bkt.clouddn.com/1537036690120.png)

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

    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](http://pfap49gih.bkt.clouddn.com/1537089878191.png)
    > 队列的顺序储存类型可描述为:
    #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=='
    ')
                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("匹配成功
    ");
        else
            printf("匹配失败
    ");
        return 0;
    }
    
  • 相关阅读:
    iOS-iOS8模拟器设置中文键盘
    iOS-应用性能调优的25个建议和技巧
    IOS-通讯录
    IOS-录音
    IOS-视频
    IOS-音乐
    IOS-音效
    iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式
    Android 带你玩转实现游戏2048 其实2048只是个普通的控件(转)
    Android TagFlowLayout完全解析 一款针对Tag的布局(转)
  • 原文地址:https://www.cnblogs.com/A-FM/p/9660206.html
Copyright © 2011-2022 走看看