栈和队列常见oj题(括号匹配问题、栈实现队列、队列实现栈、设计循环队列)

一、括号匹配问题

1、题目要求: 

栈和队列常见oj题(括号匹配问题、栈实现队列、队列实现栈、设计循环队列)_第1张图片

 

2、大体思路

遍历这个字符串,如果是左括号就让它入栈,如果是右括号就让它和栈顶元素进行匹配(前提是栈中有元素),匹配成功的话就让栈顶元素出栈,匹配失败就返回false,直到遍历完字符串,如果遍历完了栈中没有元素,则返回true。

3、代码实现

bool isValid(char * s){
    Stack stack;
    StackInit(&stack);//初始化
    int i = 0;
    while(s[i] != '\0'){
        //入栈
        if(s[i] == '{' || s[i] == '[' || s[i] == '('){
            StackPush(&stack,s[i]);
        }else{
            //栈为空时
            if(StackEmpty(&stack)){
                StackDestroy(&stack);  //销毁栈
                return false;
            }
            if((StackTop(&stack) == '(' && s[i] == ')') ||
               (StackTop(&stack) == '{' && s[i] == '}') ||
               (StackTop(&stack) == '[' && s[i] == ']')){  
                   StackPop(&stack);   //匹配的话出栈
               }else{
                   //不匹配
                   StackDestroy(&stack);
                   return false;
               }
        }
        i++;
    }
    //遍历完后栈为空
    if(StackEmpty(&stack)){
         StackDestroy(&stack);
        return true;
    }
    StackDestroy(&stack);
    return false;
}

二、用队列实现栈

1、题目要求: 

栈和队列常见oj题(括号匹配问题、栈实现队列、队列实现栈、设计循环队列)_第2张图片

2、大体思路

用两个队列q1和q2来实现,要实现入栈的话可以选不为空的队列进行入队列操作(开始两个队列都可以),假设现在元素都在q1中,要实现出栈的话把q1中的元素放入q2中,直到q1中剩一个一个元素,在让它出队列。

3、代码实现

//用两个队列实现栈
typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* ms = (MyStack*)malloc(sizeof(MyStack));
    if(ms == NULL){
        return NULL;
    }
    QueueInit(&ms->q1);
    QueueInit(&ms->q2);
    return ms;
}

void myStackPush(MyStack* obj, int x) {
    //给不为空的队列加入元素,模拟入栈
    if(QueueEmpty(&obj->q1) ){
        QueuePush(&obj->q2,x);
    }else{
        QueuePush(&obj->q1,x);
    }
}

int myStackPop(MyStack* obj) {
    //当q1为空时,把q2中的元素放入q1中直到q2中只剩一个元素,然后q2再出队列,模拟出栈
    int ret = 0;
    if(QueueEmpty(&obj->q1)){
        while(QueueSize(&obj->q2) != 1){
            QueuePush(&obj->q1,QueueFront(&obj->q2));
            QueuePop(&obj->q2);
        }
        ret = QueueFront(&obj->q2);
        QueuePop(&obj->q2);
    }else{
         while(QueueSize(&obj->q1) != 1){
            QueuePush(&obj->q2,QueueFront(&obj->q1));
            QueuePop(&obj->q1);
        }
        ret = QueueFront(&obj->q1);
        QueuePop(&obj->q1);
    }
    return ret;
}
//栈顶元素相当于是队尾元素
int myStackTop(MyStack* obj) {
    if(QueueEmpty(&obj->q1)){
        return QueueBack(&obj->q2);
    }else{
        return QueueBack(&obj->q1);
    }
}

bool myStackEmpty(MyStack* obj) {
    if(QueueSize(&obj->q1) == 0 && QueueSize(&obj->q2) == 0){
        return true;
    }
    return false;
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

三、用栈实现队列

1、题目要求

栈和队列常见oj题(括号匹配问题、栈实现队列、队列实现栈、设计循环队列)_第3张图片

2、大体思路

用两个栈s1和s2来实现,s1用来模拟入队列,s2用来模拟出队列。实现入队列就直接对s1进行入栈操作;出队列的话,先判断s2中是否有元素,如果没有则把s1中的元素放入s2中,然后再对s2进行出栈操作。

3、代码实现

typedef struct {
    //s1用来入队列,s2用来出队列
    Stack s1;  
    Stack s2;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
    if(q == NULL){
        return NULL;
    }
    StackInit(&q->s1);
    StackInit(&q->s2);
    return q;
}
//入队列
void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->s1,x);
}
//出队列
int myQueuePop(MyQueue* obj) {
    //s2不为空的话先把s1中的元素搬移到s2中
    if(StackEmpty(&obj->s2)){
        while(!StackEmpty(&obj->s1)){
            StackPush(&obj->s2,StackTop(&obj->s1));
            StackPop(&obj->s1);
        }
    }
    int ret =  StackTop(&obj->s2);
    StackPop(&obj->s2);
    return ret;
    
}
//返回对头元素,和出队列差不多
int myQueuePeek(MyQueue* obj) {
    if(StackEmpty(&obj->s2)){
        while(!StackEmpty(&obj->s1)){
            StackPush(&obj->s2,StackTop(&obj->s1));
            StackPop(&obj->s1);
        }
    }
   return StackTop(&obj->s2);
}

bool myQueueEmpty(MyQueue* obj) {
    if(StackEmpty(&obj->s1) && StackEmpty(&obj->s2)){
        return true;
    }
    return false;
}

void myQueueFree(MyQueue* obj) {
    if(obj != NULL){
        StackDestroy(&obj->s1);
        StackDestroy(&obj->s2);
        free(obj);
    }
}

四、设计一个循环队列

1、题目要求

栈和队列常见oj题(括号匹配问题、栈实现队列、队列实现栈、设计循环队列)_第4张图片

2、大体思路

 循环队列是用顺序结构存储的。用两个指针来标记对头和队尾,如图:

 栈和队列常见oj题(括号匹配问题、栈实现队列、队列实现栈、设计循环队列)_第5张图片

 但这样会有一个问题,就是在队列为空和队列满了的情况下,rear和front都重合了,这样就不能判断是队列满了还是队列为空。解决这个问题有三种方法:

方法一: 我们可以少用一个存储空间,如图所示,这样就代表队列已经满了。

栈和队列常见oj题(括号匹配问题、栈实现队列、队列实现栈、设计循环队列)_第6张图片

 方法二:用一个flag进行标记,开始设为0,插入元素时将flag设为1,删除元素时设为0;这样当front等于rear时,判断一下flag就行了。

方法三:使用一个count进行计数,只有count为零时队列为空。

3、代码实现

这里用的是方法三

typedef struct {
    int* array;//存储数据
    int front; //对头
    int rear;  //队尾
    int count; //计数
    int N; //队列容量
} MyCircularQueue;

//初始化
MyCircularQueue* myCircularQueueCreate(int k) {
    //先给队列申请空间
    MyCircularQueue* q = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if(q == NULL ){
        return NULL;
    }
    //再给队列里的数组申请空间
    q->array = (int*)malloc(sizeof(int) * k);
    if(q->array == NULL){
        //如果失败,要先释放队列的空间,注意代码的严谨性
        free(q);
        return NULL;
    }
    q->front = q->rear = q->count = 0;
    q->N = k;
    return q;
}

//判断队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return 0 == obj->count;
}

//判断队列是否满了
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return obj->count == obj->N;
}

//入队列
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj)){
        return false;
    }
    obj->array[obj->rear] = value;
    if(obj->rear == obj->N - 1){
        obj->rear = 0;
    }else{
        obj->rear++;
    }
    obj->count++;
    return true;
}
//出队列
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj)){
        return false;
    }
    if(obj->front == obj->N - 1){
        obj->front = 0;
    }else{
        obj->front++;
    }
    obj->count--;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj)){
        return -1;
    }
    return obj->array[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj)){
        return -1;
    }
    //注意获取队尾元素的计算方法
    return obj->array[(obj->rear - 1 + obj->N) % obj->N];
}

//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {
    if(obj){
        if(obj->array){
            free(obj->array);
        }
        free(obj);nhj 
    }
}

你可能感兴趣的:(散列表,leetcode,数据结构,栈)