若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
A 1,4,3,2
B 2,3,4,1
C 3,1,4,2
D 3,4,2,1
答案:C
解析:出栈的要求是先出栈顶元素。C选项是先出的3,那么此时栈中还有1和2,如果第二个要出栈的话,只能出栈顶的2,而他出的1,所以C选项肯定是错的。
循环队列的存储空间为 Q(1:100) ,初始状态为 front=rear=100 。经过一系列正常的入队与退队操作
后, front=rear=99 ,则循环队列中的元素个数为( )
A 1
B 2
C 99
D 0或者100
答案:D
解析:由于循环队列的性质,当front==rear时,不能判断队列为空还是为满,所以D正确。
4.以下( )不是队列的基本运算?
A 从队尾插入一个新元素
B 从队列中删除第i个元素
C 判断一个队列是否为空
D 读取队头元素的值
答案:B
5.现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为?(假设
队头不存放数据)
A (rear - front + N) % N + 1
B (rear - front + N) % N
C ear - front) % (N + 1)
D (rear - front + N) % (N - 1)
答案:B
需要注意的点:本篇博客的代码中用到的数据结构可以从我上一期博客中找到。链接。
题目介绍:
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的相同类型的左括号。
OJ链接
思路分析:
使用一个栈来存储字符串中的左括号,如果遇到字符串中的右括号,则出栈匹配,一旦匹配失败则返回false,否则就一直匹配,直到将数组元素全部匹配完成,返回true。
代码实现:
bool isValid(char * s)
{
Stack st;
StackInit(&st);
while(*s)
{
if((*s=='(')||(*s=='[')||(*s=='{'))
{
StackPush(&st,*s);
s++;
}
else
{
if(StackEmpty(&st)==true)//数组只有有括号时的处理
return false;
STDataType tmp=StackTop(&st);
StackPop(&st);
if((*s==')'&&tmp!='(')
||(*s==']'&&tmp!='[')
||(*s=='}'&&tmp!='{'))
return false;
else
{
s++;
}
}
}
bool ret=StackEmpty(&st);//数组只有左括号时的处理
StackDestroy(&st);
return ret;
}
题目介绍:请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 OJ链接。
思路分析:队列先进先出,栈是后进先出。主要解决出栈时的问题,本题需要使用两个队列才能实现栈,当出栈时,将一个队列中的元素转移到另一个空队列中,原队列只保留队尾元素,此时该元素就是我们要出栈的元素。之后每次出栈都以同样的方法倒元素即可。
图解:
此时需要出栈顶元素5,我们将队列1的元素倒到队列2去,其中队列1只留一个元素。
这时队列1就只剩5这个元素了,对其操作即可。
代码如下:
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate()
{
MyStack* st=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&st->q1);
QueueInit(&st->q2);
return st;
}
void myStackPush(MyStack* obj, int x)
{
if(QueueEmpty(&obj->q2))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q1,x);
}
}
int myStackPop(MyStack* obj)
{
if(!QueueEmpty(&obj->q1))
{
while(QueueSize(&obj->q1)>1)
{
QueuePush(&obj->q2,QueueFront(&obj->q1));
QueuePop(&obj->q1);
}
int tmp=QueueFront(&obj->q1);
QueuePop(&obj->q1);
return tmp;
}
else
{
while(QueueSize(&obj->q2)>1)
{
QueuePush(&obj->q1,QueueFront(&obj->q2));
QueuePop(&obj->q2);
}
int tmp=QueueFront(&obj->q2);
QueuePop(&obj->q2);
return tmp;
}
}
int myStackTop(MyStack* obj)
{
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj)
{
return (QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2));
}
void myStackFree(MyStack* obj)
{
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
题目介绍:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)。OJ链接。
思路分析:同样是使用两个栈来实现队列,需要注意队列是先进先出,其中一个栈用来入队(pushst),一个栈专门用来出队(popst)。当出队时,如果popst为空,就将pushst中的元素倒到popst中,再在popst里出栈。
代码如下:
typedef struct
{
Stack popst;
Stack pushst;
} MyQueue;
MyQueue* myQueueCreate()
{
MyQueue* tmp=(MyQueue*)malloc(sizeof(MyQueue));
StackInit(&tmp->popst);
StackInit(&tmp->pushst);
return tmp;
}
void myQueuePush(MyQueue* obj, int x)
{
StackPush(&obj->pushst,x);
}
int myQueuePeek(MyQueue* obj)
{
if(StackEmpty(&obj->popst))
{
while(StackSize(&obj->pushst)>0)
{
StackPush(&obj->popst,StackTop(&obj->pushst));
StackPop(&obj->pushst);
}
return StackTop(&obj->popst);
}
return StackTop(&obj->popst);
}
int myQueuePop(MyQueue* obj)
{
int top=myQueuePeek(obj);
StackPop(&obj->popst);
return top;
}
bool myQueueEmpty(MyQueue* obj)
{
return StackEmpty(&obj->popst)&&StackEmpty(&obj->pushst);
}
void myQueueFree(MyQueue* obj)
{
StackDestroy(&obj->popst);
StackDestroy(&obj->pushst);
free(obj);
}
题目介绍:
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
OJ链接
思路分析:
这里我们并不是使用链表来实现循环队列,而是使用数组来实现它。原因是因为单链表实现循环列表的话,不好处理队尾元素。所以我们就使用数组来实现循环队列。该部分较难,我将一些需要注意的地方写了出来,大家自己写的时候应该加以注意,后面也会有代码可以对照。
需要注意的是:
假设队头尾front,队尾为rear,队列容量为k,那么:
typedef struct
{
int* a;
int head;
int tail;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a=(int*)malloc(sizeof(int)*(k+1));
obj->head=obj->tail=0;
obj->k=k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
assert(obj);
return obj->head==obj->tail;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
assert(obj);
int tail= (obj->tail+1)%(obj->k+1);
return tail==obj->head;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
assert(obj);
if(myCircularQueueIsFull(obj))
{
return false;
}
obj->a[obj->tail]=value;
obj->tail++;
obj->tail %= (obj->k + 1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
assert(obj);
if(myCircularQueueIsEmpty(obj))
{
return false;
}
obj->head++;
obj->head%=(obj->k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj)
{
assert(obj);
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->head];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
int tail=obj->tail==0?obj->k:obj->tail-1;
return obj->a[tail];
}
void myCircularQueueFree(MyCircularQueue* obj)
{
assert(obj);
free(obj->a);
free(obj);
}
本篇博客主要介绍了一些常见的选择题和OJ题,主要考察的还是队列和栈的性质。关于循环队列的部分呢,难度较大,没有特殊要求的话,可以跳过。