剑指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代码的一些最基本的编程元素,需要掌握清楚。