- 栈:一种特殊的线性表。只允许在固定的一端进行插入和删除元素的操作。插入和删除的一端叫做栈顶,LIFO(Last In First Out)的原则。栈中的数据遵循后进先后LIFO(Last In First Out)的原则。
- 压栈:栈的插入操作叫做压栈/入栈/进栈,入数据在栈顶。
- 出栈:栈的删除操作叫做出栈,出数据也在栈顶。
头文件->Stack.h
// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
//typedef int STDataType;
//#define N 10
//typedef struct Stack
//{
//STDataType _a[N];
//int _top; // 栈顶
//}Stack;
#ifndef STACK_H_
#define STACK_H_
#include
#include
#include
#include
typedef int STDataType;
typedef struct Stack
{
STDataType *p;
int top; //栈顶
int Capacity; //容量
} ST;
void StackInit(ST *st); //初始化栈
void StackDestory(ST *st); //销毁栈
void StackPush(ST *st, STDataType x); //压栈
void StackPop(ST *st); //出栈
bool StackEmpty(ST *st); //判断栈是否为空
int StackSize(ST *st); //栈中变量的数量
STDataType StackTop(ST *st); //栈顶的值
#endif
第一个接口:StackInit->初始化
void StackInit(ST *st)
{
st->p = NULL;
st->top = 0;
st->Capacity = 0;
}
第二个接口StackDestory:释放栈->释放开辟的空间,将容量和栈顶置为0
void StackDestory(ST *st)
{
assert(st);
free(st->p);
st->p = NULL;
st->top = 0;
st->Capacity = 0;
}
第三个接口StackPush:扩容并且入栈
void StackPush(ST *st, STDataType x)
{
assert(st);
//扩容
if (st->Capacity == st->top)
{
//初始化中容量为0这里要判断一下
int newCapacity = st->Capacity == 0 ? 2 : st->Capacity * 2;
//开辟动态空间
st->p = (STDataType *)realloc(st->p, sizeof(STDataType) * newCapacity);
//判断堆区是否已满
if (st->p == NULL)
{
printf("realloc fail!!!\n");
exit(EXIT_FAILURE);
}
//更新容量
st->Capacity = newCapacity;
}
//在栈顶插入数据
st->p[st->top] = x;
++st->top;
}
第四个接口StackPop:出栈
void StackPop(ST *st)
{
assert(st);
//当栈没有变量时,继续出栈会导致越界
assert(st->top > 0);
--st->top;
}
第五个接口StackEmpty:判断栈释放为空
bool StackEmpty(ST *st)
{
assert(st);
//如果top为0则返回true,反之false
return st->top == 0;
}
第六个接口StackSize:栈中有效数据的数量
int StackSize(ST *st)
{
assert(st);
return st->top;
}
最后一个接口:StackTop->取栈顶的数据
STDataType StackTop(ST *st)
{
assert(st);
//数组下标从0开始,所以需要减一
return st->p[st->top - 1];
}
Stack.h
#ifndef STACK_H_
#define STACK_H_
#include
#include
#include
#include
//在数据结构中栈是一种特殊的顺序表
//在操作系统中栈是虚拟进程中的内存分布
typedef int STDataType;
typedef struct Stack
{
STDataType *p;
int top; //栈顶
int Capacity; //容量
} ST;
void StackInit(ST *st); //初始化栈
void StackDestory(ST *st); //销毁栈
void StackPush(ST *st, STDataType x); //压栈
void StackPop(ST *st); //出栈
bool StackEmpty(ST *st); //判断栈是否为空
int StackSize(ST *st); //栈中变量的数量
STDataType StackTop(ST *st); //栈顶的值
#endif
Stack.c
#include "Stack.h"
void StackInit(ST *st)
{
st->p = NULL;
st->top = 0;
st->Capacity = 0;
}
void StackDestory(ST *st)
{
assert(st);
free(st->p);
st->p = NULL;
st->top = 0;
st->Capacity = 0;
}
void StackPush(ST *st, STDataType x)
{
assert(st);
//扩容
if (st->Capacity == st->top)
{
int newCapacity = st->Capacity == 0 ? 2 : st->Capacity * 2;
st->p = (STDataType *)realloc(st->p, sizeof(STDataType) * newCapacity);
if (st->p == NULL)
{
printf("realloc fail!!!\n");
exit(EXIT_FAILURE);
}
st->Capacity = newCapacity;
}
//在栈顶插入数据
st->p[st->top] = x;
++st->top;
}
void StackPop(ST *st)
{
assert(st);
//当栈没有变量时,继续出栈会导致越界
assert(st->top > 0);
--st->top;
}
bool StackEmpty(ST *st)
{
assert(st);
//如果top为0则返回true,反之false
return st->top == 0;
}
int StackSize(ST *st)
{
assert(st);
return st->top;
}
STDataType StackTop(ST *st)
{
assert(st);
return st->p[st->top - 1];
}
Test.c
#include "Stack.h"
int main()
{
ST s;
//初始化栈
StackInit(&s);
//压栈
StackPush(&s, 1);
StackPush(&s, 2);
//出栈
StackPop(&s);
StackPush(&s, 3);
StackPush(&s, 4);
StackPush(&s, 5);
StackPush(&s, 6);
//出栈
StackPop(&s);
StackPop(&s);
while (!StackEmpty(&s)) //判断栈是否为空
{
printf("%d ", StackTop(&s)); //打印栈顶的数据
StackPop(&s); //出栈
}
printf("\n");
//释放栈
StackDestory(&s);
system("pause");
return 0;
}
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void StackInit(ST* ps);
void StackDestory(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);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void StackDestory(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ps->a = (STDataType*)realloc(ps->a, newCapacity* sizeof(STDataType));
if (ps->a == NULL)
{
printf("realloc fail\n");
exit(-1);
}
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);
return ps->top == 0;
}
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 isValid(char * s)
{
ST st;
StackInit(&st);
while(*s)
{
if(*s == '(' || *s == '{' || *s == '[')
{
//左括号入栈
StackPush(&st, *s);
//更新s
++s;
}
else
{
//如果只有一个右括号,会导致访问空指针,导致崩溃
if(StackEmpty(&st))
return false;
//左括号出栈与右括号匹配
char top = StackTop(&st); //取栈顶值
StackPop(&st);
if(*s == ')' && top == '('
|| *s == '}' && top == '{'
|| *s == ']' && top == '[')
{
//如果匹配则继续比较
++s;
}
else
{
return false;
}
}
}
//如果栈为空,则所有括号匹配<->不为空则没有完全匹配
bool ret = StackEmpty(&st);
StackDestory(&st);
return ret;
}
- 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
FIFO(First In First Out) ->跟排队一样- 入队列:进行插入操作的一端称为"队尾 "
- 出队列:进行删除操作的一端称为"队头"
- 队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数
组头上出数据,需要挪动数据,效率会比较低。
头文件:Queue.h
#ifndef QUEUE_H_
#define QUEUE_H_
#include
#include
#include
#include
//链式队列->队列节点里面包含队列头和尾
typedef int QDataType;
//入队数据
typedef struct QueueNode
{
QDataType val; //数据域
struct QueueNode *next; //指针域
} QNode;
//队列结构
typedef struct Queue
{
QNode *head; //头节点->队列头
QNode *tail; //尾结点->队列尾
} Queue;
void QueueInit(Queue *q); //初始化
void QueueDestory(Queue *q); //释放队列
void QueuePush(Queue *q, QDataType x); //数据入队列(从队尾进入)
void QueuePop(Queue *q);
bool QueueEmpty(Queue *q); //判断队列是否为空
size_t QueueSize(Queue *q); //队列长度
QDataType QueueFront(Queue *q); //队头数据
QDataType QueueBack(Queue *q); //队尾数据
#endif
第一个接口QueueInit:初始化队列
void QueueInit(Queue *q)
{
assert(q);
q->head = NULL;
q->tail = NULL;
}
第二个接口QueueDestory:释放队列
void QueueDestory(Queue *q)
{
assert(q);
QNode *cur = q->head;
while (cur)
{
QNode *next = cur->next;
free(cur);
cur = next;
}
q->head = q->tail = NULL;
}
第三个接口QueuePush:入队列
void QueuePush(Queue *q, QDataType x)
{
assert(q);
//开辟新节点
QNode *newnode = (QNode *)malloc(sizeof(QNode));
//判空
if (newnode == NULL)
{
printf("malloc fail!!!\n");
exit(EXIT_FAILURE);
}
else
{
newnode->val = x;
newnode->next = NULL;
}
//入队列
//如果队头和队尾都为NULL,则它们同时指向头节点
if (q->head == NULL && q->tail == NULL)
{
q->head = newnode;
q->tail = newnode;
}
else
{
q->tail->next = newnode;
//更新队尾
q->tail = newnode;
}
}
第四个接口QueuePop:出队列
void QueuePop(Queue *q)
{
assert(q);
//队列没有数据时,不能删除
assert(q->head != NULL);
//出队列(从队头出)
if (q->head->next == NULL)
{
//当只有一个节点时,头被释放,tail还是指向原来的头节点,这将导致不确定性
free(q->head);
q->tail = q->head = NULL;
}
else
{
QNode *next = q->head->next;
free(q->head);
q->head = next;
}
}
第五个接口QueueEmpty:判断队列是否为NULL
bool QueueEmpty(Queue* pq)
{
assert(pq);
//return pq->head == NULL && pq->tail == NULL;
return pq->head == NULL;
}
第六个接口QueueSize:队列的长度
size_t QueueSize(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
size_t size = 0;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
第七个接口QueueFront:队头数据
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->data;
}
最后一个接口QueueBack:队尾数据
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->tail);
return pq->tail->data;
}
Queue.h
#ifndef QUEUE_H_
#define QUEUE_H_
#include
#include
#include
#include
//链式队列->队列节点里面包含队列头和尾
typedef int QDataType;
typedef struct QueueNode
{
QDataType val; //数据域
struct QueueNode *next; //指针域
} QNode;
typedef struct Queue
{
QNode *head; //头节点->队列头
QNode *tail; //尾结点->队列尾
} Queue;
void QueueInit(Queue *q); //初始化
void QueueDestory(Queue *q); //释放队列
void QueuePush(Queue *q, QDataType x); //数据入队列(从队尾进入)
void QueuePop(Queue *q);
bool QueueEmpty(Queue *q); //判断队列是否为空
size_t QueueSize(Queue *q); //队列长度
QDataType QueueFront(Queue *q); //队头数据
QDataType QueueBack(Queue *q); //队尾数据
#endif
Queue.c
#include "Queue.h"
void QueueInit(Queue *q)
{
assert(q);
q->head = q->tail = NULL;
}
void QueueDestory(Queue *q)
{
assert(q);
QNode *cur = q->head;
while (cur)
{
QNode *next = cur->next;
free(cur);
cur = next;
}
q->head = q->tail = NULL;
}
void QueuePush(Queue *q, QDataType x)
{
assert(q);
//开辟新节点
QNode *newnode = (QNode *)malloc(sizeof(QNode));
//判空
if (newnode == NULL)
{
printf("malloc fail!!!\n");
exit(EXIT_FAILURE);
}
else
{
newnode->val = x;
newnode->next = NULL;
}
//入队列
//如果队头和队尾都为NULL,则它们同时指向头节点
if (q->head == NULL && q->tail == NULL)
{
q->head = newnode;
q->tail = newnode;
}
else
{
q->tail->next = newnode;
//更新队尾
q->tail = newnode;
}
}
void QueuePop(Queue *q)
{
assert(q);
assert(q->head != NULL);
//出队列(从队头出)
if (q->head->next == NULL)
{
//当只有一个节点时,头被释放,tail还是指向原来的头节点,这将导致不确定性
free(q->head);
q->tail = q->head = NULL;
}
else
{
QNode *next = q->head->next;
free(q->head);
q->head = next;
}
}
bool QueueEmpty(Queue *q)
{
assert(q);
return q->head == NULL;
}
size_t QueueSize(Queue *q)
{
assert(q);
assert(q->head);
QNode *cur = q->head;
size_t Size = 0;
while (cur)
{
++Size;
cur = cur->next;
}
return Size;
}
QDataType QueueFront(Queue *q)
{
assert(q);
assert(q->head);
return q->head->val;
}
QDataType QueueBack(Queue *q)
{
assert(q);
assert(q->tail);
return q->tail->val;
}
Test.c
#include "Queue.h"
//测试
int main()
{
Queue q;
//初始化队列
QueueInit(&q);
//入队列
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
QueuePush(&q, 6);
//显示队列数据
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
//出队列
QueuePop(&q);
}
printf("\n");
Queue p;
//初始化队列
QueueInit(&p);
//入队列
QueuePush(&p, 1);
QueuePush(&p, 2);
QueuePush(&p, 3);
QueuePush(&p, 4);
QueuePush(&p, 5);
QueuePush(&p, 6);
//出队列
QueuePop(&p);
QueuePop(&p);
//显示队列数据
while (!QueueEmpty(&p))
{
printf("%d ", QueueFront(&p));
//出队列
QueuePop(&p);
}
printf("\n");
system("pause");
return 0;
}
- 用队列实现栈。(OJ链接)
思想:使用二个队列来进行实现
用C实现,造轮子我省略了…
MyStack* myStackCreate()
{
//动态开辟空间
MyStack* st = (MyStack*)malloc(sizeof(MyStack));
//初始化结构体
QueueInit(&st->q1);
QueueInit(&st->q2);
return st;
}
void myStackPush(MyStack* obj, int x)
{
Queue* nonEmpty = &obj->q1; //非空队列
Queue* Empty = &obj->q2; //空队列
if(!QueueEmpty(nonEmpty))
{
QueuePush(nonEmpty, x);
}
else
{
QueuePush(Empty, x);
}
}
int myStackPop(MyStack* obj)
{
Queue* nonEmpty = &obj->q1; //非空队列
Queue* Empty = &obj->q2; //空队列
//判断非空和空队列
if(!QueueEmpty(Empty))
{
nonEmpty = &obj->q2;
Empty = &obj->q1;
}
//把非空队列的N-1个数据压入到空队列中
while(QueueSize(nonEmpty) > 1)
{
QueuePush(Empty, QueueFront(nonEmpty));
//非空队列出数据
QueuePop(nonEmpty);
}
//返回非空队列的队头
int top = QueueFront(nonEmpty);
QueuePop(nonEmpty);
return top;
}
int myStackTop(MyStack* obj)
{
Queue* nonEmpty = &obj->q1; //非空队列
Queue* Empty = &obj->q2; //空队列
if(!QueueEmpty(nonEmpty))
{
//返回队尾
return QueueBack(nonEmpty);
}
else
{
return QueueBack(Empty);
}
}
bool myStackEmpty(MyStack* obj)
{
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj)
{
//这里不能直接释放obj,会导致内存泄漏
QueueDestory(&obj->q1);
QueueDestory(&obj->q2);
free(obj);
}
- 用栈实现队列。(OJ链接)
思想:二个栈来进行实现
这里也是用C实现,也省略了造轮子…
//二个栈实现队列
typedef struct
{
ST st1;
ST st2;
} MyQueue;
MyQueue* myQueueCreate()
{
MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
//初始化结构体
StackInit(&q->st1);
StackInit(&q->st2);
return q;
}
void myQueuePush(MyQueue* obj, int x)
{
//入栈
StackPush(&obj->st1, x);
}
int myQueuePop(MyQueue* obj)
{
//将第一个栈的数据导入第二个栈中
if(StackEmpty(&obj->st2))
{
while(StackSize(&obj->st1))
{
StackPush(&obj->st2, StackTop(&obj->st1));
StackPop(&obj->st1); //导一个出一个
}
}
//取第二个栈顶的数据
int top = StackTop(&obj->st2);
StackPop(&obj->st2); //出栈
return top;
}
int myQueuePeek(MyQueue* obj)
{
if(StackEmpty(&obj->st2))
{
while(StackSize(&obj->st1))
{
StackPush(&obj->st2, StackTop(&obj->st1));
StackPop(&obj->st1); //导一个出一个
}
}
return StackTop(&obj->st2);
}
bool myQueueEmpty(MyQueue* obj)
{
return StackEmpty(&obj->st1) && StackEmpty(&obj->st2);
}
void myQueueFree(MyQueue* obj)
{
StackDestory(&obj->st1);
StackDestory(&obj->st2);
free(obj);
}
- 设计循环队列。(OJ链接)
//数组实现
typedef struct
{
int* p;
int head; //队头
int tail; //队尾
int k; //有效数据
} MyCircularQueue;
bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k)
{
//动态开辟结构体
MyCircularQueue* q = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
assert(q);
//开辟四个数组空间,多出一个用来判断满和空的情况
q->p = (int*)malloc(sizeof(int) * (k + 1));
q->head = 0;
q->tail = 0;
q->k = k;
return q;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
assert(obj);
//如果tail后面是head说明队列已经满了,不能入队
if(myCircularQueueIsFull(obj))
{
return false;
}
else
{
obj->p[obj->tail] = value;
//最后一个元素不存储数据
if(obj->tail == obj->k)
{
obj->tail = 0;
}
else
{
++obj->tail;
}
}
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
assert(obj);
//如果队头(head)等于队尾(tail)说明队列为空,不能删
if(myCircularQueueIsEmpty(obj))
{
return false;
}
else
{
//最后一个元素不存储数据
if(obj->head == obj->k)
{
obj->head = 0;
}
else
{
++obj->head;
}
}
return true;
}
int myCircularQueueFront(MyCircularQueue* obj)
{
assert(obj);
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
return obj->p[obj->head];
}
}
int myCircularQueueRear(MyCircularQueue* obj)
{
assert(obj);
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
//如果tail为0,则返回第k个数据,说明已经走完一遍
if(obj->tail == 0)
return obj->p[obj->k];
else
return obj->p[obj->tail - 1];
}
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
assert(obj);
return obj->head == obj->tail;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
assert(obj);
//如果队尾为k,并且队头为0说明,队列已满
if(obj->tail == obj->k && obj->head == 0)
{
return true;
}
else
{
return obj->tail + 1 == obj->head;
}
}
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->p);
free(obj);
}