前言
俗话说:熟能生巧,我们在学习完知识,一定要运用,不运用那么他过段时间就忘了,所以大家还是要认真的看一些题
(1)有效的括号
思路:我们可以用栈的知识
将左括号入栈,右括号出栈顶元素然后匹配,如果匹配那么返回真,否则返回假。
bool isValid(char * s){
ST st;
StackInit(&st);
while(*s)
{
if(*s=='('||*s=='{'||*s=='[')
{
StackPush(&st,*s);
++s;
}
else
{
if(StackEmpty(&st))
{
StackDestroy(&st);
return false;
}
char top = StackTop(&st);
StackPop(&st);
if((top=='('&&*s!=')')||
(top=='{'&&*s!='}')||
(top=='['&&*s!=']') )
{
StackDestroy(&st);
return false;
}
else
{
++s;
}
}
}
//看栈是否为空
bool ret=StackEmpty(&st);
StackDestroy(&st);
return ret;
}
上面只是我们程序的代码,我们还要引用栈
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int capacity;
int top;//表示栈顶
}ST;
//栈的初始化
void StackInit(ST* ps);
//栈的销毁
void StackDestroy(ST* ps );
//栈的插入
void StackPush(ST* ps, STDataType x);
//栈的删除
void StackPop(ST* ps);
//判断栈是否为空
bool StackEmpty(ST* ps);
//取栈顶的元素
STDataType StackTop(ST* ps);
//看栈的大小
int StackSize(ST* ps);
//栈的初始化
void StackInit(ST* ps)
{
assert(ps);
//ps->a = NULL;
//ps->sz = 0;
//ps->top = 0;
ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
if (ps->a == NULL)
{
perror("malloc error");
exit(-1);
}
ps->capacity = 4;
ps->top = 0;
}
//栈的销毁
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
//栈的插入
void StackPush(ST* ps, STDataType x)
{
assert(ps);
//扩容
if (ps->top == ps->capacity)
{
int newcapacity = ps->capacity * 2;
STDataType* ret = (STDataType*)realloc(ps->a,sizeof(STDataType) * newcapacity);
if (ret == NULL)
{
perror("realloc error");
exit(-1);
}
ps->a = ret;
ps->capacity = newcapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
//栈的删除
void StackPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
//判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
//if (ps->top == 0)
//{
// return true;
//}
//else
//{
// return false;
//}
return ps->top == 0;
}
//取栈顶的元素
STDataType StackTop(ST* ps)
{
assert(ps);
//返会top下一个元素
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
//看栈的大小
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool isValid(char * s){
ST st;
StackInit(&st);
while(*s)
{
if(*s=='('||*s=='{'||*s=='[')
{
StackPush(&st,*s);
++s;
}
else
{
if(StackEmpty(&st))
{
StackDestroy(&st);
return false;
}
char top = StackTop(&st);
StackPop(&st);
if((top=='('&&*s!=')')||
(top=='{'&&*s!='}')||
(top=='['&&*s!=']') )
{
StackDestroy(&st);
return false;
}
else
{
++s;
}
}
}
//看栈是否为空
bool ret=StackEmpty(&st);
StackDestroy(&st);
return ret;
}
(2)用队列实现栈
思路:我们现在有两个队列,用两个队列实现栈
对列的功能是先进先出,而栈是先出后进
所以我们通过画图可以分析出来
我们有两个队列,一个队列为空,一个队列插入数据,
如果想要删除数据,就将有数据的除了要删除的数据,其他放到空队列中,然后再删除数据,原先插入队列的数据就变为了空队列。
所以两个队列肯定有一个保持空队列,一个插入数据。
其他的功能就很简单了。
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) {
assert(obj);
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
assert(obj);
Queue* Emptyq=&obj->q1;
Queue* noEmpty=&obj->q2;
if(!QueueEmpty(&obj->q1))
{
Emptyq = &obj->q2;
noEmpty = &obj->q1;
}
while(noEmpty->head!=noEmpty->tail)
{
QDataType ret = QueueFront(noEmpty);
QueuePop(noEmpty);
QueuePush(Emptyq,ret);
}
QDataType del=QueueFront(noEmpty);
QueuePop(noEmpty);
return del;
}
int myStackTop(MyStack* obj) {
assert(obj);
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
assert(obj);
return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
assert(obj);
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
因为我们是c语言,所以我们写的队列链接进去,所以完整代码入下
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
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);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* del = cur;
cur = cur->next;
free(del);
//del = NULL;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* del = pq->head;
pq->head = pq->head->next;
free(del);
}
pq->size--;
}
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL && pq->tail == NULL;
}
// 1G = 1024MB
// 1024MB = 1024*1024KB
// 1024*1024KB = 1024*1024*1024Byte
int QueueSize(Queue* pq)
{
assert(pq);
/*int size = 0;
QNode* cur = pq->head;
while (cur)
{
cur = cur->next;
++size;
}
return size;*/
return pq->size;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) {
assert(obj);
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
assert(obj);
Queue* Emptyq=&obj->q1;
Queue* noEmpty=&obj->q2;
if(!QueueEmpty(&obj->q1))
{
Emptyq = &obj->q2;
noEmpty = &obj->q1;
}
while(noEmpty->head!=noEmpty->tail)
{
QDataType ret = QueueFront(noEmpty);
QueuePop(noEmpty);
QueuePush(Emptyq,ret);
}
QDataType del=QueueFront(noEmpty);
QueuePop(noEmpty);
return del;
}
int myStackTop(MyStack* obj) {
assert(obj);
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
assert(obj);
return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
assert(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);
*/
(3)用栈实现队列
思路:我们可以模仿以下上面的思路,但是我们肯定需要做一些改动。
我们通过画图,产生一个思路
我们的两个栈,分为插入栈和删除栈。
只要插入数据我们就将数据放到插入栈中,
想要删除数据,如果删除栈为空,就将插入栈的全部数据放到删除栈,然后再删除数据,知道删除栈为空,再重复操作。
typedef struct {
ST PushST;
ST PopST;
} MyQueue;
int myQueuePeek(MyQueue* obj);
bool myQueueEmpty(MyQueue* obj);
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&obj->PushST);
StackInit(&obj->PopST);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
assert(obj);
StackPush(&obj->PushST,x);
}
int myQueuePop(MyQueue* obj) {
assert(obj);
assert(!myQueueEmpty(obj));
int peek = myQueuePeek(obj);
StackPop(&obj->PopST);
return peek;
}
int myQueuePeek(MyQueue* obj) {
assert(obj);
assert(!myQueueEmpty(obj));
if(StackEmpty(&obj->PopST))
{
while(!StackEmpty(&obj->PushST))
{
StackPush(&obj->PopST,StackTop(&obj->PushST));
StackPop(&obj->PushST);
}
}
return StackTop(&obj->PopST);
}
bool myQueueEmpty(MyQueue* obj) {
assert(obj);
return StackEmpty(&obj->PushST)&&StackEmpty(&obj->PopST);
}
void myQueueFree(MyQueue* obj) {
assert(obj);
StackDestroy(&obj->PushST);
StackDestroy(&obj->PopST);
free(obj);
obj=NULL;
}
因为我们是c语言,所以我们要把自己的写的栈也链接进去,所以完整代码就是
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int capacity;
int top;//表示栈顶
}ST;
//栈的初始化
void StackInit(ST* ps);
//栈的销毁
void StackDestroy(ST* ps );
//栈的插入
void StackPush(ST* ps, STDataType x);
//栈的删除
void StackPop(ST* ps);
//判断栈是否为空
bool StackEmpty(ST* ps);
//取栈顶的元素
STDataType StackTop(ST* ps);
//看栈的大小
int StackSize(ST* ps);
//栈的初始化
void StackInit(ST* ps)
{
assert(ps);
//ps->a = NULL;
//ps->sz = 0;
//ps->top = 0;
ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
if (ps->a == NULL)
{
perror("malloc error");
exit(-1);
}
ps->capacity = 4;
ps->top = 0;
}
//栈的销毁
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
//栈的插入
void StackPush(ST* ps, STDataType x)
{
assert(ps);
//扩容
if (ps->top == ps->capacity)
{
int newcapacity = ps->capacity * 2;
STDataType* ret = (STDataType*)realloc(ps->a,sizeof(STDataType) * newcapacity);
if (ret == NULL)
{
perror("realloc error");
exit(-1);
}
ps->a = ret;
ps->capacity = newcapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
//栈的删除
void StackPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
//判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
//if (ps->top == 0)
//{
// return true;
//}
//else
//{
// return false;
//}
return ps->top == 0;
}
//取栈顶的元素
STDataType StackTop(ST* ps)
{
assert(ps);
//返会top下一个元素
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
//看栈的大小
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
typedef struct {
ST PushST;
ST PopST;
} MyQueue;
int myQueuePeek(MyQueue* obj);
bool myQueueEmpty(MyQueue* obj);
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&obj->PushST);
StackInit(&obj->PopST);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
assert(obj);
StackPush(&obj->PushST,x);
}
int myQueuePop(MyQueue* obj) {
assert(obj);
assert(!myQueueEmpty(obj));
int peek = myQueuePeek(obj);
StackPop(&obj->PopST);
return peek;
}
int myQueuePeek(MyQueue* obj) {
assert(obj);
assert(!myQueueEmpty(obj));
if(StackEmpty(&obj->PopST))
{
while(!StackEmpty(&obj->PushST))
{
StackPush(&obj->PopST,StackTop(&obj->PushST));
StackPop(&obj->PushST);
}
}
return StackTop(&obj->PopST);
}
bool myQueueEmpty(MyQueue* obj) {
assert(obj);
return StackEmpty(&obj->PushST)&&StackEmpty(&obj->PopST);
}
void myQueueFree(MyQueue* obj) {
assert(obj);
StackDestroy(&obj->PushST);
StackDestroy(&obj->PopST);
free(obj);
obj=NULL;
}
(4)设计循环队列
思路:我们的循环队列,可以有两种方式,一种是数组,一种是链表,我们想要采用哪种,需要我们自己分析,分析我们的思路,以及每一步的操作的对于那种方法好。
我们如果要用链表,我们可以完成这个循环,先进先出,我们就需要两个指针,一个头指针,一个尾指针。
我们先这可以判断,队列为空的条件是head = tail
,但是我们如果链表满了,我们的条件就还是这个,判断不了是空,还是满,所以解决办法是可以设置一个sz
,我们还可以增加一个结点,然后等满的时候我们的条件就是tail->next=head
.
我们队首的元素就是head
所指的元素,我们的队尾元素就是我们tail
的上一个元素,所以我们这个不好找,解决方法是我们在遍历的时候留下我们的上一个元素地址,我们就可以找到了。
我们在删除链表的时候,还得遍历链表,太复杂了,我们就可以选择顺序表,我们就可以进行下标的随机访问。
我们在进行顺序表的时候,我们在创建空间的时候我们也多创建一个空间
我们要找front
我们就直接找下标对应的元素,找rear
的下一个元素,我们插入数据直接在rear上插入,删除数据在front直接向前挪一。我们唯一要注意的就是我们的内容满了就不能在添加了。
typedef struct {
int* a;
int front;
int rear;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a=(int*)malloc(sizeof(int)*(k+1));
obj->front=0;
obj->rear=0;
obj->k=k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
assert(obj);
return obj->rear==obj->front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
assert(obj);
return (obj->rear+1)%(obj->k+1)==obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
assert(obj);
if(myCircularQueueIsFull(obj))
{
return false;
}
obj->a[obj->rear]=value;
obj->rear=(obj->rear+1)%(obj->k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
assert(obj);
if(myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front=(obj->front+1)%(obj->k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
assert(obj);
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
assert(obj);
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
assert(obj);
free(obj->a);
free(obj);
}
总结
我们的栈和队列问题,这些题是关键。大家多多练习,大家一起加油。