目录
- 有效的括号(括号匹配)
- 用栈实现队列
- 用队列实现栈
- 设计循环队列
有效的括号(括号匹配)
链接: link
题目描述:
题目思路:
1、如果是左括号“( { [ ”就入栈
2、如果是右括号“) } ] ”,就取出栈顶元素与该右括号进行匹配
如果不匹配,就直接return false
如果匹配,s++,指针继续向下走,寻找下一个括号,进行上述操作
注意:
1、如果只有左括号,则栈不为空,则要return false
2、如果只有右括号,栈为空,不能取栈顶元素进行匹配
3、内存泄漏问题,每次返回一个bool值之前都要销毁栈,以免发生内存泄漏
代码实现:
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;//最开始不malloc空间
//pst->top = -1;//指向栈顶元素
pst->top = 0;//指向栈顶元素的下一个位置,表示已经有元素
pst->capacity = 0;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = 0;
pst->capacity = 0;
}
void STPush(ST* pst, STDataType x)
{
assert(pst);
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
pst->a = tmp;
pst->capacity = newcapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->top--;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];//栈顶元素
}
bool STEmpty(ST* pst)
{
return pst->top == 0;
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
bool isValid(char * s)
{
ST st;
STInit(&st);
while(*s)
{
//1、左括号入栈
if(*s=='('
|| *s=='{'
|| *s=='[')
{
STPush(&st,*s);
}
//2、右括号出栈匹配
else
{
//不匹配情况
//如果栈空,只有右括号,则不匹配,直接返回false
if(STEmpty(&st))
{
return false;
}
char top = STTop(&st);
STPop(&st);
if((*s==']'&&top!='[')
|| (*s=='}'&&top!='{')
||(*s==')'&&top!='('))
{
return false;
}
//匹配
}
s++;//向后遍历字符串寻找括号
}
bool ret = STEmpty(&st);//如果栈空返回true,否则返回false
STDestroy(&st);
return ret;
}
用栈实现队列
链接: link
题目描述:
题目思路:
两个栈实现队列,首先明确:
栈后进先出
队列先进先出
方法:
此处方法就是先倒数据,将栈1的元素4 3 2全部导入栈2中,最后删除1,如下图
在这个过程中,将栈1的全部元素导入栈2后,我们可以发现栈2出栈的顺序就是队列出队的顺序,于是可以将两个栈做如下更改:
分析:
1、队列的结构
typedef struct
{
ST pushst;
ST popst;
} MyQueue;
MyQueue* myQueueCreate()
{
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
if(obj==NULL)
{
perror("malloc fail");
return NULL;
}
STInit(&obj->pushst);
STInit(&obj->popst);
return obj;
}
2、入队操作
此处入队操作就是入栈操作,将元素入到pushst栈当中
void myQueuePush(MyQueue* obj, int x)
{
STPush(&obj->pushst,x);
}
3、返回队列开头元素
首先判断popst中是否为空,如果popst为空,判断pushst是否为空,如果pushst不为空,将pushst中的元素入栈到popst中,最后返回popst的栈顶元素
int myQueuePeek(MyQueue* obj) //只取栈顶元素
{
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst,STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
return STTop(&obj->popst);//popst中的栈顶元素,即pushst中的栈底元素
}
4、移除队列开头的元素,并返回队头元素
复用myQueuePeek函数,保存该函数的返回值,再出popst的栈顶元素
int myQueuePop(MyQueue* obj) //删数据
{
int front = myQueuePeek(obj);
STPop(&obj->popst);
return front;
}
5、判空
popst和pushst同时为空
bool myQueueEmpty(MyQueue* obj)
{
return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}
6、销毁
void myQueueFree(MyQueue* obj)
{
STDestroy(&obj->pushst);
STDestroy(&obj->popst);
free(obj);
}
整体代码:
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;//最开始不malloc空间
//pst->top = -1;//指向栈顶元素
pst->top = 0;//指向栈顶元素的下一个位置,表示已经有元素
pst->capacity = 0;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = 0;
pst->capacity = 0;
}
void STPush(ST* pst, STDataType x)
{
assert(pst);
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
pst->a = tmp;
pst->capacity = newcapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->top--;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];//栈顶元素
}
bool STEmpty(ST* pst)
{
return pst->top == 0;
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
typedef struct
{
ST pushst;
ST popst;
} MyQueue;
MyQueue* myQueueCreate()
{
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
if(obj==NULL)
{
perror("malloc fail");
return NULL;
}
STInit(&obj->pushst);
STInit(&obj->popst);
return obj;
}
void myQueuePush(MyQueue* obj, int x)
{
STPush(&obj->pushst,x);
}
int myQueuePop(MyQueue* obj) //删数据
{
int front = myQueuePeek(obj);
STPop(&obj->popst);
return front;
}
int myQueuePeek(MyQueue* obj) //只取栈顶元素
{
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst,STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
return STTop(&obj->popst);//popst中的栈顶元素,即pushst中的栈底元素
}
bool myQueueEmpty(MyQueue* obj)
{
return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}
void myQueueFree(MyQueue* obj)
{
STDestroy(&obj->pushst);
STDestroy(&obj->popst);
free(obj);
}
用队列实现栈
链接: link
题目描述:
题目思路:
题目中给我们两个队列实现一个栈,首先明确:
1、队列的性质:先进先出
2、栈的性质:后进先出
如何才能使用两个队列实现栈的后进先出?
本题给的两个队列就是用来导数据,进而实现栈的后进先出的性质
举例:如上图,如果说我们要出数据5,那么就需要将队列1当中的1 2 3 4 先入到队列2中,再出数据5,这样就实现了后进先出的性质。
注意:
如何入数据?
1、如果两个队列中的一个队列为空一个队列不为空,那么数据入到非空队列中
2、如果两个队列都为空,数据入到其中一个队列
分析:
1、栈的结构和栈的创建
方法1:给定MyStack栈中的两个队列都是结构体类型,直接malloc动态开辟一个栈的空间,里面存放队列1 q1和队列2 q2
初始化队列使用结构体指针。
方法2:给定MyStack栈中的两个队列都是结构体指针类型,动态开辟栈的空间,再动态开辟队列的空间,这样在初始化时就不需要进行取地址操作,因为q1和q2就是结构体指针类型。
2、入数据操作
1、如果q1不为空,那么就入队列1中
2、如果q2不为空,那么就入队列2中
3、如果两个都不为空,则随意入队列
void myStackPush(MyStack* obj, int x)
{
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
3、出栈操作——倒数据
1、将非空队列的队头的数据导入空队列当中——入队
2、弹出非空队列的队头数据
3、取栈顶元素
int myStackPop(MyStack* obj)
{
Queue* qEmpty=&obj->q1;
Queue* qNoneEmpty = &obj->q2;
if(!QueueEmpty(&obj->q1))
{
Queue* qEmpty=&obj->q2;
Queue* qNoneEmpty = &obj->q1;
}
while(QueueSize(qNoneEmpty)>1)
{
QueuePush(qEmpty,QueueFront(qNoneEmpty));
QueuePop(qNoneEmpty);
}
int top = QueueFront(qNoneEmpty);
QueuePop(qNoneEmpty);
return top;
}
4、取栈顶元素——队尾元素
1、第一个队列不为空,就取队尾元素
2、反之取第二个队列的队尾元素
int myStackTop(MyStack* obj)
{
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
5、判空
bool myStackEmpty(MyStack* obj)
{
return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}
6、销毁
不仅释放栈,也要释放队列
void myStackFree(MyStack* obj)
{
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
整体代码:
typedef int QDataType;
//每个节点的结构
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
//标识整个队列的结构
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;//队列的长度
}Queue;
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
//队列为空
if (pq->ptail == NULL)
{
assert(pq->phead == NULL);
pq->phead = pq->ptail = newnode;
}
else
{
//队列不空
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
//类似头删
assert(pq);
assert(!QueueEmpty(pq));
//1、一个节点
//2、多个节点
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
//头删
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
pq->size--;
}
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->phead->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->ptail->data;
}
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
//return pq->size == 0;
return pq->phead == NULL && pq->ptail == NULL;
}
typedef struct
{
Queue q1;//队列1
Queue q2;//队列2
} MyStack;
MyStack* myStackCreate()
{
MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
if (obj == NULL)
{
perror("malloc fail");
return NULL;
}
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* qEmpty=&obj->q1;
Queue* qNoneEmpty = &obj->q2;
if(!QueueEmpty(&obj->q1))
{
qEmpty=&obj->q2;
qNoneEmpty = &obj->q1;
}
while(QueueSize(qNoneEmpty)>1)
{
QueuePush(qEmpty,QueueFront(qNoneEmpty));
QueuePop(qNoneEmpty);
}
int top = QueueFront(qNoneEmpty);
QueuePop(qNoneEmpty);
return top;
}
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);
}
设计循环队列
链接: link
题目描述:
思路分析:
本题使用数组设计循环队列
1、假设循环队列存储k个数据,开k+1个空间,每次入队一个元素,rear指针都会指向该元素的后一个位置。
1、循环队列的结构
typedef struct
{
int front;
int rear;
int k;//队列中元素个数
int* a;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a = (int*)malloc(sizeof(int*)*(k+1));
obj->front=obj->rear = 0;
obj->k=0;
return obj;
}
2、判断循环队列为空:front=rear
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->rear==obj->front;
}
3、判断队列满:(rear+1)%(k+1)==front
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return (obj->rear+1)%(obj->k+1)==obj->front;
}
4、入数据
在rear位置入数据再让rear++,特殊情况:循环队列可能会绕回去,所以要判断rear的位置
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if( myCircularQueueIsEmpty(obj))
{
return false;
}
obj->a[obj->rear]=value;
obj->rear++;
obj->rear%=(obj->k+1);//保证范围
}
5、出数据(删除数据)
判空,如果为空,则不进行删除操作
删除操作即让front++,并且保证front的范围
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if( myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
obj->front%=(obj->k+1);//保证范围
return true;
}
6、返回队头和队尾数据
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else if(obj->rear==0)
{
return obj->a[obj->rear+k-1];
}
else
{
return obj->a[obj->rear-1];
}
}
整体代码:
typedef struct
{
int front;
int rear;
int k;//队列中元素个数
int* a;
} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->rear==obj->front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return (obj->rear+1)%(obj->k+1)==obj->front;
}
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a = (int*)malloc(sizeof(int)*(k+1));
obj->front=obj->rear = 0;
obj->k=k;
return obj;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if( myCircularQueueIsFull(obj))
{
return false;
}
obj->a[obj->rear]=value;
obj->rear++;
obj->rear%=(obj->k+1);//保证范围
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if( myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
obj->front%=(obj->k+1);//保证范围
return true;
}
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->a);
free(obj);
}