剑指Offer-数据结构 09. 用两个栈实现队列

剑指Offer-数据结构 09. 用两个栈实现队列


Q:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 append_tail和 delete_head,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,delete_head操作返回 -1 )

示例 1:


提示:

1 <= values <= 10000
最多会对 append_tail、delete_head进行 10000 次调用

 


问题分析

栈是先进后出,队列是先进先出,如果只用一个栈能实现队列吗?可以,但是效率低下,每一次取栈底的元素,需要上面的所有元素出栈,这个效率显然低下,所以才有这个题目,使用2个栈实现队列,把一个栈A的数据pop出来,然后push到另外一个栈B,那这个栈B不就是A的倒序吗?不就是队列的顺序了吗?

关于栈的实现,请参考《ADT(抽象数据类型)--堆栈》

算法逻辑:

需要2个函数,一个是append_tail,往队列尾部添加数据,一个是delete_head从头部取出数据,每次遇到这种需要封装的逻辑,有多么的想念面向对象的语言!!!

对之前的栈改造一下,append_tail直接push到stack_a中即可,当从队列中取数据delete_head的时候,先看一下stack_b中有无数据,如果有,直接返回;如果没有就看stack_a有无数据,如果stack_a如果有数据就先将stack_a的数据全部push到stack_b中,并从stack_a中删除,在从stack_b中取出数据就是队列顺序的数据了。

代码:

typedef int STACK_TYPE;

/***************************************************
 *              Stack Operation
 ***************************************************/
typedef struct STACK_NODE {
    STACK_TYPE value;
    struct STACK_NODE *next;
}StackNode;

//destory stack
void destory(StackNode **stack) {
    while(!is_empty(*stack)) {
        pop(stack);
    }
}

//push
void push(StackNode **stack, STACK_TYPE value) {
    StackNode *new_node = (StackNode *)malloc(sizeof(StackNode));
    assert(new_node != NULL);

    //insert the new node into head
    new_node->next = *stack;
    new_node->value = value;
    *stack = new_node;
}

//pop
void pop(StackNode **stack) {
    StackNode *head;
    assert(!is_empty(*stack));

    head = *stack;
    *stack = head->next;
    free(head);
}

//top
STACK_TYPE top(const StackNode *const stack) {
    assert(!is_empty(stack));
    return stack->value;
}

//is_empty
int is_empty(const StackNode * const stack) {
    return stack == NULL;
}

//never full
int is_full(const StackNode * const stack) {
    return FALSE;
}


/***************************************************
 *              Queue Operation
 ***************************************************/

void append_tail(StackNode **stack, int value) {
    push(stack, value);
}

int delete_head(StackNode **stack_a, StackNode **stack_b) {
    if(!is_empty(*stack_b)) {
        int tmp = top(*stack_b);
        pop(stack_b);
        return tmp;
    }

    if(is_empty(*stack_a)) { return -1;}

    while(!is_empty(*stack_a)) {
        int tmp = top(*stack_a);
        pop(stack_a);
        push(stack_b, tmp);
    }

    int tmp = top(*stack_b);
    pop(stack_b);
    return tmp;
}

/***************************************************
 *              Main
 ***************************************************/
int main() {

    static StackNode *stack_a;
    static StackNode *stack_b;

    append_tail(&stack_a, 1);
    append_tail(&stack_a, 2);
    printf("delete_head : %d\n", delete_head(&stack_a, &stack_b));

    append_tail(&stack_a, 3);
    append_tail(&stack_a, 4);
    append_tail(&stack_a, 5);



    printf("delete_head : %d\n", delete_head(&stack_a, &stack_b));
    printf("delete_head : %d\n", delete_head(&stack_a, &stack_b));
    printf("delete_head : %d\n", delete_head(&stack_a, &stack_b));
    printf("delete_head : %d\n", delete_head(&stack_a, &stack_b));

    destory(&stack_a);
    destory(&stack_b);
    return 0;
}

输出:

delete_head : 1
delete_head : 2
delete_head : 3
delete_head : 4
delete_head : 5

小结:

这个问题首先考察了栈和队列的概念,如果连栈和队列的概念都不清楚的自然该被淘汰;

其次考察了栈和队列的实现逻辑。

再次就是对指针和链表的考察。

这些都是构成C代码的一些最基本的编程元素,需要掌握清楚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值