栈和队列
栈
**栈:**一种特殊的数据结构,其只允许在固定的一段进行插入和删除元素的操作。进行数据插入和删除的一端叫栈顶,另一端叫栈底。栈中元素遵循后进先出的原则
栈在逻辑上是线性的 ,物理 结构上也是线性的,属于线性表的一种
压栈:栈的插入数据操作叫做压栈,进栈,入栈,从栈顶进入
出栈:栈删除数据操作叫做出栈,从栈顶出
栈一般可以由数组和链表实现,相对而言,选用数组会比使用链表的代价小
选用数组来实现栈:
选择用双向链表来实现栈:相比较单链表,双向链表多出一个指针,在不同的操作系统下,指针的大小是不同的,32位:4字节,64位:8字节,而这些空间的消耗其实是没必要的。
选用单链表实现栈:相比于双向链表,单链表节省了的空间,但是,用单链表实现栈,在每次插入或者删除数据时,都需要进行内存的申请与释放操作,频繁的申请空间释放空间是会降低程序的效率的。
选用数组实现栈:用数组实现栈既解决了双向链表不必要的空间消耗问题也解决了频繁申请与释放空间的问题,虽然数组存在性能的消耗,但是相比较另外两种实现方式,这是最优的选择。
栈里面的数据不能被遍历也不能被随机访问,这是由栈的特性决定的(后进先出,只能在一端进行插入与删除操作)
栈的实现
首先,创建两个文件,一个是Stack.c文件,用来实现函数,一个是Stack.h文件,这里存放对应的头文件、栈的定义与函数的定义。
栈的定义
c
typedef int STDataType;//当后面需求变更时,只需要修改int就行,比如要存储字符型,只需要把Int改成char就行。
typedef struct Stack
{
STDataType* arr;
int capacity;//栈空间的大小
int top;//栈顶
}ST;
栈的初始化
c
//.h文件下
void StackInit(ST*ps);//初始化栈
c
//.c文件下
void StackInit(ST* ps)//初始化栈
{
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
栈的销毁
c
//.h文件下
void StackDestroy(ST*ps);//栈的销毁
c
//.c文件下
void StackDestroy(ST* ps)//栈的销毁
{
assert(ps);
if (ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
入栈
c
//.h
void StackPush(ST*ps,STDataType x);//入栈
c
void StackPush(ST* ps, STDataType x)//入栈
{
assert(ps);
if (ps->capacity==ps->top)//空间不足
{//当空间大小与有效数据个数相同时表示栈空间用完了
int newnode = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDataType* tmp = (STDataType*)realloc(ps->arr,newnode*sizeof(STDataType));
assert(tmp);
ps->arr = tmp;
ps->capacity = newnode;
}
ps->arr[ps->top++] = x;
}
出栈
c
//.h
bool StackEmpty(ST*ps);//判断栈是否位空]
void StackPop(ST*ps);//出栈
c
//.c
bool StackEmpty(ST* ps)//判断栈是否位空
{
assert(ps);
return ps->top == 0;
}
void StackPop(ST* ps)//出栈
{
assert(ps);
assert(!StackEmpty(ps));//判断栈是否为空
--ps->top;
}
获取栈顶元素与栈中有效元素个数
c
//.h
STDataType StackTop(ST*ps);//获取栈顶元素
STDataType STSize(ST*ps);//获取有效元素个数
c
//.h
STDataType StackTop(ST* ps)//获取栈顶元素
{
assert(ps);
assert(!StackEmpty(ps));
return ps->arr[ps->top-1];
}
STDataType STSize(ST* ps)//获取有效元素个数
{
assert(ps);
return ps->top;
}
完整代码
c
//.h文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* arr;
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);//获取栈顶元素
STDataType STSize(ST*ps);//获取有效元素个数
c
//.c文件
#include"Stack.h"
void StackInit(ST* ps)//初始化栈
{
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
void StackDestroy(ST* ps)//栈的销毁
{
assert(ps);
if (ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
void StackPush(ST* ps, STDataType x)//入栈
{
assert(ps);
if (ps->capacity==ps->top)//空间不足
{
int newnode = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDataType* tmp = (STDataType*)realloc(ps->arr,newnode*sizeof(STDataType));
assert(tmp);
ps->arr = tmp;
ps->capacity = newnode;
}
ps->arr[ps->top++] = x;
}
void StackPop(ST* ps)//出栈
{
assert(ps);
assert(!StackEmpty(ps));
--ps->top;
}
bool StackEmpty(ST* ps)//判断栈是否位空
{
assert(ps);
return ps->top == 0;
}
STDataType StackTop(ST* ps)//获取栈顶元素
{
assert(ps);
assert(!StackEmpty(ps));
return ps->arr[ps->top-1];
}
STDataType STSize(ST* ps)//获取有效元素个数
{
assert(ps);
return ps->top;
}
队列
队列:只允许在一段进行插入数据,在另一端进行插入数据的特殊线性表,队列,先进先出
底层由链表来实现,虽然数=数组也可以,但是数组效率低。完整代码如下:
c
.c
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QueueNode//队列节点
{
QDataType data;
struct QueueNode* next;
}QueueNode;
typedef struct Queue
{
QueueNode* phead;
QueueNode* ptail;
int size;//节点个数
}Queue;
void QueueInit(Queue*pq);//队列初始化
void QueuePush(Queue*pq,QDataType x);//队列插入数据
bool QueueEmpty(Queue*pq);//判断队列是否为空
void QueuePop(Queue*pq);//删除队列数据
QDataType QueueFront(QueueNode*pq);//取对头数据
QDataType QueueAfter(Queue* pq);//取队尾数据
int QueueSize(Queue*pq);//取有效数据个数
void QueueDestroy(Queue*pq);//队列的销毁
c
.c
#include"Queue.h"
void QueueInit(Queue* pq)//队列初始化
{
assert(pq);
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)//队列插入数据
{
assert(pq);
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
if (pq->phead==NULL)//队列为空
{
pq->phead = pq->ptail = newnode;
}
else//队列不为空
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
bool QueueEmpty(Queue* pq)//判断队列是否为空
{
assert(pq);
return pq->phead == NULL;
}
void QueuePop(Queue* pq)//删除队列数据
{
assert(pq);
assert(!QueueEmpty(&pq));
if (pq->phead==pq->ptail)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QueueNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
--pq->size;
}
QDataType QueueFront(Queue* pq)//取队头数据
{
assert(pq);
assert(!QueueEmpty(&pq));
return pq->phead->data;
}
QDataType QueueAfter(Queue* pq)//取队尾数据
{
assert(pq);
assert(!QueueEmpty(&pq));
return pq->ptail->data;
}
int QueueSize(Queue* pq)//取有效数据个数
{
assert(pq);
return pq->size;
}
void QueueDestroy(Queue* pq)//队列的销毁
{
assert(pq);
assert(!QueueEmpty(&pq));
QueueNode* pcur = pq->phead;
while (pcur)
{
QueueNode* next = pcur->next;
free(pcur);
pcur = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}