第十期——用栈实现队列

因为本期使用C语言来实现代码,由于C语言不支持栈,所以我们要先实现栈的模拟。

栈的结构特点和实现

栈的结构特点:只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除的操作的一端称为栈顶,另一端称为栈底。栈中的元素遵循先进后出的原则。

栈的实现:栈的实现可以用数组和链表来实现,如果用数组来实现栈,入栈就在数组尾上插入数据,出栈就在数组尾上删除数据,很容易实现效率高;如果用链表实现栈,将链表头作为栈顶,入栈就是头插,出栈就是尾删,效率没有用数组实现高,所以我选择用数组实现栈的结构。

typedef int STDataType;

typedef struct Stack {

    int* a;        

    int top;

    int capacity;

} ST;

void STInit(ST* ps);//初始化栈

void STDestroy(ST* ps);//销毁栈

void STPush(ST* ps, STDataType x);//入栈

void STPop(ST* ps);//出栈

int STSize(ST* ps);//获取栈的有效元素个数

bool STEmpty(ST* ps);//检查栈是否为空

STDataType STTop(ST* ps);//获取栈顶元素

void STInit(ST* ps) {
    assert(ps);
    ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
    if (ps->a == NULL) {
        perror("malloc");
        return;
    }
    ps->capacity = 4;
    ps->top = 0; // 栈顶元素的下一个位置
}
void STDestroy(ST* ps) {
    assert(ps);
    free(ps->a);
    ps->a = NULL;
    ps->top = 0;
    ps->capacity = 0;
}

void STPush(ST* ps, STDataType x) {
    assert(ps);
    // 检查是否需要扩容
    if (ps->top == ps->capacity) {
        STDataType* tmp =
            (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
        if (tmp == NULL) {
            perror("realloc");
        }
        ps->a = tmp;
        ps->capacity *= 2;
    }
    ps->a[ps->top] = x;
    ps->top++;
}
bool STEmpty(ST* ps) {
    assert(ps);
    return ps->top == 0;
}
void STPop(ST* ps) {
    assert(ps);
    assert(!STEmpty(ps));
    ps->top--;
}
int STSize(ST* ps) {
    assert(ps);
    return ps->top;
}
STDataType STTop(ST* ps) {
    assert(ps);
    return ps->a[ps->top - 1];
}

题目:用栈实现队列

查看原题目请点击这里~

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

思路

用栈实现入队操作很容易,由于栈只允许在固定的一端进行插入和删除元素操作,而队列只允许在一端进行插入数据操作,如果我们想要出队删除元素1,相当于第一个栈的栈底元素1,就要把1上面的其他元素都移动到第二个栈中,

如果我们想要继续插入元素,应该该如何插入?

如果我们直接向第二个栈中插入元素,就会导致元素的顺序不对,那如果我们向第一个栈中插入元素,我们是否需要将第二个栈中的元素移动回来?

经过观察我们发现,如果此时继续出队删除元素,出队的顺序第二个栈出栈的顺序相同,即我们不需要将第二个栈中的数据倒回到第一个栈中,只需要将新入队的元素放在第一个栈中即可,如果需要出栈,就从第二个栈中直接获取栈顶元素。

总的来说就是,第一个栈负责入队,第二个栈负责出队,如果出队的时候第二个栈为空,就将第一个栈中的元素倒到第二个栈中。

如果想要判断队列是否为空,就要判断两个栈是否都为空。

代码(C语言版)

typedef int STDataType;
typedef struct Stack {
    int* a;
    int top;
    int capacity;
} ST;

void STInit(ST* ps) {
    assert(ps);
    ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
    if (ps->a == NULL) {
        perror("malloc");
        return;
    }
    ps->capacity = 4;
    ps->top = 0; // 栈顶元素的下一个位置
}
void STDestroy(ST* ps) {
    assert(ps);
    free(ps->a);
    ps->a = NULL;
    ps->top = 0;
    ps->capacity = 0;
}

void STPush(ST* ps, STDataType x) {
    assert(ps);
    // 检查是否需要扩容
    if (ps->top == ps->capacity) {
        STDataType* tmp =
            (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
        if (tmp == NULL) {
            perror("realloc");
        }
        ps->a = tmp;
        ps->capacity *= 2;
    }
    ps->a[ps->top] = x;
    ps->top++;
}
bool STEmpty(ST* ps) {
    assert(ps);
    return ps->top == 0;
}
void STPop(ST* ps) {
    assert(ps);
    assert(!STEmpty(ps));
    ps->top--;
}
int STSize(ST* ps) {
    assert(ps);
    return ps->top;
}
STDataType STTop(ST* ps) {
    assert(ps);
    return ps->a[ps->top - 1];
}

typedef struct {
    ST stpush;
    ST stpop;
} MyQueue;

MyQueue* myQueueCreate() {
    MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));
    if (queue == NULL) {
        perror("malloc");
        return NULL;
    }
    STInit(&queue->stpush);
    STInit(&queue->stpop);
    return queue;
}

void myQueuePush(MyQueue* obj, int x) { 
    STPush(&obj->stpush, x); 
}
int myQueuePeek(MyQueue* obj) {
    if (STEmpty(&obj->stpop)) {
        // 倒数据
        while (!STEmpty(&obj->stpush)) {
            STPush(&obj->stpop, STTop(&obj->stpush));
            STPop(&obj->stpush);
        }
    }
    return STTop(&obj->stpop);
}
int myQueuePop(MyQueue* obj) {
    int ret = myQueuePeek(obj);
    STPop(&obj->stpop);
    return ret;
}

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->stpush) && STEmpty(&obj->stpop);
}

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->stpush);
    STDestroy(&obj->stpop);
    free(obj);
}

持续更新,下期见

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值