学习算法和数据结构:栈和队列

「学习算法和数据结构系列」,栈和队列同属于线性结构


栈和队列的特点

栈:LIFO(后进先出)
队列:FIFO(先进先出)
学习算法和数据结构:栈和队列_第1张图片
学习算法和数据结构:栈和队列_第2张图片

栈是限定仅在表尾进行插入和删除的线性表
队列是仅允许在一端插入在另一端删除的线性表

不论栈还是队列都是一种访问受限制的线性表


*补充:给定n个数,求所有可能的出栈顺序种类数;公式如下图所示:学习算法和数据结构:栈和队列_第3张图片
这可以看作是卡特兰数的一个应用,证明戳这里:http://blog.sina.com.cn/s/blog_6917f47301010cno.html(文章不长,不是我写的)


栈和队列的代码实现

不同的数据结构说白了就是一些包含系列操作集的数据集合

栈的特有操作集:弹栈(Pop),压栈(Push)
队列的特有操作集:进队列,出队列

不论栈还是队列都可以用“数组”或者“链表”来实现(顺序存储+链式存储)



栈的ADT
//ADT
Data
    同线性表;元素具有相同的类型,相邻元素间具有前趋和后继结点
Operation
    InitStack(*S):初始化操作,建立一个空栈S
    DestroyStack(*S):若栈存在,则销毁它
    ClearStack(S):将栈清空
    StackEmpty(S):若栈为空,返回true,否则返回false
    GetTop(S, *e):若栈存在且非空,则用e返回栈顶元素
    Push(*S, e):若栈S存在,插入新元素到栈S中并成为栈顶元素
    Pop(*S, *e):删除栈S中的栈顶元素,并用e返回
    StackLength(S):返回栈S的元素个数
endADT


栈的数组实现
typedef struct
{
    int data[MAXSIZE];  /*下标从0开始*/
    int top;  /*用于栈顶指针*/
}sqStack;

栈插入元素(进栈)

int Push(sqStack *S, int e)
{
    if(S->top == MAXSIZE-1){  /*栈满*/
        return -1;
    }
    S->top++;  /*栈顶指针增加一*/
    S->data[S->top] = e;  /*将新插入的元素赋值给栈顶空间*/
    return 0;
}

栈删除元素(出栈)

int Pop(sqStack *S, int *e)
{
    if(S->top == -1){
        return -1;
    }
    *e = S->data[S->top];  /*将要删除的元素赋值给e*/
    S->top--;  /*栈顶指针减一*/
    return 0;
}
栈的链表实现(链栈)

对于链表来说,不需要实现固定好大小,而且基本上不会出现没有空间的情况(除非计算机操作系统已经濒临死机崩溃)

typedef struct _snode
{
    int data;
    struct _snode *next;
}SNode, *LinkStackPtr;

typedef struct
{
    LinkStackptr top;
    int count;
}LinkStack;

栈插入元素(进栈)

int Push(LinkStack *S, int e)
{
    LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
    s->data = e;
    s->next = S->top;
    S->top = s;
    S->count++;
    return 0;
}

栈删除元素(出栈)

int Pop(LinkStack *S, int e)
{
    LinkStackPtr p;
    if(StackEmpty(*S)){
        return -1;
    }
    *e = S->top->data;
    p = S->top;
    S->top = S->top->next;
    free(p);
    S->count++;
    return 0;
}


循环队列的ADT
//ADT
Data
    同线性表;元素具有相同的类型,相邻元素具有前趋和后继关系
Operation
    InitQueue(*Q):初始化操作,建立一个空队列
    DestroyQueue(*Q):若队列Q存在,则销毁它
    ClearQueue(*Q):将队列Q清空
    QueueEmpty(Q):若队列Q为空,则返true,否则返回false
    GetHead(Q, *e):若队列Q存在且非空,用e返回队列Q的队头元素
    EnQueue(*Q):若队列Q存在,插入新元素e到Q中并成为队尾元素
    DeQueue(*Q, *e):删除队列Q中队头元素,并用e返回其值
endADT
循环队列的数组实现
typedef struct
{
    int data[MAXSIZE];
    int front;  /*头指针*/
    int rear;  /*尾指针,若队列不变,指向队列尾元素的下一个位置*/
}sqQueue;

循环队列初始化

int InitQueue(SqQueue *Q)
{
    Q->front = 0;
    Q->rear = 0;
    return 0;
}

循环队列长度

int QueueLength(sqQueue Q)
{
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

循环队列入队列

int EnQueue(sqQueue *Q, int e)
{
    if((Q->rear+1) % MAXSIZE == Q->front){  /*判断队列是否已满*/
        return -1;
    }
    Q->data[Q->rear] = e;  /*将e的值赋给队尾元素*/
    Q->rear = (Q->rear+1) % MAXSIZE;  /*rear指针向后移动一位,若到最后则转到数组的头部*/
    return 0;
}

循环队列出队列

int DeQueue(sqQueue *Q, int e)
{
    if(Q->front == Q->rear){  /*判断队列是否为空*/
        return -1;
    }
    *e = Q->data[Q->front];  /*将队头元素赋给e*/
    Q->front = (Q->front+1) % MAXSIZE;  /*front指针向后移动一位,若到最后则转到数组的头部*/
    return 0;
}
队列的链表实现(链队列)
typedef strut _qNode  /*结点结构*/
{
    int data;
    struct _qNode *next;
}QNode, *QueuePtr;
typedef struct  /*队列的链表结构(和栈一样的套路,先隔离再整体)*/
{
    QueuePtr front, rear;  /*队头、队尾指针*/
}LinkQueue;

元素入队

int EnQueue(LinkQueue *Q, int e)
{
    QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
    if(!s){  /*内存分配失败*/
        exit(OVERFLOW);
    }
    s->data = e;
    s->next = NULL;
    Q->rear->next = s;  /*把拥有元素e的新结点s赋给原队尾结点的后继*/
    Q->rear = s;  /*把当前的s设置为队尾结点,rear指向s*/
    return 0;
}

元素出队

int DeQueue(LinkQueue *Q, int e)
{
    QueuePtr p;
    if(Q->front == Q->rear){
        return -1;
    }
    p = Q->front->next;  /*将要删除的队头结点暂存给p*/
    *e = p->data;  /*将要删除的队头结点赋给e*/
    Q->front->next = p->next;  /*将原队头结点后继p->next赋给头结点后继*/
    if(Q->rear == p){  /*若头结点是队尾,则删除后将rear指向头结点*/
        Q->rear == Q->front;
    }
    free(p);
    return 0;
}

你可能感兴趣的:(算法和数据结构)