注:本文所使用代码语言为C语言,栈和队列均为笔者用C语言实现,详情请看 栈和队列的C语言实现
本文所使用的栈和队列的结构
栈
typedef char DataType;
typedef struct Stack
{
DataType* a;
int top;//栈顶
int capacity;//容量
}Stack;
void StackInit(Stack* ps)//初始化栈
{
assert(ps);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
void StackPush(Stack* ps, DataType data)//入栈
{
assert(ps);
if (ps->top == ps->capacity||ps->top==0)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
DataType* tmp = (DataType*)realloc(ps->a, sizeof(DataType) * newCapacity);
if (tmp == NULL)
{
perror("realloc");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
(ps->a)[ps->top] = data;
ps->top++;
}
void StackPop(Stack* ps)//出栈
{
assert(ps);
assert(ps->top>0);
ps->top--;
}
int StackSize(Stack* ps)//获取栈中有效元素的个数
{
assert(ps);
return ps->top;
}
DataType StackTop(Stack* ps)//获取栈顶元素
{
assert(ps);
return (ps->a)[ps->top - 1];
}
int StackEmpty(Stack* ps)//检测栈是否为空 如果为空就返回1,不为空就返回0
{
assert(ps);
return ps->top == 0;
}
void StackDestory(Stack* ps)//销毁栈
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
队列
typedef int DataType;
typedef struct QListNode
{
DataType data;
struct QListNode* next;
}Node;
typedef struct Queque
{
Node* head;
Node* tail;
int size;
}Queue;
void QueueInit(Queue* p);//初始化
void QueuePush(Queue* p, DataType x);//队尾入队列
void QueuePop(Queue* p);//队头出数据
DataType QueueFront(Queue* p);//获取队列头部元素
DataType QueueBack(Queue* p);//获取队列尾部元素
int QuequeSize(Queue* p);//获取队列中有效元素的个数
bool QueueEmpty(Queue* p);//检测队列是否为空
void QueueDestroy(Queue* p);//销毁队列
void QueueInit(Queue* p)//初始化
{
assert(p);
p->head = NULL;
p->tail = NULL;
p->size = 0;
}
void QueuePush(Queue* p, DataType x)//队尾入队列
{
assert(p);
Node* newnode = (Node*)malloc(sizeof(Node));
if (newnode == NULL)
{
perror("malloc");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (p->head == NULL)
{
p->head = newnode;
p->tail = newnode;
}
else
{
p->tail->next = newnode;
p->tail = newnode;
}
p->size++;
}
void QueuePop(Queue* p)//队头出队列
{
assert(p);
assert(p->head);//如果没有数据就出不了了
Node* tmp = p->head;
p->head = p->head->next;
if (p->tail == tmp)
{
p->tail = p->tail->next;
}
free(tmp);
p->size--;
}
DataType QueueFront(Queue* p)//获取队列头部元素
{
assert(p && p->head);
return p->head->data;
}
DataType QueueBack(Queue* p)//获取队列尾部元素
{
assert(p && p->head);
return p->tail->data;
}
int QuequeSize(Queue* p)//获取队列中有效元素的个数
{
assert(p);
return p->size;
}
bool QueueEmpty(Queue* p)//检测队列是否为空
{
assert(p);
return p->head == NULL;
}
void QueueDestroy(Queue* p)//销毁队列
{
assert(p);
while (p->head)
{
Node* tmp = p->head;
p->head = p->head->next;
free(tmp);
}
p->tail = NULL;
p->head = NULL;
p->size = 0;
}
括号匹配问题(有效的括号)
解题思路
如果是一个符合题意的字符串,那么当在字符串中遇到一个左括号时,在后续的遍历中,一定会有有一个相同类型的右括号与之对应。当多试几个样例后会发现,倘若是多个左括号在一起,那么最先配对成功的一定就是最后一个。依照这个思路,可以尝试用栈这个数据结构。
所以,当我们在遍历字符串碰到左括号时,就将左括号进行压栈操作,每当碰到右括号时,就将左括号取出看是否与其对应,如此往复,直到字符串遍历完或者出现括号不对应的情况。
bool isValid(char * s){
Stack st;
StackInit(&st);
while(*s)
{
if(*s=='('||*s=='['||*s=='{')//左括号就进栈
{
StackPush(&st,*s);
}
if(*s==')'||*s==']'||*s=='}')//碰过右括号就比较
{
if (StackEmpty(&st))//如果栈内为空
{
StackDestory(&st);
return false;
}
char top=StackTop(&st);
StackPop(&st);
if((top=='('&&*s!=')')||(top=='{'&&*s!='}')||(top=='['&&*s!=']'))
{
return false;
}
}
s++;
}
if (StackEmpty(&st))//如果栈内为空
{
StackDestory(&st);
return true;
}
StackDestory(&st);
return false;
}
用队列实现栈
思路
设置两个队列,一个用于导入数据,一个用于存储数据
例:
当需要Pop的时候,就将存储数据的队列的前n-1个数据挪到另一个队列,在将最后一个数删掉(因为从栈的角度上,1是在“栈底”的元素,4是“栈顶”的元素)
当再次往"栈"里插入数据的时候,就将插入到不为空的队列里
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->q1)))//当q1不为空时
{
QueuePush(&(obj->q1),x);
}
else
{
QueuePush(&(obj->q2),x);
}
}
int myStackPop(MyStack* obj) {
Queue*empty=&(obj->q1);
Queue*nonEmpty=&(obj->q2);
if(!QueueEmpty(&(obj->q1)))//先确定好哪个为空,哪个不为空
{
nonEmpty=&(obj->q1);
empty=&(obj->q2);
}
while(QuequeSize(nonEmpty)>1)//再将不为空的队列中的数往为空的队列中转移
{
QueuePush(empty,QueueFront(nonEmpty));
QueuePop(nonEmpty);
}
int top=QueueFront(nonEmpty);
QueuePop(nonEmpty);
return top;
}
int myStackTop(MyStack* obj) {
if(!QueueEmpty(&(obj->q1)))
{
return QueueBack(&(obj->q1));
}
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);
}
用栈实现队列
思路
当要用到栈去实现队列时,当往"队列"中去插入数据
当我们想要去"队列"中取数据时,我们应该取到的数据是3,所以,我们还需要一个栈来放前面的两个元素
此时3就成为了栈顶的数据,可以对其进行取出或者删除操作
于是就有了这么一条思路
准备两个栈,一个负责push(插入)数据,一个负责pop(删除)数据,当需要进行push操作时,就将数据往push栈中插入;若要进行pop操作时,先看pop栈有没有数据可供pop,如果有,就直接从pop栈中弹出数据,若没有,就先将push栈中的数据挪到pop栈中,在进行pop操作
typedef struct {
Stack PushSt;
Stack PopSt;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue*queue=(MyQueue*)malloc(sizeof(MyQueue));
StackInit(&(queue->PushSt));
StackInit(&(queue->PopSt));
return queue;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&(obj->PushSt),x);
}
int myQueuePop(MyQueue* obj) {
if(StackEmpty(&(obj->PopSt)))//如果PopSt栈中没有数据的话,就要先从PushSt中导入数据
{
while(!StackEmpty(&(obj->PushSt)))
{
StackPush(&(obj->PopSt),StackTop(&(obj->PushSt)));
StackPop(&(obj->PushSt));
}
}
int tmp=StackTop(&(obj->PopSt));
StackPop(&(obj->PopSt));
return tmp;
}
int myQueuePeek(MyQueue* obj) {
if(StackEmpty(&(obj->PopSt)))//如果PopSt栈中没有数据的话,就要先从PushSt中导入数据
{
while(!StackEmpty(&(obj->PushSt)))
{
StackPush(&(obj->PopSt),StackTop(&(obj->PushSt)));
StackPop(&(obj->PushSt));
}
}
return StackTop(&(obj->PopSt));
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&(obj->PopSt))&&StackEmpty(&(obj->PushSt));
}
void myQueueFree(MyQueue* obj) {
StackDestory(&(obj->PopSt));
StackDestory(&(obj->PushSt));
free(obj);
}
设计循环队列
思路
循环队列的实现用不论是顺序表还是链表都可以,这里用顺序表来介绍思路
由于题目中要我们实现的循环队列的长度是固定的,我们很容易想到,直接在动态申请大小为k个int大小的连续空间,由于是可循环的,它的逻辑图如下
实际情况如下
每当往队列里插入数据时,队列尾就往后一格,当删除数据的时候,队列头就往前一格,队列头和队列尾之间的位置就是有效元素
当一直插入数据直到队列满时
此时,队头和队尾指向同一个位置,但是当队列为空时,队头和队尾也是指向同一个位置,不好区分。
于是,我们在申请空间时,申请的空间要比规定长度大1,这多出来的空间就可以用来做区分:
当队列的头和尾指向一起时,就说明此时的队列为空,倘若队列尾的下一个元素被队列头指着,说明此时,队列已经满了
typedef struct {
int*arr;
int front;
int rear;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue*queue=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
queue->arr=(int*)malloc(sizeof(int)*(k+1));
queue->front=0;
queue->rear=0;
queue->k=k;
return queue;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if((obj->rear+1)%(obj->k+1)==obj->front)//如果队列满了
{
return false;
}
obj->arr[obj->rear]=value;
obj->rear++;
if(obj->rear>obj->k)
{
obj->rear=(obj->rear)%(obj->k+1);
}
printf("%d %d\n",obj->front,obj->rear);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(obj->front==obj->rear)//如果队列为空
{
return false;
}
obj->front++;
if(obj->front>obj->k)
{
obj->front=(obj->front)%(obj->k+1);
}
printf("%d %d\n",obj->front,obj->rear);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(obj->front==obj->rear)//如果队列为空
{
return -1;
}
printf("%d %d\n",obj->front,obj->rear);
return obj->arr[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(obj->front==obj->rear)//如果队列为空
{
return -1;
}
if(obj->rear==0)
{
return obj->arr[obj->k];
}
printf("%d %d\n",obj->front,obj->rear);
return obj->arr[obj->rear-1];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
if(obj->front==obj->rear)//如果队列为空
{
return true;
}
printf("%d %d\n",obj->front,obj->rear);
return false;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
if((obj->rear+1)%(obj->k+1)==obj->front)//如果队列满了
{
return true;
}
printf("%d %d\n",obj->front,obj->rear);
return false;
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}
用链表结构实现
typedef struct QueueNode
{
int data;
struct QueueNode*next;
}QueueNode;
typedef struct {
QueueNode*tail;
QueueNode*front;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
QueueNode*node=(QueueNode*)malloc(sizeof(QueueNode));//多出来的那个结点
MyCircularQueue*queue=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
node->next=NULL;
QueueNode*tmp=node;
for(int i=1;i<=k;i++)
{
QueueNode*newnode=(QueueNode*)malloc(sizeof(QueueNode));
newnode->next=NULL;
tmp->next=newnode;
tmp=tmp->next;
}
tmp->next=node;//创建了一个循环链表
queue->tail=node;
queue->front=node;
return queue;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
if(obj->tail->next==obj->front)
{
return true;
}
return false;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
if(obj->tail==obj->front)
{
return true;
}
return false;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))//如果是满的话
{
return false;
}
obj->tail->data=value;
obj->tail=obj->tail->next;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(obj->front==obj->tail)//没有元素可以删了
{
return false;
}
obj->front=obj->front->next;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->front->data;
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
QueueNode*cur=obj->front;
while(cur->next!=obj->tail)
{
cur=cur->next;
}
return cur->data;
}
void myCircularQueueFree(MyCircularQueue* obj) {
QueueNode*cur=obj->front;
QueueNode*Next=cur->next;
while(1)
{
if(cur==obj->tail)
{
free(cur);
obj->front=NULL;
obj->tail=NULL;
break;
}
free(cur);
cur=Next;
Next=Next->next;
}
}