Collection of stack and queue exercises (continuously updated)

Question 1 (bracket matching)

Given a string s consisting only of '(', ')', '{', '}', '[', ']', determine whether the string is valid.

A valid string must satisfy:

1. An opening bracket must be closed with a closing bracket of the same type.

2. Opening brackets must be closed in the correct order.

3. Each closing parenthesis has a corresponding opening parenthesis of the same type.

char pairs(char* ch)
{
    if(*ch=='}')
    return '{';
    if(*ch==')')
    return '(';
    if(*ch==']')
    return '[';
    return 0;
}
bool isValid(char * s){
    char stack[10000]={0};
    int top=0,i=0;
    while(*(s+i))
    {
        char ch=pairs(s+i);
        if(ch)
        {
            if(top==0||ch!=stack[top-1])//这里需要判断栈是否为空的原因是没有左括号还在匹配会造成越界
            {
                return false;
            }
            else
            {
                top--;
            }
        }
        else
        {
            stack[top++]=*(s+i);
        }
        i++;
    }
        return top==0;

}

The second question (using a queue to simulate a stack)

The reason why it is necessary to judge whether the stack is empty here is that there is no left parenthesis and still matching will cause out-of-bounds

Please use only two queues to implement a last-in-first-out (LIFO) stack, and support all four operations (push, top, pop, and empty) of a normal stack.

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));

    QueueInit(&obj->q1);
    QueueInit(&obj->q2);

    return obj;
}

void myStackPush(MyStack* obj, int x) {
    assert(obj);

    if (!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1);
    }
    else
    {
        QueuePush(&obj->q2);
    }
    return;
}

int myStackPop(MyStack* obj) {
    Queue* pEmpty = &obj->q1;//注意左右两边的类型要匹配
    Queue* pNonEmpty = &obj->q2;
    if (!QueueEmpty(pEmpty))
    {
        Queue* pEmpty = &obj->q2;
        Queue* pNonEmpty = &obj->q1;
    }
    while (QueueSize(pNonEmpty) > 1)
    {
        QueuePush(pNonEmpty, QueueFront(pNonEmpty));
        QueuePop(pNonEmpty);
    }
    int top = QueueFront(pNonEmpty);
    QueuePop(pNonEmpty);
    return top;
}

int myStackTop(MyStack* obj) {
    Queue* pEmpty = &obj->q1;
    Queue* pNonEmpty = &obj->q2;
    if (!QueueEmpty(pEmpty))
    {
        Queue* pEmpty = &obj->q2;
        Queue* pNonEmpty = &obj->q1;
    }
    return QueueBack(pNonEmpty);
}

bool myStackEmpty(MyStack* obj) {
    if (!(QueueEmpty(&obj->q2)) && !(QueueEmpty(&obj->q1)))
    {
        return false;
    }
    return true;
}

void myStackFree(MyStack* obj) {
    QueueDestory(&obj->q1);//free可能会free不干净,万一是链式结构呢?
    QueueDestory(&obj->q2);
    free(obj);
}

Question 3 (Simulating a queue with a stack)

Please use only two stacks to implement a first-in-first-out queue. The queue should support all operations supported by general queues (push, pop, peek, empty):

Implement the MyQueue class:

void push(int x) pushes element x to the end of the queue

int pop() removes and returns an element from the beginning of the queue

int peek() returns the element at the head of the queue

boolean empty() returns true if the queue is empty; otherwise, returns false

illustrate:

You can only use standard stack operations -- that is, only push to top, peek/pop from top, size, and is empty operations are legal.

Your language may not support stacks. You can use list or deque (double-ended queue) to simulate a stack, as long as it is a standard stack operation.

problem solving ideas

It can be implemented with two stacks, one stack for enqueue operation, we call it enqueue stack , and the other stack for dequeue operation, we call it dequeue stack

Dequeue operation: When the dequeue stack is not empty, the dequeue operation is performed directly. If it is empty, all elements of the dequeue stack need to be imported into the dequeue stack, and then the dequeue operation is performed.

#define maxSize 100
typedef struct {
    //入队栈
    Stack pushST;
    //出队栈
    Stack popST;
} MyQueue;
 
/** Initialize your data structure here. */
MyQueue* myQueueCreate(int maxSize) {
    MyQueue* pqueue = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&pqueue->pushST, maxSize);
    StackInit(&pqueue->popST, maxSize);
    return pqueue;
}
 
/** Push element x to the back of queue. */
void myQueuePush(MyQueue* obj, int x) {
    //入队栈进行入栈操作
    StackPush(&obj->pushST, x);
}
 
/** Removes the element from in front of queue and returns that element. */
int myQueuePop(MyQueue* obj) {
    //如果出队栈为空,导入入队栈的元素
    if(StackEmpty(&obj->popST) == 0)
    {
        while(StackEmpty(&obj->pushST) != 0)
        {
            StackPush(&obj->popST, StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    
    int front = StackTop(&obj->popST);
    //出队栈进行出队操作
    StackPop(&obj->popST);
    return front;
}
 
/** Get the front element. */
int myQueuePeek(MyQueue* obj) {
    //类似于出队操作
    if(StackEmpty(&obj->popST) == 0)
    {
        while(StackEmpty(&obj->pushST) != 0)
        {
            StackPush(&obj->popST, StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    
    return StackTop(&obj->popST);
}
 
//判断栈是否为空
bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->pushST) == 0
        &&  StackEmpty(&obj->popST) == 0;
}
 
void myQueueFree(MyQueue* obj) {
    StackDestroy(&obj->pushST);//与上题一样不能直接free,要交给栈的销毁函数来做
    StackDestroy(&obj->popST);
    
    free(obj);
}

Question 4 (Design Circular Queue)

Design your circular queue implementation. A circular queue is a linear data structure whose operation is based on the FIFO (first in first out) principle and the tail of the queue is connected after the head of the queue to form a loop. It is also known as a "ring buffer".

One benefit of circular queues is that we can utilize previously used space on this queue. In a normal queue, once a queue is full, we cannot insert the next element, even if there is still room at the front of the queue. But with a circular queue, we can use this space to store new values.

Your implementation should support the following operations:

MyCircularQueue(k): Constructor, set the queue length to k.

Front: Get elements from the front of the queue. Returns -1 if the queue is empty.

Rear: Get the element at the end of the queue. Returns -1 if the queue is empty.

enQueue(value): Insert an element into the circular queue. Returns true if the insertion was successful.

deQueue(): Remove an element from the circular queue. Returns true if the deletion was successful.

isEmpty(): Checks if the circular queue is empty.

isFull(): Checks if the circular queue is full.

#define dataType int 

typedef struct {
    dataType* arr;
    int front;
    int rear;
    int size;
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* ret = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if (ret == NULL)
    {
        perror("malloc::fail");
    }
    ret->arr = (dataType*)malloc(sizeof(dataType) * (k + 1));
    ret->front = ret->rear = 0;
    ret->size =k+1;
    return ret;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if (((obj->rear + 1) %obj->size) == obj->front)//判断循环队列是否为满,%不是/
    {
        return false;
    }
    obj->arr[obj->rear] = value;
    obj->rear=(obj->rear+1)%obj->size;//不需要加MaxSize
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if (obj->rear == obj->front)
    {
        return false;
    }
    obj->front= (obj->front +1) % obj->size;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if (obj->rear == obj->front)
    {
        return -1;
    }
    return obj->arr[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if (obj->rear==obj->front)
    {
        return -1;
    }
    //因为是先存数据在加加,所以rear实际上是指向队尾的下一个元素
    //故最好在此处进行分类讨论
    if(obj->rear==0)
    {
        return obj->arr[obj->size-1];
    }
    else
    {
        return obj->arr[obj->rear-1];
    }

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front == obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if (obj->front == (obj->rear + 1 + obj->size) % obj->size)
    {
        return true;
    }
    return false;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);//双层释放
    free(obj);
}

/**
 * Your MyCircularQueue struct will be instantiated and called as such:
 * MyCircularQueue* obj = myCircularQueueCreate(k);
 * bool param_1 = myCircularQueueEnQueue(obj, value);
 
 * bool param_2 = myCircularQueueDeQueue(obj);
 
 * int param_3 = myCircularQueueFront(obj);
 
 * int param_4 = myCircularQueueRear(obj);
 
 * bool param_5 = myCircularQueueIsEmpty(obj);
 
 * bool param_6 = myCircularQueueIsFull(obj);
 
 * myCircularQueueFree(obj);
*/

Guess you like

Origin blog.csdn.net/m0_74234485/article/details/129346934