Interview questions about stacks and queues (1)

One: To implement a stack, the time complexity required to implement Push (out of the stack), Pop (into the stack), and Min (return to the minimum value) is O(1)

method one:

Idea: Here we use the static sequence table implementation at the bottom of the stack. We can easily achieve the time complexity of O(1) when popping the stack and inserting the stack. However, to return the minimum value, according to our conventional thinking, traverse the stack, you can The minimum value is obtained, but the time complexity is O(n), which does not meet the requirements of the title. We can put two data in the stack at a time, one is the data to be placed, and the other is Mindata. The data is encapsulated into a structure. If the stack is empty, we can make the value of Mindata equal to data. If it is not empty, we can compare the data in the new element with the Mindata in the top element of the stack. If the data in the new element is If it is less than or equal to the top of the stack, the value of Mindata in the new element can be equal to data. If it is greater than the Mindata in the top element of the stack, the data in the new element remains unchanged, and Mindata is updated to the Mindata in the top element of the stack.

Suppose now that we put: 5, 2, 3, 1 into the stack in turn Mindata5 in the new element, so both data and Mindata in the new element are 2, then 3 is placed, because 3 is greater than Mindata2 in the top element of the stack, data in all new elements is 3, Mindata is 2, and finally 1 is placed, the process is as follows picture:
write picture description here

The code is implemented as follows:

StackAndQueueInterview.h

#pragma once


#include <stdio.h>
#include <assert.h>

#define MAX_SIZE 100
//将本来的数据和最小值封装为一个结构体
typedef struct NewData
{
    int data;
    int Mindata;
}Newdata;

typedef struct Stack
{
    Newdata _arr[MAX_SIZE];//栈里面放的都是封装好的结构体
    int _size;
}Stack, *PStack;


//初始化栈
void InitStack(PStack s);
//给栈顶插入元素
void StackPush(PStack s, int data);
void StackPop(PStack s);//出栈
//返回栈最小元素
int StackMindata(PStack s);

StackAndQueueInterview.c

#include "StackAndInterview.h"

//初始化栈
void InitStack(PStack s)
{
    assert(s);

    //初始化只需将有效元素清零
    s->_size = 0;
}


//给栈顶插入元素
void StackPush(PStack s, int data)
{
    assert(s);

    int size = s->_size;

    if (size == MAX_SIZE)
    {
        printf("栈已满!!!\n");
        return;
    }

    //如果栈是空的,那么最小data和data都是data
    if (size == 0)
    {
        s->_arr->data = s->_arr->Mindata = data;
        s->_size++;
        return;
    }

    //如果栈不为空,比较data与栈的最小元素,1.若data小,那么用data更新最小元素
    if ((s->_arr + size - 1)->Mindata >= data)
    {
        (s->_arr + size)->Mindata = (s->_arr + size)->data = data;
        s->_size++;
        return;
    }
    //2.若栈的最小元素小,新插入的data还是data,Mindata用原栈中的Mindata更新
    else
    {
        (s->_arr + size)->Mindata = (s->_arr + size - 1)->Mindata;
        (s->_arr + size)->data = data;
        s->_size++;
    }

}

//从栈顶出栈
void StackPop(PStack s)
{
    assert(s);

    if (s->_size == 0)
    {
        printf("栈已空!!!\n");
        return;
    }

    s->_size--;
}

//返回栈最小元素
int StackMindata(PStack s)
{
    assert(s);

    if (s->_size == 0)
    {
        printf("栈已空,操作失败!!!\n");
        return 0;
    }

    return (s->_arr + (s->_size - 1))->Mindata;
}

test.c

Test environment: vs2031

#include "StackAndInterview.h"
#include <Windows.h>


int main()
{
    Stack s;

    InitStack(&s);

    StackPush(&s, 5);
    StackPush(&s, 4);
    StackPush(&s, 2);
    StackPush(&s, 3);
    StackPush(&s, 7);
    StackPush(&s, 9);
    StackPush(&s, 1);

    StackPop(&s);
    printf("Mindata:%d\n",StackMindata(&s));
    system("pause");
    return 0;
}

Method Two:

Idea: We can use two stacks to store data, one for data and one for Mindata. The top element of the Mindata stack must be the smallest element in the stack at this time, and then the two stacks are encapsulated into one stack. The requirements in the title can be fulfilled.

Suppose we still put: 5, 2, 3, 1 in the stack in turn. If the data stack is empty at this time, it means that the Mindata stack is also empty. When 5 is placed, both stacks are empty, so put 5 directly into the stack. If the data to be placed, 2 is less than or equal to the top element of the Mindata stack, then 2 is also placed in the Mindata stack, otherwise, ignore it. The operation is shown in the following figure:
write picture description here

If you want to take the minimum value, take the top element of the Mindata stack, so that the time complexity can be O(1). The code is implemented as follows:

StackAndInterview.h

#pragma once


#include <stdio.h>
#include <assert.h>


#define MAX_SIZE 100

typedef int DataType;

//存放平常数据的栈
typedef struct Stack1
{
    DataType _arr[MAX_SIZE];
    int _size;
}Stack1;

//存放最小数据的栈
typedef struct Stack2
{
    DataType _arr[MAX_SIZE];
    int _size;
}Stack2;

//将两个栈封装为1个
typedef struct Stack
{
    Stack1 s1;
    Stack2 s2;

}Stack, *PStack;




//初始化栈
void InitStack(PStack s);
//入栈
void StackPush(PStack s, DataType data);
//获取栈顶元素
DataType StackTop(Stack2* s2);
//出栈
void StackPop(PStack s);
//获取最小值
DataType StackMindata(PStack s);

StackAndInterview.c

#include "StackAndInterview.h"

//初始化栈
void InitStack(PStack s)
{
    assert(s);

    //将两个栈分别初始化
    s->s1._size = 0;

    s->s2._size = 0;
}

//入栈
void StackPush(PStack s, DataType data)
{
    assert(s);

    if (s->s1._size == MAX_SIZE)
    {
        printf("栈已满!!!\n");
        return;
    }

    //若栈为空,直接入栈
    if (s->s1._size == 0)
    {
        s->s1._arr[0] = data;
        s->s2._arr[0] = data;
        s->s1._size++;
        s->s2._size++;
    }
    else
    {
        //如果data小于,s2栈中的栈顶元素,将data入栈到S2
        if (data <= StackTop(&(s->s2)))
        {
            s->s2._arr[s->s2._size] = data;
            s->s2._size++;
        }
        s->s1._arr[s->s1._size] = data;
        s->s1._size++;
    }

}


//获取栈顶元素
DataType StackTop(Stack2* s2)
{
    assert(s2);

    if (s2->_size == 0)
    {
        printf("栈已空!!!\n");
        return 0;
    }

    return s2->_arr[s2->_size - 1];
}

//出栈
void StackPop(PStack s)
{
    assert(s);

    if (s->s1._size == 0)
    {
        printf("栈已空!\n");
        return;
    }

    //如果两个栈栈顶元素相等,都出栈
    if (s->s1._arr[s->s1._size - 1] == StackTop(&(s->s2)))
    {
        s->s1._size--;
        s->s2._size--;
    }

    else
        s->s1._size--;
}

//获取最小值
DataType StackMindata(PStack s)
{
    assert(s);

    if (s->s1._size == 0)
    {
        printf("栈已空!!!\n");
        return 0;
    }

    return StackTop(&(s->s2));
}

test.c

#include "StackAndInterview.h"
#include <Windows.h>


int main()
{
    Stack s;

    InitStack(&s);
    StackPop(&s);
    StackPush(&s, 5);
    StackPush(&s, 4);
    StackPush(&s, 2);
    StackPush(&s, 3);
    StackPush(&s, 7);
    StackPush(&s, 9);
    StackPush(&s, 1);

    StackPop(&s);
    printf("Mindata:%d\n", StackMindata(&s));

    system("pause");
    return 0;
}

Two: use two stacks to implement a queue

Idea: First of all, we must figure out what the characteristics of the stack and the queue are. The stack, first-in, last-out, can only be pushed and popped from the top of the stack; while for the queue, first-in, first-out, the queue is entered from the end of the queue. Operation, dequeue operation from the head of the queue. Suppose we have two stacks s1 and s2, s1 is used for the enqueue operation, and s2 is used for the dequeue operation. As shown in the figure below, we need to insert elements 5, 4, and 9 into the queue in turn, because we put the elements into the queue in turn. Stack s1, if it is a queue, we first dequeue element 5, but since the element is in stack s1, we cannot directly pop the element at the bottom of the stack, so we can push the elements in s1 into the stack to s2
write picture description here
. As shown in the figure below:
write picture description here
At this point, the element at the head of the queue is the top element of the stack s2. To pop out of the queue, we can directly pop the stack on s2. Suppose we now want to insert elements 2 and 4 into the queue in turn, as shown in the following figure:
write picture description here
From the above three figures, we can draw: Assuming that s1 is not empty and s2 is empty, then the head of the queue is the bottom of the stack of s1, and the tail of the queue is The top of the stack of s1; assuming that s1 is empty and s2 is not empty, then the head of the queue is the top of the stack of s2, and the tail of the queue is the bottom of the stack of s2; assuming that neither s1 nor s2 is empty, then the head of the queue is the top of the stack of s2, The tail of the queue is the top of the stack of s1. The specific code is implemented as follows:

StackAndInterview.h

#pragma once

#include <stdio.h>
#include <assert.h>


typedef int DataType;

#define MAX_SIZE 3


typedef struct Stack
{
    DataType _arr[MAX_SIZE];
    int _size;
}Stack;


typedef struct Queue
{
    Stack s1;
    Stack s2;
}Queue, *PQueue;



//初始化队列
void QueueInit(PQueue q);
//入栈
void StackPush(Stack* s, DataType data);
//入队列,入到栈s1
void QueuePush(PQueue q, DataType data);
//返回栈顶元素
DataType StackTop(Stack* s);
//出栈
void StackPop(Stack* s);
//出队列
void QueuePop(PQueue q);
//获取队头元素
DataType QueueFront(PQueue q);
//获取队尾元素
DataType QueueBack(PQueue q);

StackAndInterview.c

#include "StackAndInterview.h"


//初始化队列
void QueueInit(PQueue q)
{
    assert(q);

    //对两个栈进行初始化
    q->s1._size = 0;
    q->s2._size = 0;
}

//入栈
void StackPush(Stack* s, DataType data)
{
    assert(s);

    if (s->_size == MAX_SIZE)
    {
        printf("栈已满!!!\n");
        return;
    }

    s->_arr[s->_size] = data;
    s->_size++;
}

//入队列,入到栈s1
void QueuePush(PQueue q, DataType data)
{
    assert(q);

    if (q->s1._size == MAX_SIZE)
    {
        //如果s2为空,才能将s1中的元素搬移到s2否则,队头和就找不到了
        if (q->s2._size == 0)
        {

            while (q->s1._size != 0)
            {
                DataType data = StackTop(&(q->s1));
                StackPop(&(q->s1));
                StackPush(&(q->s2), data);
            }
        }
        else
        {
            printf("队列已满!!!\n");
            return;
        }

    }

    //对s1进行入栈操作
    StackPush(&(q->s1), data);
}


//返回栈顶元素
DataType StackTop(Stack* s)
{
    assert(s);

    if (s->_size == 0)
    {
        printf("栈已空!\n");
        return 0;
    }

    return s->_arr[s->_size - 1];
}

//出栈
void StackPop(Stack* s)
{
    assert(s);

    if (s->_size == 0)
    {
        printf("栈为空,操作失败!!!\n");
        return;
    }

    s->_size--;
}

//出队列
void QueuePop(PQueue q)
{
    assert(q);

    //如果s2不为空,那么s2的栈顶元素就是队头,直接出队列
    if (q->s2._size > 0)
    {
        StackPop(&(q->s2));
        return;
    }

    //如果s2为空
    else
    {
        //如果s1也为空,队列为空
        if (q->s1._size == 0)
        {
            printf("队列为空,操作失败!!!\n");
            return;
        }

        //如果s1不为空,将s1的数据倒过来
        else
        {
            while (q->s1._size != 0)
            {
                DataType data = StackTop(&(q->s1));
                StackPop(&(q->s1));
                StackPush(&(q->s2), data);
            }

            //此时,s2的栈顶就是队头
            StackPop(&(q->s2));
        }

    }
}


//获取队头元素
DataType QueueFront(PQueue q)
{
    assert(q);

    //如果s1和s2都为空,说明队列为空
    if (q->s1._size == 0 && q->s2._size == 0)
    {
        printf("队列为空,操作失败!!!\n");
        return 0;
    }

    //如果s2不为空,那么队头就是s2的栈顶,否则,就是s1的栈底
    if (q->s2._size != 0)
        return StackTop(&(q->s2));
    else
        return q->s1._arr[0];

}

//获取队尾元素
DataType QueueBack(PQueue q)
{
    assert(q);

    //如果s1和s2都为空,说明队列为空
    if (q->s1._size == 0 && q->s2._size == 0)
    {
        printf("队列为空,操作失败!!!\n");
        return 0;
    }

    //如果s1不为空,那么队尾就是s1的栈顶,否则,就是s2的栈底
    if (q->s1._size != 0)
        return StackTop(&(q->s1));
    else
        return q->s2._arr[0];

}

test.c

#include "StackAndInterview.h"
#include <Windows.h>


void Test3()
{
    Queue q;

    QueueInit(&q);

    QueuePush(&q, 5);
    QueuePush(&q, 4);
    QueuePush(&q, 1);
    QueuePush(&q, 3);
    printf("Front:%d\n", QueueFront(&q));
    QueuePop(&q);

    //获取队头元素
    printf("Front:%d\n",QueueFront(&q));
    //获取队尾元素
    printf("Back:%d\n",QueueBack(&q));

    QueuePush(&q, 1);
    QueuePush(&q, 2);

    printf("Front:%d\n", QueueFront(&q));
    printf("Back:%d\n", QueueBack(&q));
}

int main()
{
    //Test1();//面试题1方法1
    //Test();//面试题方法2
    Test3();//面试题2

    system("pause");
    return 0;
}

Three: Use two queues to implement a stack

Idea: Here we can easily think of the method of the previous question, as shown in the figure below: We put 5, 4, and 3 into the stack in turn, 3 is the top of the stack, and 5 is the bottom of the stack. Suppose there are two queues q1, q2, first put 5, 4, and 3 are entered into the queue in turn, 5 is the head of the queue, and 3 is the tail of the queue. If you want to perform the pop-out operation, since the queue can only perform the out-queue operation from the head of the queue, q1 cannot complete the requirement, but if the above question is the same, Reverse the elements in q1 as q2 in turn, you will find that the arrangement of elements is still the same, and the requirements cannot be fulfilled.
write picture description here
But if we do this, enter into q1 when entering the queue, and import the elements in q1 into q2 when leaving the queue, and there is only one left, then we can turn the top element of the stack into the head of the queue, and we can complete the requirements, as shown in the following figure ;
write picture description here
The specific code is implemented as follows:

StackAndInterview.h

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>


typedef int DataType;

typedef struct Node
{
    DataType _data;
    struct Node* _pNext;
}Node;

typedef struct Queue
{
    Node* _pHead;
    Node* _pTail;
}Queue;

typedef struct Stack
{
    Queue* q1;
    Queue* q2;
}Stack, *PStack;



//初始化栈
void StackInit(PStack s);
//创建新节点
Node* BuyNewNode(DataType data);
//入栈
void StackPush(PStack s, DataType data);
//入队列
void QueuePush(Queue* q, DataType data);
//出队列
void QueuePop(Queue* q);
//队列判空
int QueueEmpty(Queue* q);
//出栈
void StackPop(PStack s);
//获取栈顶元素
DataType StackTop(PStack s);

StackAndInterview.c

#include "StackAndInterview.h"


//创建新节点
Node* BuyNewNode(DataType data)
{
    Node* ptr;

    ptr = (Node*)malloc(sizeof(Node));
    if (NULL == ptr)
    {
        printf("节点申请失败!!!\n");
        return NULL;
    }

    ptr->_data = data;
    ptr->_pNext = NULL;
    return ptr;
}

//初始化栈
void StackInit(PStack s)
{
    assert(s);

    //分别将两个队列初始化
    s->q1->_pHead = s->q1->_pTail = BuyNewNode(0);
    s->q2->_pHead = s->q2->_pTail = BuyNewNode(0);
}


//入队列
void QueuePush(Queue* q, DataType data)
{
    assert(q);

    //从队尾插入,不用考虑队列为空时,因为刚开始头节点和尾节点指向同一个节点
    q->_pTail->_pNext = BuyNewNode(data);
    q->_pTail = q->_pTail->_pNext;
}

//入栈
void StackPush(PStack s, DataType data)
{
    assert(s);

    //直接对q1进行入队列
    QueuePush(s->q1, data);
}

//出队列
void QueuePop(Queue* q)
{
    assert(q);
    Node* pDelete = q->_pHead->_pNext;

    if (q->_pHead->_pNext == NULL)
    {
        printf("队列为空,操作失败!!!\n");
        return;
    }

    //从队头出队列
    //如果只剩一个节点,按照小面这样做,_pHead就指向NULL,而_pTail还是指向最后一个节点
    q->_pHead->_pNext = q->_pHead->_pNext->_pNext;
    if (pDelete->_pNext == NULL)
        q->_pTail = q->_pHead;
    free(pDelete);
}

//队列判空
int QueueEmpty(Queue* q)
{
    assert(q);

    if (q->_pHead->_pNext == NULL)
        return 1;
    return 0;
}

//获取队头元素
DataType QueueFront(Queue* q)
{
    assert(q);

    if (q->_pHead->_pNext == NULL)
    {
        printf("队列为空,操作失败!\n");
        return 0;
    }

    return q->_pHead->_pNext->_data;
}

//出栈
void StackPop(PStack s)
{
    assert(s);
    Node* ptr2 = NULL;

    //如果q1不为空,q2为空,将q1元素搬移到q2只剩一个,q1队头就是栈的栈顶
    if (!QueueEmpty(s->q1) && QueueEmpty(s->q2))
    {
        Node* ptr = s->q1->_pHead->_pNext;//q1的第一个有效节点

        while (ptr->_pNext)
        {
            DataType data = QueueFront(s->q1);
            QueuePop(s->q1);
            QueuePush(s->q2, data);
            ptr = s->q1->_pHead->_pNext;//必须加,否则因为释放了ptr,ptr下次就进不来了
        }

        //此时,q1中仅剩一个元素,且为栈顶元素
        QueuePop(s->q1);
    }

    ptr2 = s->q2->_pHead->_pNext;//q2的第一个有效节点
    //出完之后将q2中的元素再移回去保证,q2始终为空
    while (ptr2)
    {
        DataType data = QueueFront(s->q2);
        QueuePop(s->q2);
        QueuePush(s->q1, data);
        ptr2 = s->q2->_pHead->_pNext;//必须加,否则因为释放了ptr,ptr下次就进不来了
    }

}


//获取栈顶元素
DataType StackTop(PStack s)
{
    assert(s);
    DataType Top = 0;
    Node* ptr2 = NULL;

    if (QueueEmpty(s->q1) && QueueEmpty(s->q2))
    {
        printf("栈已空!!!\n");
        return 0;
    }

    //如果q1不为空,q2为空,将q1元素搬移到q2只剩一个,q1队头就是栈的栈顶
    if (!QueueEmpty(s->q1) && QueueEmpty(s->q2))
    {
        Node* ptr = s->q1->_pHead->_pNext;//q1的第一个有效节点

        while (ptr->_pNext)
        {
            DataType data = QueueFront(s->q1);
            QueuePop(s->q1);
            QueuePush(s->q2, data);
            ptr = s->q1->_pHead->_pNext;//必须加,否则因为释放了ptr,ptr下次就进不来了
        }

        //此时,q1中仅剩一个元素,且为栈顶元素
        Top = QueueFront(s->q1);
        QueuePop(s->q1);
        QueuePush(s->q2, Top);
    }

    ptr2 = s->q2->_pHead->_pNext;//q2的第一个有效节点
    //出完之后将q2中的元素再移回去保证,q2始终为空
    while (ptr2)
    {
        DataType data = QueueFront(s->q2);
        QueuePop(s->q2);
        QueuePush(s->q1, data);
        ptr2 = s->q2->_pHead->_pNext;//必须加,否则因为释放了ptr,ptr下次就进不来了
    }

    return Top;
}

test.c

#include "StackAndInterview.h"
#include <Windows.h>



void Test4()
{
    Stack s;
    Queue q1;//先给两个队列
    Queue q2;
    s.q1 = &q1;
    s.q2 = &q2;
    StackInit(&s);
    printf("Top:%d\n",StackTop(&s));

    StackPush(&s, 5);
    StackPush(&s, 4);
    StackPush(&s, 3);
    printf("Top:%d\n", StackTop(&s));

    StackPop(&s);
    printf("Top:%d\n", StackTop(&s));
    StackPush(&s, 7);
    StackPush(&s, 8);
    StackPush(&s, 9);
    printf("Top:%d\n", StackTop(&s));
}


int main()
{
    //Test1();//面试题1方法1
    //Test2();//面试题方法2
    //Test3();//面试题2
    Test4();//面试题3

    system("pause");
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325944624&siteId=291194637
Recommended