一:实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)
方法一:
思路:这里我们栈底层采用的是静态顺序表实现,出栈、入栈我们都很容易实现时间复杂度为O(1),但是,要返回最小值,按照我们常规的思路,遍历栈,可以得出最小值,但是时间复杂度为O(n),不符合题目要求,我们可以在栈中每次放入两个数据,一个是本来就要放的data,另一个为Mindata,将这两个数据封装为一个结构体,如果栈为空,我们可以将Mindata的值与data相等,若不为空,可以将新元素中的data与栈顶元素中的Mindata比较,若新元素中的data小于等于栈顶的,可以将新元素中的Mindata的值与data相等,若大于栈顶元素中的Mindata,新元素中的data不变,Mindata更新为栈顶元素中的Mindata
假设现在我们向栈中依次放入:5, 2, 3, 1.第一次放5,因为此时栈为空,所以data和Mindata都是5,然后放2,因为2小于等于栈顶元素中的Mindata5,所以新元素中的data与Mindata都为2,接下来放3,因为3大于栈顶元素中的Mindata2,所有新元素中的data为3,Mindata为2,最后放1,过程如下图:
代码实现如下:
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;
}
if (size
== 0)
{
s
->_arr
->data = s
->_arr
->Mindata
= data;
s
->_size
++;
return;
}
if ((s
->_arr
+ size
- 1)
->Mindata
>= data)
{
(s
->_arr
+ size)
->Mindata
= (s
->_arr
+ size)
->data = data;
s
->_size
++;
return;
}
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
测试环境: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;
}
方法二:
思路:我们可以使用两个栈存储数据,一个栈放data,一个栈放Mindata,放Mindata栈的栈顶元素一定是此时栈中的最小元素,然后将这两个栈封装为一个栈,就可以实现题目中的要求。
假设我们还是在栈中依次放入:5,2,3,1.如果此时data栈为空,那么说明Mindata栈也为空,放5时,两个栈都为空,直接将5都入栈,接下来放2,data栈直接放,如果将要放入的data,2小于等于Mindata栈的栈顶元素,那么也将2入到Mindata栈,否则,不予理会。操作如下图所示:
如果要取最小值,就取Mindata栈的栈顶元素,这样就能实现时间复杂度为O(1),代码实现如下:
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;
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;
}
二:使用两个栈实现一个队列
思路:首先,我们必须要搞清楚栈和队列分别有什么特性,栈,先进后出,只能从栈顶进行入栈和出栈操作;而对于队列,先进先出,从队尾进行入队列操作,从队头进行出队列操作。假设我们有两个栈s1和s2,s1用来入队列操作,s2用来进行出队列操作,如下图所示我们依次要向队列中插入元素5, 4,9,因为我们将元素依次入到栈s1,如果是队列我们出队列首先是元素5,但由于元素在栈s1中,不能直接对栈底元素进行出栈操作,所以我们可以将s1中的元素,依次入栈到s2 入栈后如下图: 此时,队头元素就是栈s2的栈顶元素,要出队列,我们可以直接对s2进行出栈操作。假设我们现在又要向队列中依次插入元素2,4,如下图: 从上面三幅图我们可得出:假设s1不为空,s2为空,那么队头为s1的栈底,队尾为s1的栈顶;假设s1为空,s2不为空,那么队头为s2的栈顶,队尾为s2的栈底;假设s1、s2都不为空,那么队头为s2的栈顶,队尾为s1的栈顶。具体代码实现如下:
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);
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()
{
Test3();
system("pause");
return 0;
}
三:使用两个队列实现一个栈
思路:这里我们很容易就联想到上道题的方法,如下图:我们将5,4,3依次入栈,3为栈顶,5为栈底,假设有两个队列q1、q2,先将5,4,3依次入队列,5为队头,3为队尾,如果要进行出栈操作,由于队列只能从队头进行出队列操作,所以q1不能完成要求,但如果向上题一样,将q1中的元素依次倒如q2,会发现,元素排列还是一样,不能完成要求。 但是如果我们这样做呢,入队列时向q1入,出队列时将q1中的元素导入到q2中只剩一个,那么就可以将栈顶元素变成队头元素,就可以完成要求,如下图; 具体代码实现如下:
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);
QueuePush(s
->q1,
data);
}
void QueuePop(
Queue* q)
{
assert(q);
Node
* pDelete
= q
->_pHead
->_pNext;
if (q
->_pHead
->_pNext
== NULL)
{
printf(
"队列为空,操作失败!!!\n");
return;
}
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;
if (
!QueueEmpty(s
->q1)
&& QueueEmpty(s
->q2))
{
Node
* ptr
= s
->q1
->_pHead
->_pNext;
while (ptr
->_pNext)
{
DataType
data = QueueFront(s
->q1);
QueuePop(s
->q1);
QueuePush(s
->q2,
data);
ptr
= s
->q1
->_pHead
->_pNext;
}
QueuePop(s
->q1);
}
ptr2
= s
->q2
->_pHead
->_pNext;
while (ptr2)
{
DataType
data = QueueFront(s
->q2);
QueuePop(s
->q2);
QueuePush(s
->q1,
data);
ptr2
= s
->q2
->_pHead
->_pNext;
}
}
DataType StackTop(PStack s)
{
assert(s);
DataType Top
= 0;
Node
* ptr2
= NULL;
if (QueueEmpty(s
->q1)
&& QueueEmpty(s
->q2))
{
printf(
"栈已空!!!\n");
return 0;
}
if (
!QueueEmpty(s
->q1)
&& QueueEmpty(s
->q2))
{
Node
* ptr
= s
->q1
->_pHead
->_pNext;
while (ptr
->_pNext)
{
DataType
data = QueueFront(s
->q1);
QueuePop(s
->q1);
QueuePush(s
->q2,
data);
ptr
= s
->q1
->_pHead
->_pNext;
}
Top
= QueueFront(s
->q1);
QueuePop(s
->q1);
QueuePush(s
->q2, Top);
}
ptr2
= s
->q2
->_pHead
->_pNext;
while (ptr2)
{
DataType
data = QueueFront(s
->q2);
QueuePop(s
->q2);
QueuePush(s
->q1,
data);
ptr2
= s
->q2
->_pHead
->_pNext;
}
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()
{
Test4();
system(
"pause");
return 0;
}