栈 and 队列

1. 概念 : 栈 vs 队列
1.1 栈

栈是一种特殊的线性表,只能在一端进行插入删除元素的操作。可以进行数据插入删除的一端称为栈顶,另一端称为栈底。 战中的元素遵循LIFO( Last In First Out )后进先出的原则

压栈:栈的元素插入操作称为压栈 / 入栈,入数据在栈顶

出栈:栈的删除操作称为出栈,出数据也在栈顶 

1.2 队列

队列也是一种特殊的线性表。队列只允许在一端进行插入操作,在另一端进行删除数据的操作

队列遵循FIFO( First In First Out ) 先进先出的原则

 2. 基本结构的实现 : 栈 vs 队列

栈可以使用链表或者数组进行实现 但是数组相对更优(数组在尾插数据的时候代价较小

栈也可以使用链表或者数组实现 链表更优( 出队列的时候删除数组首元素 "头删"  效率低

2.1 栈
2.1.1  静态栈

静态栈定长,实际一般不使用

typedef int SLDataType;
#define N 10
typedef struct Stack
{
    SLDataType arr[N];
    int top;
}Stack;
2.1.2 动态增长栈
 
typedef int SLDataType;
typedef struct Stack
{
    SLDataType* arr;
    int top;
    int capacity;
}Stack;

//初始化
void StackInit(Stack* ps){
    assert(ps);
    ps->arr = NULL;
    ps->capacity = 0;
}

//入栈
void StackPush(Stack* ps, SLDataType x){
    assert(ps);
    if(ps->top == ps->capacity){
        int newCapacity = ps->capacity = 0 ? 4 : 2 * ps->capacity;
        SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(Stack));
        
        assert(temp);
        ps->arr = temp;
        ps->capacity = newCapacity;
    }
    ps->arr[ps->top] = x;
    ps->top++;  
}

//出栈
void StackPop(Stack* ps){
    assert(ps);
    assert(ps->top > 0);
    ps->top--;
}

//获取栈顶元素
SLDataType StackTop(Stack* ps){
    assert(ps);
    assert(ps->top > 0);
    return ps->arr[ps->top - 1];
}

//获取栈顶有效元素的个数
int StackSize(Stack* ps){
    assert(ps);
    return ps->top;
}

//检测栈是否为空
bool StackEmpty(Stack* ps){
    assert(ps);
    return ps->top == 0;
}

//销毁栈
void StackDestrory(Stack* ps){
    assert(ps);
    
    free(ps->arr);
    ps->arr = NULL;
    ps->top = ps->capacity = 0;
}
2.2 队列
typedef int QDataType;
typedef struct QNode{
    struct QNode* next;
    QDataType val;
}QNode;
typedef struct Queue{
    QNode* head;
    QNode* tail;
    int size;
}Queue;

void QueueInit(Queue* pq){
    assert(pq);
    pq->head = pq->tail = NULL;
    pq->size = 0;
}

void QueueDestroy(Queue* pq){
    assert(pq);
    QNode* cur = pq->head;
    while(cur){
        QNode* next = cur->next;
        free(cur);
        cur = next;
    }
    pq->head = pq->tail = NULL;
    pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x){
    assert(pq);
    
    QNode* node = (QNode*)malloc(sizeof(QNode));
    assert(node);
    node->val = x;
    node->next = NULL;
    
    if(pq->head == pq->tail)
        pq->head = pq->tail = node;
    else{
        pq->tail->next = node;
        pq->tail = node;
    }
    ps->size++;
}

void QueuePop(Queue* pq){
    assert(pq && pq->head);
    
    QNode* node = pq->head;
    pq->head = pq->head->next;
    free(node);
    node = NULL;

    if(pq->head == NULL)
        pq->tail = NULL;
    
    pq->size--;
}

QDataType QueueFront(Queue* pq){
    assert(pq && pq->head);
    return pq->head->val;
}

QDataType QueueBack(Queue* pq){
    assert(pq && pq->tail);
    return pq->tail->val;
}

bool QueueEmpty(Queue* pq){
    assert(pq);
    return pq->head == NULL;
}

int QueueSize(Queue* pq){
    assert(pq);
    return pq->size;
}
3. some 经典题目们 :
3.1 括号匹配问题:

“有效的括号” : 数量 and 顺序 都匹配 

==== >>>>>     左括号入栈,取栈顶与右括号匹配      if no  ====  报错

===== >>>>>  栈为空 可以解决 左括号多右括号少 的问题,BUT   if  右多左少 怎么办 

=======》》》》 可以 一上来就先分别计算左右的数量 不符合直接false   再进行接下来操作

3.2 队列实现栈:

开两个队列 一个存数据,一个出数据的时候导数据 

3.3 设计循环队列:

循环队列是空间的重复利用

数组 / 循环链表 都OK  ===》》》 链表取队尾数据不方便 ==>> 双向循环链表 / backprev 指针

                                                       如果back指向尾,如何区分 1 和 空 ?  ( back 不能指向 -1  back  指针 ) ===== 》》》》  back 指向尾的下一个

【 使用数组解决】

front ,back 表示下标        数组空间之后,再开一个空间 size

判满 : front == back    ------ >>  (back + 1) % k == front   k:数组长度【不算size的空间

                                                    将存储数据的size 移动到数组首元素处 

front ——> back  :  有效空间

                                                                  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值