1.栈
1.1栈的概念及结构
1.1.1概念
栈 :一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(LastInFirstOut)的则。
压栈 :栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。

1.1.2结构
数组栈

链式栈
如果用尾做栈顶,尾插尾删,要设计成双向链表,否则删除数据效率低
如果用头做栈顶,头插头删,就可以设计成单链表

两种都可以,非要选一种,数组栈结构稍微好一点。
1.2接口函数
cpp
//要改变结构体的内容
//传结构体的指针
void StackInit(ST* ps);
void StackDestory(ST* ps);
void StackPush(ST* ps,STDataType x);
void StackPop(ST* ps);
STDataType StackTop(ST* ps);
//取栈顶的数据
int StackSize(ST* ps);
//栈中元素个数
bool StackEmpty(ST* ps);
//判断栈是否为空
1.3详细代码
cpp
#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)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
//初始化时,top给的是0,
// 意味着top指向栈顶数据的下一个
// ps->top=-1;
//初始化时,top给的是 - 1,
// 意味着top指向栈顶数据
ps->capacity = 0;
}
void StackDestory(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 ==\
0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)\
realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
void StackPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
//栈不为空才能删
ps->top--;
}
STDataType StackTop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
//栈不为空才能取栈顶元素
return ps->a[ps->top - 1];
}
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool StackEmpty(ST* ps)
{
assert(ps);
/*
if (ps->top == 0)
return true;
else
return false;
*/
return ps->top == 0;
}
void TestStack()
{
ST st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
//遍历栈中的数据
while (!StackEmpty(&st))
{
printf("%d ", StackTop(&st));
StackPop(&st);
}
StackDestory(&st);
}
int main()
{
TestStack();
return 0;
}
1.4例题:有效括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
cpp
bool isValid(char* s)
{
struct Stack st;
Init(&st);
while(*s)
{
//左括号入栈
if(*s=='(' || *s=='[' || *s=='{')
{
Push(&st,*s);
s++;
}
//剩下的都是右括号
else
{
//如果没有左括号和剩下的右括号匹配
//就不是有效括号
if(isEmpty(&st))
return false;
//取出栈顶的左括号
char top=GetTop(&st);
Pop(&st);
//如果左括号和右括号不匹配
//就不是有效括号
if((top=='(' && *s!=')')||
(top=='[' && *s!=']')||
(top=='{' && *s!='}'))
{
Destory(&st);
return false;
}
//匹配了就往后继续判断
else
s++;
}
}
//如果列表的左括号和右括号都能匹配上
//则执行完while循环后,栈为空
if(isEmpty(&st))
return true;
Destory(&st);
return false;
}
2.队列
2.1队列的概念及结构
队列: 只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列: 进行插入操作的一端称为队尾
**出队列:**进行删除操作的一端称为队头

2.2队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
2.2.1接口函数
cpp
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);
2.2.1.1定义队列
cpp
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int QDataType;
//这是单链表,要有节点
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QueueNode;
//为了方便尾插,除了有一个头指针,
//还要有一个尾指针
//所以定义一个结构体出来
typedef struct Queue
{
QueueNode* head;
QueueNode* tail;
}Queue;
2.2.1.2初始化队列
cpp
//传结构体的指针,无需二级指针
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
2.2.1.3销毁队列
cpp
void QueueDestory(Queue* pq)
{
assert(pq);
QueueNode* cur = pq->head;
while (cur != NULL)
{
QueueNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = NULL;
pq->head = NULL;
}
2.2.1.4队尾入
cpp
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
printf("malloc fail.\n");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
//如果没有节点
if (pq == NULL)
{
pq->head = newnode;
pq->tail = newnode;
}
//有节点就直接插入、链接
else
{
//head tail newnode
pq->tail->next = newnode;
pq->tail = newnode;
}
}
2.2.1.5队头出
cpp
void QueuePop(Queue* pq)
{
assert(pq);
//队列不能为空
assert(pq->head);
//如果只有一个节点
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = NULL;
pq->tail = NULL;
}
//先保存下一个
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
2.2.1.6判断队列是否为空
cpp
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
2.2.1.7获取队头的数据
cpp
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->data;
}
2.2.1.8获取队尾的数据
cpp
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->tail->data;
}
2.2.1.9获取队列大小
cpp
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QNode* cur = pq->head;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
2.2.1.10销毁队列
cpp
void QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = NULL;
pq->tail = NULL;
}
2.2.1.11测试
cpp
void Test()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePop(&q);
QueuePush(&q, 5);
printf("size=%d\n", QueueSize(&q));
printf("head=%d\n", QueueFront(&q));
printf("tail=%d\n", QueueBack(&q));
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
QueueDestroy(&q);
}
3.测试
3.1用栈实现队列
cpp
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int Type;
struct Stack
{
int top;
int capacity;
Type* a;
};
void Init(struct Stack* st)
{
assert(st);
st->a = NULL;
st->top = 0;
st->capacity = 0;
}
void Push(struct Stack* st,Type x)
{
int newCapacity = 4;
if (st->top == st->capacity)
{
if (st->top != 0)
newCapacity = st->capacity * 2;
Type* tmp = (Type*)realloc(st->a,sizeof(Type)*newCapacity);
if (tmp == NULL)
{
printf("realloc fail.\n");
exit(-1);
}
st->a = tmp;
st->capacity = newCapacity;
}
st->a[st->top] = x;
st->top++;
}
void Pop(struct Stack* st)
{
assert(st);
assert(st->top > 0);
st->top--;
}
Type Top(struct Stack* st)
{
assert(st);
assert(st->top > 0);
return st->a[st->top - 1];
}
Type Peek(struct Stack* st)
{
assert(st);
assert(st->top > 0);
return st->a[0];
}
bool isEmpty(struct Stack* st)
{
assert(st);
return st->top == 0;
}
int Size(struct Stack* st)
{
assert(st);
return st->top;
}
void Destory(struct Stack* st)
{
assert(st);
free(st->a);
st->capacity = 0;
st->top = 0;
}
void Print(struct Stack* st)
{
int i = 0;
for (i = 0;i < st->top;i++)
printf("%d ", st->a[i]);
printf("\n");
}
typedef struct
{
struct Stack st1;
struct Stack st2;
} MyQueue;
MyQueue* myQueueCreate()
{
MyQueue* q=(MyQueue*)malloc(sizeof(MyQueue));
Init(&q->st1);
Init(&q->st2);
return q;
}
void myQueuePush(MyQueue* obj, int x)
{
Push(&obj->st1,x);
}
int myQueuePop(MyQueue* obj)
{
int top=0;
int ret=Peek(&obj->st1);
while(Size(&obj->st1)>1)
{
top=Top(&obj->st1);
Push(&obj->st2,top);
Pop(&obj->st1);
}
Pop(&obj->st1);
while(Size(&obj->st2))
{
top=Top(&obj->st2);
Push(&obj->st1,top);
Pop(&obj->st2);
}
return ret;
}
int myQueuePeek(MyQueue* obj)
{
return Peek(&obj->st1);
}
bool myQueueEmpty(MyQueue* obj)
{
return isEmpty(&obj->st1);
}
void myQueueFree(MyQueue* obj)
{
Destory(&obj->st1);
Destory(&obj->st2);
}
3.2用队列实现栈
cpp
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int Type;
struct QueueNode
{
Type val;
struct QueueNode* next;
};
struct Queue
{
struct QueueNode* head;
struct QueueNode* tail;
};
void Init(struct Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
void Push(struct Queue* pq, Type x)
{
struct QueueNode* newnode = (struct QueueNode*)malloc(sizeof(struct QueueNode));
if (newnode == NULL)
{
printf("malloc fail.\n");
exit(-1);
}
newnode->val = x;
newnode->next = NULL;
if (pq->head == NULL)
{
pq->head = newnode;
pq->tail = newnode;
return;
}
pq->tail->next = newnode;
pq->tail = newnode;
}
void Pop(struct Queue* pq)
{
assert(pq);
assert(pq->head);
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = NULL;
return;
}
struct QueueNode* nxt = pq->head->next;
free(pq->head);
pq->head = nxt;
}
Type Front(struct Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->val;
}
Type Back(struct Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->tail->val;
}
int Size(struct Queue* pq)
{
assert(pq);
struct QueueNode* cur = pq->head;
int size = 0;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
bool isEmpty(struct Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
void Destory(struct Queue* pq)
{
assert(pq);
struct QueueNode* cur = pq->head;
while (cur)
{
struct QueueNode* nxt = cur->next;
free(cur);
cur = nxt;
}
pq->head = NULL;
pq->tail = NULL;
}
typedef struct
{
struct Queue q1;
struct Queue q2;
} MyStack;
MyStack* myStackCreate()
{
MyStack* st = (MyStack*)malloc(sizeof(MyStack));
Init(&st->q1);
Init(&st->q2);
return st;
}
void myStackPush(MyStack* obj, int x)
{
if (!isEmpty(&obj->q1))
Push(&obj->q1,x);
else
Push(&obj->q2,x);
}
int myStackTop(MyStack* obj)
{
if (!isEmpty(&obj->q1))
return Back(&obj->q1);
return Back(&obj->q2);
}
bool myStackEmpty(MyStack* obj)
{
if (isEmpty(&obj->q1) && isEmpty(&obj->q2))
return true;
return false;
}
int myStackPop(MyStack* obj)
{
if (myStackEmpty(obj))
return -1;
int top = 0;
int ret=myStackTop(obj);
if (!isEmpty(&obj->q1))
{
while (Size(&obj->q1)>1)
{
top =Front(&obj->q1);
Pop(&obj->q1);
Push(&obj->q2, top);
}
Pop(&obj->q1);
}
else if (!isEmpty(&obj->q2))
{
while (Size(&obj->q2)>1)
{
top = Front(&obj->q2);
Pop(&obj->q2);
Push(&obj->q1, top);
}
Pop(&obj->q2);
}
return ret;
}
void myStackFree(MyStack* obj)
{
Destory(&obj->q1);
Destory(&obj->q2);
obj=NULL;
}
3.3设计循环队列
无论使用数组实现还是链表实现,都要多开一个空间。如果设计存k个数据的循环队列,就要开k+1个空间。否则无法实现判空和判满。
①数组实现

cpp
typedef struct
{
int* a;
int size;
int head;
int tail;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* cq=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
cq->a=(int*)malloc(sizeof(int)*(k+1));
cq->head=0;
cq->tail=0;
cq->size=k;
return cq;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return (obj->head==obj->tail);
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
if(obj->head==0 && obj->tail+obj->head==obj->size)
return true;
if(obj->tail<obj->head && obj->tail+1==obj->head)
return true;
return false;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
return false;
obj->tail++;
obj->tail=obj->tail%(obj->size+1);
obj->a[obj->tail]=value;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return false;
obj->head++;
obj->head=obj->head%(obj->size+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return -1;
int index=(obj->head+1);
if(index>obj->size)
index=0;
return obj->a[index];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return -1;
int index=obj->tail;
return obj->a[index];
}
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->a);
free(obj);
}
②链表实现

cpp
struct QueueNode
{
int val;
struct QueueNode* next;
};
typedef struct
{
struct QueueNode* head;
struct QueueNode* tail;
} MyCircularQueue;
struct QueueNode* BuyNode(int x)
{
struct QueueNode* newnode = (struct QueueNode*)malloc(sizeof(struct QueueNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->val = x;
newnode->next = NULL;
return newnode;
}
//构造器,设置队列长度为 k
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
int i = 0;
cq->head = BuyNode(0);
cq->tail = cq->head;
struct QueueNode* cur = cq->head;
for (i = 0;i < k;i++)
{
struct QueueNode* newnode = BuyNode(0);
cur->next = newnode;
cur = cur->next;
}
cur->next = cq->head;
return cq;
}
//检查循环队列是否为空。
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->head==obj->tail;
}
// 检查循环队列是否已满。
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return ((obj->tail)->next == obj->head);
}
//向循环队列插入一个元素。如果成功插入则返回真。
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if (myCircularQueueIsFull(obj))
return false;
//尾插
obj->tail = obj->tail->next;
(obj->tail)->val = value;
return true;
}
//从循环队列中删除一个元素。如果成功删除则返回真。
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if (myCircularQueueIsEmpty(obj))
return false;
//头删
obj->head = obj->head->next;
return true;
}
//从队首获取元素。如果队列为空,返回 -1
int myCircularQueueFront(MyCircularQueue* obj)
{
if (myCircularQueueIsEmpty(obj))
return -1;
return (obj->head->next)->val;
}
//获取队尾元素。如果队列为空,返回 -1 。
int myCircularQueueRear(MyCircularQueue* obj)
{
if (myCircularQueueIsEmpty(obj))
return -1;
return (obj->tail)->val;
}
//释放队列内存
void myCircularQueueFree(MyCircularQueue* obj)
{
struct QueueNode* cur = obj->head;
cur = cur->next;
while (cur != obj->head)
{
struct QueueNode* nxt = cur->next;
free(cur);
cur = nxt;
}
}