作者:[南航科院小张
南航科院小张的博客
专栏:从c语言的入门到进阶
学习知识不只是要懂,还要会用;想要找到好的工作,这里给大家介绍一件可以斩获诸多大厂offer的利器–牛客网
点击免费注册和我一起开始刷题之路吧!!!
一、有效的括号
题解:这里我们可以用栈的特性:先进后出;要是遇到左括号就入栈,要是右括号就和栈顶的元素进行比较,看是否匹配,要是匹配,就把栈顶出栈,要是不匹配,直接返回false;下面有几个要注意的点:
- 全部都是左括号;这个情况的话就是可以出循环,但是我们要在后面判断一下栈是否为空,要是空,那么就符合题意,返回true;否则返回false;
- 全部是右括号;这个问题当第一个右括号的时候就会返回法false,因为不匹配;
- 右括号比左括号多;这个情况的话也是最后面的判断栈是否空可以解决;
下面代码要注意的是c语言没有栈,我自己实现的一个栈,然后就是在返回true或者false之前的时候一定要销毁栈!!!
// 支持动态增长的栈
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int top; // 栈顶
int capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
void StackInit(Stack* ps) {
assert(ps);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
void StackPush(Stack* ps, STDataType data) {
assert(ps);
if (ps->top == ps->capacity) {
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity *2;
STDataType* temp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
if (temp == NULL) {
perror("realloc fail");
exit(-1);
}
ps->a = temp;
ps->capacity = newcapacity;
}
ps->a[ps->top] = data;
ps->top++;
}
void StackPop(Stack* ps) {
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
STDataType StackTop(Stack* ps) {
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
int StackSize(Stack* ps) {
assert(ps);
return ps->top;
}
int StackEmpty(Stack* ps) {
assert(ps);
return ps->top ==0;
}
void StackDestroy(Stack* ps) {
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
bool isValid(char * s){
Stack st;
StackInit(&st);
while(*s){
if(*s=='('||*s=='{'||*s=='['){
StackPush(&st,*s);
}
else{
if(StackEmpty(&st)){//为了防止栈为空,下面的StackPop接口还在用;
StackDestroy(&st);
return false;
}
char top=StackTop(&st);
if(*s==')'&&top!='('
||*s=='}'&&top!='{'
||*s==']'&&top!='[')
{
StackDestroy(&st);
return false;
}
else{
StackPop(&st);
}
}
++s;
}
bool flag=StackEmpty(&st);
StackDestroy(&st);
return flag;
}
二、用队列实现栈
思路很简单,但是用代码实现起来还是有点挑战的哈哈;
栈的特点:先进后出;队列特点:先进先出;
用两个队列实现栈,利用队列的特点,把先进的数据导到另外一个队列里面,然后剩下一个数据,然后出这个数据(pop数据),这样就实现了栈的出数据特点,栈顶出数据;我们要控制那里的队列为空就往空队列导数据,非空队列留下一个来出数据,就这样一直在两个队列里面操作,然后入数据就往非空队列里入数据;我这里是直接写的队列哈,所以比较多代码;
// 链式结构:表示队列
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* next;
QDataType data;
}QNode;
// 队列的结构
typedef struct Queue
{
size_t sz;
QNode* head;
QNode* tail;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
void QueueInit(Queue* q) {
assert(q);
q->head = q->tail = NULL;
q->sz = 0;
}
void QueuePush(Queue* q, QDataType data) {
assert(q);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL) {
perror("malloc fail");
exit(-1);
}
else {
newnode->data = data;
newnode->next = NULL;
}
if (q->head == NULL) {
q->head = q->tail = newnode;
q->sz++;
}
else {
q->tail->next = newnode;
q->tail = newnode;
q->sz++;
}
}
void QueuePop(Queue* q) {
assert(q);
assert(!QueueEmpty(q));
if (q->head->next == NULL) {
free(q->head);
q->head = q->tail = NULL;
q->sz--;
}
else {
QNode* cur = q->head->next;
free(q->head);
q->head = cur;
q->sz--;
}
}
QDataType QueueFront(Queue* q) {
assert(q);
assert(!QueueEmpty(q));
return q->head->data;
}
QDataType QueueBack(Queue* q) {
assert(q);
assert(!QueueEmpty(q));
return q->tail->data;
}
int QueueSize(Queue* q) {
assert(q);
return q->sz;
}
int QueueEmpty(Queue* q) {
assert(q);
return q->head == NULL && q->tail == NULL;
}
void QueueDestroy(Queue* q) {
assert(q);
QNode* cur = q->head;
while (cur) {
QNode* next = cur->next;
free(cur);
cur = next;
}
q->head = q->tail = NULL;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
if(obj==NULL){
perror("malloc fail");
exit(-1);
}
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1)){
QueuePush(&obj->q1,x);
}
else{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
Queue* EmptyQ=&obj->q1;
Queue* noEmptyQ=&obj->q2;
if(!QueueEmpty(&obj->q1)){
EmptyQ=&obj->q2;
noEmptyQ=&obj->q1;
}
while(QueueSize(noEmptyQ)>1){
int top=QueueFront(noEmptyQ);
QueuePop(noEmptyQ);
QueuePush(EmptyQ,top);
}
int top=QueueFront(noEmptyQ);
QueuePop(noEmptyQ);
return top;
}
int myStackTop(MyStack* obj) {
Queue* EmptyQ=&obj->q1;
Queue* noEmptyQ=&obj->q2;
if(!QueueEmpty(&obj->q1)){
EmptyQ=&obj->q2;
noEmptyQ=&obj->q1;
}
while(QueueSize(noEmptyQ)>1){
int top=QueueFront(noEmptyQ);
QueuePop(noEmptyQ);
QueuePush(EmptyQ,top);
}
int top=QueueFront(noEmptyQ);
QueuePop(noEmptyQ);
QueuePush(EmptyQ,top);
return top;
}
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2));
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
/**
* Your MyStack struct will be instantiated and called as such:
* MyStack* obj = myStackCreate();
* myStackPush(obj, x);
* int param_2 = myStackPop(obj);
* int param_3 = myStackTop(obj);
* bool param_4 = myStackEmpty(obj);
* myStackFree(obj);
*/
三. 用栈实现队列
思路很简单,但是用代码实现起来还是有点挑战的哈哈;
栈的特点:先进后出;队列特点:先进先出;
用栈来模拟队列的特点,有了上面的题解,想必我们很容易想到方法了,这题比上一题简单哦,我们搞两个栈,一个栈专门用来入数据,一个栈专门用来出数据,因为入数据完后将全部数据到入专门的出数据的栈里面的时候,出数据的栈的数据是符合队列的出数据规则的了;所以可以对两个栈分开工作;
要注意的是:出数据的栈要判断是否为空,要是空的话就导数据,然后再出;
//Stack
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top; // 栈顶
int capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackInit(Stack* ps) {
assert(ps);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
void StackPush(Stack* ps, STDataType data) {
assert(ps);
if (ps->top == ps->capacity) {
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* temp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
if (temp == NULL) {
perror("realloc fail");
exit(-1);
}
ps->a = temp;
ps->capacity = newcapacity;
}
ps->a[ps->top] = data;
ps->top++;
}
void StackPop(Stack* ps) {
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
STDataType StackTop(Stack* ps) {
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
int StackSize(Stack* ps) {
assert(ps);
return ps->top;
}
int StackEmpty(Stack* ps) {
assert(ps);
return ps->top == 0 ? 1 : 0;
}
void StackDestroy(Stack* ps) {
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
typedef struct {
Stack PopST;
Stack PushST;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
if(obj==NULL){
perror("malloc fail");
exit(-1);
}
StackInit(&obj->PopST);
StackInit(&obj->PushST);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->PushST,x);
}
//判断PopST队列是否为空,要是空,就导数据;
void PushSTTOPopST(MyQueue* obj){
if(StackEmpty(&obj->PopST)){
while(!StackEmpty(&obj->PushST)){
int top=StackTop(&obj->PushST);
StackPop(&obj->PushST);
StackPush(&obj->PopST,top);
}
}
}
int myQueuePop(MyQueue* obj) {
PushSTTOPopST(obj);
int top=StackTop(&obj->PopST);
StackPop(&obj->PopST);
return top;
}
int myQueuePeek(MyQueue* obj) {
PushSTTOPopST(obj);
int top=StackTop(&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);
}
/**
* Your MyQueue struct will be instantiated and called as such:
* MyQueue* obj = myQueueCreate();
* myQueuePush(obj, x);
* int param_2 = myQueuePop(obj);
* int param_3 = myQueuePeek(obj);
* bool param_4 = myQueueEmpty(obj);
* myQueueFree(obj);
*/
四. 设计循环队列
这道题其实难,可以用链表也可以用顺序表,不过我觉得用顺序表更简单容易实现一点;为了可以判断什么时候是满的什么时候是空的,我们有两个方法,一个是用size来计数,第二个是直接加一个节点;加了一个节点后当数据为空,就是head等于tail的时候,当(tail+1)%N等于head的时候为满数据,这个时候不能再插入数据了;我们一定要注意这是一个循环的,到边界的时候一定要有回去,这个时候我的实现是%N,返回尾元素则很巧,(tail-1+n)%n;我们要画图多观察才容易理解;要是不容易理解代码,可以画图然后看着代码来还原思路;
typedef struct {
int* a;
int head;
int tail;
int N;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
if(obj==NULL){
perror("obj malloc fail");
exit(-1);
}
obj->a=(int*)malloc(sizeof(int)*(k+1));//加一个空间,便于判断空和满;
if(obj->a==NULL){
perror("a malloc fail");
exit(-1);
}
obj->N=k+1;//作用很大,便于下标的循环恢复;
obj->head=obj->tail=0;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->tail==obj->head;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->tail+1)%(obj->N)==obj->head;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->a[obj->tail]=value;
obj->tail++;
obj->tail%=obj->N;//防止在最大下标+1的情况,要循环进行恢复最小下标;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->head++;
obj->head%=obj->N;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[obj->head];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[(obj->tail-1+obj->N)%(obj->N)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
obj->a=NULL;
free(obj);
}
/**
* Your MyCircularQueue struct will be instantiated and called as such:
* MyCircularQueue* obj = myCircularQueueCreate(k);
* bool param_1 = myCircularQueueEnQueue(obj, value);
* bool param_2 = myCircularQueueDeQueue(obj);
* int param_3 = myCircularQueueFront(obj);
* int param_4 = myCircularQueueRear(obj);
* bool param_5 = myCircularQueueIsEmpty(obj);
* bool param_6 = myCircularQueueIsFull(obj);
* myCircularQueueFree(obj);
*/