/*代码里所用的函数接口都在上一篇博文。里面只进行说明。*/
1、括号匹配;给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串,判断字符串是否有效。
有效字符串需满足:
-
左括号必须用相同类型的右括号闭合。
-
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
函数接口:bool isValid(char* s)
//C语言
这道题用栈来操作。复合先进后出。我们把左括号进行压栈,右括号进行对比,匹配上就出栈。
一半布尔值我都是用的 int ,0为假,非0为真。
int bracket(char* bra)
{
char* p = bra;
Stack stack; //定义一个栈
st_init(&stack); //初始化栈,下面进行压栈
while (*p)
{
switch (*p)
{
case '(':
case '{':
case '[':
st_add(&stack, *p); //如果是左括号我们都压进栈
break;
case ')':
case '}':
case ']':
if (st_empt(&stack)) //如果栈是空的,说明没有左括号,那肯定不匹配
{
return 0;
}
char left = st_top(&stack);
if (!((left=='('&&*p == ')')||(left == '{'&&*p == '}')||(left == '['&&*p == ']'))) //这里有个!,是不满足的括号匹配的,我们就返回 0;
{
return 0;
}
st_del(&stack); //匹配了,删除栈顶。
default:
break; //遍历完后。退出循环
}
++p;
}
return 1; //返回真
}
2、用队列实现栈;使用队列实现栈的下列操作:
-
push(x) -- 元素 x 入栈
-
pop() -- 移除栈顶元素
-
top() -- 获取栈顶元素
-
empty() -- 返回栈是否为空
栈是先进后出,队列是后进先出。所以实现需要一些手段。下面的图是代码里比较难理解的地方
//C语言
typedef struct MyStack
{
int capacity;
Queue queue;
}MyStack; //这个结构体是队列,虽然名字是栈
//初始化/创建
// MyStack* stack = (MyStack*)malloc(sizeof(MyStack));//因为没有给内存,则需要在堆上申请内存
MyStack* myst_init(MyStack* stack, int capacity)
{
assert(stack);//保证传入的stack地址有效
stack->capacity = capacity;
qu_init(&(stack->queue));
return stack;
}
//添加
//栈只能在栈顶进行操作。这儿队尾当作栈顶
void myst_push(MyStack* st, int data)
{
assert((st->queue.size)<(st->capacity));
qu_push(&(st->queue),data);
}
//删除
//删除也要在栈顶,但是队列的删除在队尾。所以需要把队首变成队尾。
void myst_pop(MyStack* st)
{
assert(st->queue.size>0);
int size = st->queue.size;
for (int i = 0; i < size - 1; i++)
{
int temp = qu_head(&(st->queue));
qu_pop(&(st->queue));
qu_push(&(st->queue), temp);
}
qu_pop(&(st->queue));//删除
--st->queue.size;
}
//取栈顶元素
void myst_top(MyStack* st)
{
assert(st->queue.size > 0);
int size = st->queue.size;
for (int i = 0; i < size - 1; i++)
{
int temp = qu_head(&(st->queue));
qu_pop(&(st->queue));
qu_push(&(st->queue), temp);
}
int temp2 = qu_head(&(st->queue));
qu_pop(&(st->queue));
qu_push(&(st->queue), temp2);
return temp2;
}
//判断为空
int myst_empt(MyStack* st)
{
return qu_empty(&(st->queue));
}
取栈顶元素和删除一样的,只是把删除换成了取队首元素的函数而已。
3、用栈实现队列
使用栈实现队列的下列操作:
-
push(x) -- 将一个元素放入队列的尾部。
-
pop() -- 从队列首部移除元素。
-
peek() -- 返回队列首部的元素。
-
empty() -- 返回队列是否为空。
有了上面的基础,这个题也就有了一定的思想。中间的删除就看这个图。
//C语言
typedef struct MyQueue
{
int maxSize;
Stack stackA; //因为栈只能在栈顶操作,所以我们需要两个栈来实现一个队列
Stack stackB;
}MyQueue; //定义一个队列,内部是栈
//初始化
MyQueue* mtqu_init(MyQueue* queue)
{
assert(queue);
queue->maxSize = 0;
st_init(&(queue->stackA));
st_init(&(queue->stackB));
return queue;
}
//添加
void myqu_push(MyQueue* qu, int data)
{
st_push(&(qu->stackA), data);//我们在第一个栈进行压栈
}
//删除
void myqu_pop(MyQueue* qu) //队列需要先进先出
{
if (st_empt(&(qu->stackB)))//判断第二个栈是否尾空
{
int size = st_size(&(qu->stackA));
for (int i = 0; i < size; ++i)
{
int temp = st_top(&(qu->stackA));
st_del(&(qu->stackA));
st_push(&(qu->stackB), temp);
} //我们把第一个栈的元素取出压到第二个栈里面,那么在第一个栈的第一个元素到第
//二个栈的栈顶了。我们就可以对栈顶进行删除,这个时候实现对队首的删除。
}
st_del(&(qu->stackB));
}
//返回队首
int myqu_front(MyQueue* qu)
{
if (st_empt(&(qu->stackB)))
{
int size = st_size(&(qu->stackA));
for (int i = 0; i < size; ++i)
{
int temp = st_top(&(qu->stackA));
st_del(&(qu->stackA));
st_push(&(qu->stackB), temp);
}
}
return st_top(&(qu->stackB)); //和删除一样,把删除操作换成第二个栈的栈顶元素
}
//判断为空
int myqu_empty(MyQueue* qu)
{
return st_empt(&(qu->stackA)) && st_empt(&(qu->stackB));//两个栈为空即空
}
4、实现最小栈
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
-
push(x) -- 将元素 x 推入栈中。
-
pop() -- 删除栈顶的元素。
-
top() -- 获取栈顶元素。
-
getMin() -- 检索栈中的最小元素。
最小栈也需要用两个栈来实现。
//C语言
typedef struct MinStack
{
Stack stack1;
Stack stack2;
}MinStack;
//初始化
MinStack* mst_init()
{
MinStack* stack = (MinStack*)mallloc(sizeof(MinStack));
assert(stack);
st_init(&(stack->stack1));
st_init(&(stack->stack2));
return stack;
}
//进栈
void mst_push(MinStack* mst, int data)
{
st_push(&(mst->stack1),data);
if (st_empt(&(mst->stack2)))//如果第二个栈为空,直接把这个值压进栈
{
st_push(&(mst->stack2), data);
}
else //不是的话就取出第二个栈的栈顶元素,比较两个元素的值
{
int min = st_top(&(mst->stack2));
if (data < min) //如果所压的元素小于第二个栈的栈顶元素就对第二个栈进行压栈
//否则就不做任何事情
{
min = data;
st_push(&(mst->stack2), min);
}
}
}
//出栈
void mst_pop(MinStack* mst)
{
if (st_top(&(mst->stack1)) == st_top(&(mst->stack2)))//如果第一个栈和第二个的栈顶元
//素相同就把第二个栈顶元素也需要删除,刷新最小值
{
st_del(&(mst->stack2));
}
st_del(&(mst->stack1));
}
//获取最小
int mst_min(MinStack* mst)
{
return st_top(&(mst->stack2));//第二个栈的栈顶元素
}
//栈顶
int mst_top(MinStack* mst)
{
return st_top(&(mst->stack1));
}
//判断为空
int mst_empty(MinStack* mst)
{
return st_empt(&(mst->stack1));
}
5、设计循环队列
-
MyCircularQueue(k): 构造器,设置队列长度为 k 。
-
Front: 从队首获取元素。如果队列为空,返回 -1 。
-
Rear: 获取队尾元素。如果队列为空,返回 -1 。
-
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
-
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
-
isEmpty(): 检查循环队列是否为空。
-
isFull(): 检查循环队列是否已满。
这道题的接口是真滴多。循环队列就是一个员=圆环,然后涉及一个公式。公式解释一下,代码就好理解了,思路也有了。
//C语言
//循环队列
//创建队列
typedef int CQData;
typedef struct CirculateQueue
{
CQData* arr;
int size;
int capacity;
int front;
int rear;
}CQ;
CQ* cq_init(int capacity)
{
CQ* circulateQueue = (CQ*)malloc(sizeof(CQ));
circulateQueue->arr = NULL;
circulateQueue->capacity = capacity;
circulateQueue->front = circulateQueue->rear = circulateQueue->size = 0;
return circulateQueue;
}
int cq_push(CQ* cq, int data)
{
if (cq->capacity == cq->size)
{
return -1;
}
cq->arr[cq->rear] = data;
cq->rear = (cq->rear + 1) % cq->capacity;
return data;
}
int cq_pop(CQ* cq)
{
if (cq->size == 0)
{
return -1;
}
--cq->size;
cq->front = (cq->front + 1) % cq->capacity;
return 1;
}
CQData cq_front(CQ* cq)
{
if (cq->size == 0)
{
return -1;
}
return cq->arr[cq->front];
}
CQData cq_rear(CQ* cq)
{
if (cq->size == 0)
{
return -1;
}
return cq->arr[(cq->rear + cq->capacity -1) % cq->capacity];
}
int cq_empty(CQ* cq)
{
return cq->size == 0;
}
int cq_full(CQ* cq)
{
return cq->size == cq->capacity;
}
void cq_free(CQ* cq)
{
free(cq->arr);
free(cq);
}