1.栈
1.1栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
1.2栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更有一些。因为在数组为上插入数据的代价比较小。
接下来我们一起用数组实现栈
定义结构体
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;//栈的容量
}ST;
定义一个
STDataType
类型的指针,int
类型的top
变量记录位置,int
类型的capacity
变量记录栈的容量
Stack.h文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;//栈的容量
}ST;
//栈的初始化
void STackInit(ST* ps);
//栈的销毁
void STackDestroy(ST* ps);
//入栈
void STackPush(ST* ps, STDataType x);
//出栈
void STackPop(ST* ps);
//判断是否栈空
bool STackEmpty(ST* ps);
//栈的大小
int STackSize(ST* ps);
//获取栈顶元素
STDataType STackTop(ST* ps);
Stack.c文件
#include"Stack.h"
//栈的初始化
void STackInit(ST* ps)
{
assert(ps);
STDataType* tmp = (STDataType*)malloc(sizeof(STDataType) * 3);
if (tmp == NULL)
{
perror("STackInit(ST* ps)::malloc");
return;
}
ps->a = tmp;
ps->capacity = 3;
ps->top = 0;//指向栈顶元素下一个位置
//ps->a = -1;//指向栈顶元素的位置
}
//栈的销毁
void STackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->capacity = ps->top = 0;
}
//入栈
void STackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
STDataType* tmp = (STDataType*)realloc(ps->a,
sizeof(STDataType)*ps->capacity * 2);
if (tmp == NULL)
{
perror("STackPush::realloc");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top++] = x;
}
//出栈
void STackPop(ST* ps)
{
assert(ps);
assert(!STackEmpty(ps));
ps->top--;
}
//判断是否栈空
bool STackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//栈的大小
int STackSize(ST* ps)
{
assert(ps);
return ps->top;
}
//获取栈顶元素
STDataType STackTop(ST* ps)
{
assert(ps);
assert(!STackEmpty(ps));
return ps->a[ps->top-1];
}
test.c文件
#include"Stack.h"
int main()
{
ST st;
STackInit(&st);
STackPush(&st, 1);
STackPush(&st, 2);
STackPush(&st, 3);
STackPush(&st, 4);
STackPush(&st, 5);
printf("当前栈的大小为:>%d\n", STackSize(&st));
while (!STackEmpty(&st))
{
printf("%d ", STackTop(&st));
STackPop(&st);
}
return 0;
}
代码运行的结果为:
2.队列
2.1队列的概念及实现
队列:只允许在一端进行插入数据操作,在另一端进行删除操作的特殊线性表,队列具有先进先出(
First in First Out
)入队列:进行插入操作的一端为队尾,出队列:进行删除操作的一端称为队头。
2.2队列的实现
队列也可以使用数组和链表的结构实现,使用链表的结构更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率比较低。注意: 使用链表解结构实现,出队列操作,一定会修改头指针,如果出队列之后,队列为空,需要修改尾指针。
Queue.h文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}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);
//队列大小
int QueueSize(Queue* pq);
//队列判空
bool QueueEmpty(Queue* pq);
//获取队头元素
QDataType QueueFront(Queue* pq);
//获取队尾元素
QDataType QueueBase(Queue* pq);
Queue.c文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
//队列初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
//队列销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
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("QueuePush::malloc");
return;
}
newnode->next = NULL;
newnode->data = x;
if (pq->head == NULL)
{
assert(pq->tail == NULL);
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
//出队列
void QueuePop(Queue* pq)
{
assert(pq);
//QNode* del = pq->head;
//pq->head = del->next;
//free(del);
//if (pq->head == NULL)
// pq->tail = NULL;
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
pq->size--;
}
//队列大小
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
//队列判空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
//获取队头元素
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
//获取队尾元素
QDataType QueueBase(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
test.c文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
int main()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePop(&q);
QueuePush(&q, 2);
QueuePop(&q);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
printf("队列元素个数为:>%d\n", QueueSize(&q));
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
return 0;
}
代码测试的结果为:
3.栈和队列的面试题
3.1括号匹配问题
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;//栈的容量
}ST;
//栈的初始化
void STackInit(ST* ps);
//栈的销毁
void STackDestroy(ST* ps);
//入栈
void STackPush(ST* ps, STDataType x);
//出栈
void STackPop(ST* ps);
//判断是否栈空
bool STackEmpty(ST* ps);
//栈的大小
int STackSize(ST* ps);
//获取栈顶元素
STDataType STackTop(ST* ps);
//栈的初始化
void STackInit(ST* ps)
{
//assert(ps);
STDataType* tmp = (STDataType*)malloc(sizeof(STDataType) * 3);
if (tmp == NULL)
{
perror("STackInit(ST* ps)::malloc");
return;
}
ps->a = tmp;
ps->capacity = 3;
ps->top = 0;//指向栈顶元素下一个位置
//ps->a = -1;//指向栈顶元素的位置
}
//栈的销毁
void STackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->capacity = ps->top = 0;
}
//入栈
void STackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
STDataType* tmp = (STDataType*)realloc(ps->a,
sizeof(STDataType)*ps->capacity * 2);
if (tmp == NULL)
{
perror("STackPush::realloc");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top++] = x;
}
//判断是否栈空
bool STackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//出栈
void STackPop(ST* ps)
{
assert(ps);
assert(!STackEmpty(ps));
ps->top--;
}
//栈的大小
int STackSize(ST* ps)
{
assert(ps);
return ps->top;
}
//获取栈顶元素
STDataType STackTop(ST* ps)
{
assert(ps);
assert(!STackEmpty(ps));
return ps->a[ps->top-1];
}
bool isValid(char * s)
{
ST st;
STackInit(&st);
//StackInit(&st);
while(*s)
{
if(*s=='('||*s=='['||*s=='{')
{
STackPush(&st,*s);
}
else{
//右括号比左括号多的情况
if(STackEmpty(&st))
{
STackDestroy(&st);
return false;
}
char top=STackTop(&st);
if((top=='('&&*s!=')')||
(top=='['&&*s!=']')||
(top=='{'&&*s!='}'))
{
STackDestroy(&st);
return false;
}
STackPop(&st);
}
s++;
}
//左括号比右括号多的情况
bool ret =STackEmpty(&st);
STackDestroy(&st);
return ret;
}
3.2用队列实现栈
图形理解:
代码实现:
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}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);
//队列大小
int QueueSize(Queue* pq);
//队列判空
bool QueueEmpty(Queue* pq);
//获取队头元素
QDataType QueueFront(Queue* pq);
//获取队尾元素
QDataType QueueBase(Queue* pq);
//队列初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
//队列销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
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("QueuePush::malloc");
return;
}
newnode->next = NULL;
newnode->data = x;
if (pq->head == NULL)
{
assert(pq->tail == NULL);
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
//出队列
void QueuePop(Queue* pq)
{
assert(pq);
//QNode* del = pq->head;
//pq->head = del->next;
//free(del);
//if (pq->head == NULL)
// pq->tail = NULL;
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
pq->size--;
}
//队列大小
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
//队列判空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
//获取队头元素
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
//获取队尾元素
QDataType QueueBase(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* pst=(MyStack*)malloc(sizeof(MyStack));
if(pst==NULL)
{
perror("myStackCreate()::malloc");
return NULL;
}
QueueInit(&pst->q1);
QueueInit(&pst->q2);
return pst;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
Queue* noneempty=&obj->q1;
Queue* empty=&obj->q2;
if(QueueEmpty(&obj->q1))
{
noneempty=&obj->q2;
empty=&obj->q1;
}
while(QueueSize(noneempty)>1)
{
QueuePush(empty,QueueFront(noneempty));
QueuePop(noneempty);
}
int top=QueueFront(noneempty);
QueuePop(noneempty);
return top;
}
int myStackTop(MyStack* obj) {
if(!QueueEmpty(&obj->q1))
{
return QueueBase(&obj->q1);
}
else
{
return QueueBase(&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用栈实现队列
图形理解:
代码实现:
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;//栈的容量
}ST;
//栈的初始化
void STackInit(ST* ps);
//栈的销毁
void STackDestroy(ST* ps);
//入栈
void STackPush(ST* ps, STDataType x);
//出栈
void STackPop(ST* ps);
//判断是否栈空
bool STackEmpty(ST* ps);
//栈的大小
int STackSize(ST* ps);
//获取栈顶元素
STDataType STackTop(ST* ps);
//栈的初始化
void STackInit(ST* ps)
{
assert(ps);
STDataType* tmp = (STDataType*)malloc(sizeof(STDataType) * 3);
if (tmp == NULL)
{
perror("STackInit(ST* ps)::malloc");
return;
}
ps->a = tmp;
ps->capacity = 3;
ps->top = 0;//指向栈顶元素下一个位置
//ps->a = -1;//指向栈顶元素的位置
}
//栈的销毁
void STackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->capacity = ps->top = 0;
}
//入栈
void STackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
STDataType* tmp = (STDataType*)realloc(ps->a,
sizeof(STDataType)*ps->capacity * 2);
if (tmp == NULL)
{
perror("STackPush::realloc");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top++] = x;
}
//出栈
void STackPop(ST* ps)
{
assert(ps);
assert(!STackEmpty(ps));
ps->top--;
}
//判断是否栈空
bool STackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//栈的大小
int STackSize(ST* ps)
{
assert(ps);
return ps->top;
}
//获取栈顶元素
STDataType STackTop(ST* ps)
{
assert(ps);
assert(!STackEmpty(ps));
return ps->a[ps->top-1];
}
typedef struct {
ST pushst;
ST popst;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
if(obj==NULL)
{
perror("myQueueCreate()::malloc");
return NULL;
}
STackInit(&obj->pushst);
STackInit(&obj->popst);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
STackPush(&obj->pushst,x);
}
int myQueuePeek(MyQueue* obj) {
if(STackEmpty(&obj->popst))
{
while(!STackEmpty(&obj->pushst))
{
STackPush(&obj->popst,STackTop(&obj->pushst));
STackPop(&obj->pushst);
}
}
return STackTop(&obj->popst);
}
int myQueuePop(MyQueue* obj) {
int top=myQueuePeek(obj);
STackPop(&obj->popst);
return top;
}
bool myQueueEmpty(MyQueue* obj) {
return STackEmpty(&obj->pushst)&&
STackEmpty(&obj->popst);
}
void myQueueFree(MyQueue* obj) {
STackDestroy(&obj->pushst);
STackDestroy(&obj->popst);
free(obj);
}
3.4设计循环队列
代码实现:
typedef struct {
int* a;
int front;//首元素下标
int rear;//末尾元素的下一个位置
int k;//循环队列的数据个数
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
if(obj==NULL)
{
perror("myCircularQueueCreate::malloc");
return NULL;
}
int* tmp=(int*)malloc(sizeof(int)*(k+1));//多开一段空间
if(tmp==NULL)
{
perror("myCircularQueueCreate::malloc");
return NULL;
}
obj->a=tmp;
obj->front=obj->rear=0;
obj->k=k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
//rear\front下标相同时,循环队列为空
return obj->rear==obj->front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
//rear下一个位置与front的位置相同时,循环队列为满
return (obj->rear+1)%(obj->k+1)==obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
{
return false;
}
//obj->a[obj->rear++]=value;
obj->a[obj->rear++]=value;
//rear到末尾的情况
obj->rear %=(obj->k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
//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;
}
else
{
//rear前一个的位置为队尾的情况
//rear在数组开头的时候,特殊处理
return obj->a[(obj->rear-1+obj->k+1)%(obj->k+1)];
}
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}