下面来写一些关于栈和队列的一些笔试题:
问题1:实现一个栈,要求实现Push(入栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)
问题2:使用两个栈实现一个队列
问题3:使用两个队列实现一个栈
问题1:实现一个栈,要求实现Push(入栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)
问题分析:
要实现返回栈的最小值的时间复杂度为O(1),就要使整个栈的最小元素一定要是在栈顶,那么返回栈的在最小元素就转化为了取栈顶元素,时间复杂度就变为了O(1)。
为了实现这个目的:使整个栈的最小元素在栈顶,让入栈的时候,每次入栈两个元素,其中第一个入栈的为真正需要入栈的元素value,第二个入栈的为当前栈的最小值min,详细过程如图所示
![](https://i-blog.csdnimg.cn/blog_migrate/2cf9f6662e9eac7dc4784591f8436c6d.png)
(1)初始化操作
这个问题首先要对栈进行初始化操作
3 typedef struct MinStack
4 {
5 SeqStact stack;
6 }MinStack;
7
8 void MinStackInit(MinStack* min_stack)
9 {
10 if(min_stack == NULL)
11 {
12 //非法操作
13 return;
14 }
15 SeqStactInit(&min_stack->stack);
16 }
(2)入栈操作
如前面分析,入栈要一次插入两个元素,分别为真正要插入的元素value和当前栈的最小值min
18 void MinStackPush(MinStack* min_stack,SeqStactType value)
19 {
20 if(min_stack == NULL)
21 {
22 //非法操作
23 return;
24 }
25 SeqStactType min=value;
26 SeqStactType top;
27 int ret = SeqStactTop(&min_stack->stack,&top);
28 if(ret!=0)//ret=1
29 {
30 //有棧顶元素对情况下,让min等于棧对最小值
31 min=top<value?top:value;
32 }
33
34 SeqStactPush(&min_stack->stack,value);//先入棧的为真正要入棧对元素
35 SeqStactPush(&min_stack->stack,min);//后入棧对为当前棧对最小值
36 }
(3)出栈操作
至于
出栈过程就是一次性出栈两个元素,这样栈顶元素依旧是该栈的最小值
38 void MinStackPop(MinStack* min_stack)
39 {
40 if(min_stack == NULL)
41 {
42 //非法操作
43 return;
44 }
45 //连续出栈两个元素
46 SeqStactPop(&min_stack->stack);
47 SeqStactPop(&min_stack->stack);
48 }
49
(4)取栈的最小元素
题目中要求时间复杂度为O(1),就要把最小的元素放在栈顶,前面入栈、出栈的过程已经让当前栈的最小元素处于栈顶的位置,直接取该栈的栈顶元素就完成要求了,详细见程序
50 int MinStackTop(MinStack* min_stack,SeqStactType* value)
51 {
52 if(min_stack == NULL)
53 {
54 //非法操作
55 return 0;
56 }
57 return SeqStactTop(&min_stack->stack,value);
58 }
59
问题2:使用两个栈实现一个队列
问题分析:
栈是先入后出
队列是先进先出
要想用两个栈来实现一个队列,就是将元素的先进后出变为先进先出
首先需要创建两个栈input栈和output栈,元素先进input栈,然后再从input栈中出栈,再进入output栈,然后output栈再出栈,此时队列的顺序就为先进先出的情况了详细过程如图
![](https://i-blog.csdnimg.cn/blog_migrate/67ecea035db96a6b3d7af25fe9eedfa5.png)
(1)初始化操作
首先要进行初始化操作,就是对两个栈分别进行初始化操作
3 typedef struct QueueBy2Stack
4 {
5 SeqStact input;
6 SeqStact output;
7 }QueueBy2Stack;
8
9 void QueueInit(QueueBy2Stack* q)
10 {
11 if(q == NULL)
12 {
13 //非法操作
14 return;
15 }
16 SeqStactInit(&q->input);
17 SeqStactInit(&q->output);
18 }
(2)入栈操作
这里的入栈是指到最后,入栈到最后面的output栈,之前还要进行对input的入栈和对input的出栈同时还要对栈中元素的一些判断
需要注意的是,元素出入栈的顺序必须是元素先入栈input栈,然后再出栈input,再入栈output,再从output出栈,当在入栈input栈的时候,要保证output栈为空,否则,再进行后面出入栈的操作的时候,栈中元素的顺序就会发生混乱,一定要将output栈中的元素全部出栈到input栈中,再进行下一步的操作,详细见程序
20 void QueuePush(QueueBy2Stack* q,SeqStactType value)
21 {
22 if(q == NULL)
23 {
24 //非法操作
25 return;
26 }
27 //若output棧不为空,则需要将output棧中的元素全部出棧到input棧中,然后再进行后续操作
28 while(1)
29 {
30 SeqStactType top;
31 int ret=SeqStactTop(&q->output,&top);
32 if(ret == 0)//空棧
33 {
34 break;
35 }
36 SeqStactPop(&q->output);
37 SeqStactPush(&q->input,top);
38
39 }
40 SeqStactPush(&q->output,value);
41 return;
42 }
43
(3)出栈操作
元素出栈的顺序必须是从output栈中出栈,这就要保证在出栈的时候,input栈必须为空栈,若input栈不为空,则需要将input栈中的元素先出栈到output栈中,详细见程序
44 void QueuePop(QueueBy2Stack* q)
45 {
46 if(q == NULL)
47 {
48 //非法操作
49 return;
50 }
51 while(1)
52 {
53 SeqStactType top;
54 int ret=SeqStactTop(&q->input,&top);
55 if(ret == 0)
56 {
57 break;
58 }
59 SeqStactPop(&q->input);
60 SeqStactPush(&q->output,top);
61 }
62 SeqStactPop(&q->output);
63 }
64
(4)取栈顶元素操作
取栈顶元素只是在出栈的
output
栈中取栈顶元素,操作之前要保证
input
栈为空,详细见程序
65 int QueueTop(QueueBy2Stack* q,SeqStactType* value)
66 {
67 if(q == NULL || value == NULL)
68 {
69 //非法操作
70 return 0;
71 }
72 while(1)
73 {
74 SeqStactType top;
75 int ret=SeqStactTop(&q->input,&top);
76 if(ret == 0)
77 {
78 break;
79 }
80 SeqStactPop(&q->input);
81 SeqStactPush(&q->output,top);
82 }
83 return SeqStactTop(&q->output,value);
84 }
问题3:使用两个队列实现一个栈
问题分析:
栈是先入后出
队列是先进先出
要想用两个队列来实现一个栈,就是将元素的先进先出变为先进后出
首先要创建两个队列queue1和queue2先将元素全部入队列到queue1中,此时queue2队列为空,再将queue1队列中的前几个元素出队列到queue2中,再将queue1中的元素取出,如此往复,最终取出的元素顺序就为出栈的顺序,详细如图所示
![](https://i-blog.csdnimg.cn/blog_migrate/24377e1b86f4245a5859614d7cd0bd2b.png)
(1)初始化操作
将两个链表初始化,详细见程序
3 typedef struct StackBy2Queue
4 {
5 SeqQueue queue1;
6 SeqQueue queue2;
7 }StackBy2Queue;
8
9 void StackInit(StackBy2Queue* stack)
10 {
11 if(stack == NULL)
12 {
13 //非法操作
14 return;
15 }
16 SeqQueueInit(&stack->queue1);
17 SeqQueueInit(&stack->queue2);
18 }
(2)入队操作
入队列的操作,其实就是将元素入到非空的队列中,详细见程序
20 void StackPush(StackBy2Queue* stack,SeqQueueType value)
21 {
22 if(stack == NULL)
23 {
24 //非法操作
25 return;
26 }
27 //input队列为非空队列
28 SeqQueue* input=stack->queue1.size!=0?&stack->queue1:&stack->queue2;
29 SeqQueuePush(input,value);
30 }
31
(3)出队操作
出队列操作,就是将元素多的队列设为from将元素少的队列设为to队列,将from队列中的元素移动到to队列中,直到from队列中只有一个元素,详细见程序
32 void StackPop(StackBy2Queue* stack)
33 {
34 if(stack == NULL)
35 {
36 //非法操作
37 return;
38 }
39 if(stack->queue1.size==0&&stack->queue2.size==0)
40 {
41 //空队列
42 return;
43 }
44 //元素多对队列为from队列,即要移动的队列
45 //元素少对队列为to队列,即要移动到的队列
46 SeqQueue* from=NULL;
47 SeqQueue* to=NULL;
48 if(stack->queue1.size>0)
49 {
50 from=&stack->queue1;
51 to=&stack->queue2;
52 }
53 else
54 {
55 from=&stack->queue2;
56 to=&stack->queue1;
57 }
58 //把from中的元素移动到to队列中,直到from中只有一个元素
59 while(1)
60 {
61 if(from->size==1)
62 {
63 break;
64 }
65 SeqQueueType value;
66 SeqQueueFront(from,&value);
67 SeqQueuePop(from);
68 SeqQueuePush(to,value);
69 }
70 SeqQueuePop(from);
71
72 }
73
(4)取队首元素操作
前面同出队列操作,只是在最后取了队首元素,详细见程序
74 int StackTop(StackBy2Queue* stack,SeqQueueType* output_value)
75 {
76 if(stack == NULL || output_value == NULL)
77 {
78 //非法操作
79 return 0;
80 }
81
82 if(stack->queue1.size==0&&stack->queue2.size==0)
83 {
84 //空队列
85 return 0;
86 }
87 SeqQueue* from=NULL;
88 SeqQueue* to=NULL;
89 if(stack->queue1.size>0)
90 {
91 from=&stack->queue1;
92 to=&stack->queue2;
93 }
94 else
95 {
96 from=&stack->queue2;
97 to=&stack->queue1;
98 }
99 while(1)
100 {
101 if(from->size==1)
102 {
103 break;
104 }
105 //SeqQueueType value;
106 SeqQueueFront(from,output_value);
107 SeqQueuePop(from);
108 SeqQueuePush(to,*output_value);
109 }
110 return 1;
111 }
112