文章目录
1. 栈、队列 介绍
1.1 栈
栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
1.2 队列
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
2. 栈 函数接口 及其 实现
2.1 栈的结构
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;//数组
size_t _top;//栈顶
size_t _capacity;//容量
}Stack;
2.2 函数接口
void StackInit(Stack* ps);// 初始化
void StackDestory(Stack* ps);// 销毁
void StackPush(Stack* ps, STDataType x);// 入栈
void StackPop(Stack* ps);// 删除栈顶元素
STDataType StackTop(Stack* ps);// 取栈顶元素
bool StackEmpty(Stack* ps);// 判栈空
size_t StackSize(Stack* ps);// 栈大小
void StackPrint(Stack* ps);// 打印出栈所有元素
2.3 接口实现
2.3.1 初始化
把指向数组的指针置空,此时数组中没有元素,栈顶下标是0,此时还没有动态开辟空间,所以栈的容量是0。
void StackInit(Stack* ps)
{
assert(ps);
ps->_a = NULL;
ps->_capacity = 0;
ps->_top = 0;
}
2.3.2 销毁
首先释放掉数组动态开辟的空间,然后再将指向数组的指针置空,栈顶下标和栈容量都置0。
void StackDestory(Stack* ps)// 销毁
{
assert(ps);
if (ps->_a != NULL)
{
free(ps->_a);
ps->_a = NULL;
ps->_top = 0;
ps->_capacity = 0;
}
}
2.3.3 入栈
首先判断栈的容量是否已满,栈满就扩容,再将新元素加入栈中。
void StackPush(Stack* ps, STDataType x)// 入栈
{
assert(ps);
if (ps->_capacity == ps->_top) // 栈满扩容
{
size_t newcapacity = ps->_capacity == 0 ? 2 : ps->_capacity * 2;// 扩充的新容量
ps->_a = (STDataType*)realloc(ps->_a, sizeof(STDataType)*newcapacity);// 数组申请的空间
ps->_capacity = newcapacity; // 修改容量
}
ps->_a[ps->_top] = x;// 新元素入栈
ps->_top++;
}
2.3.4 删除栈顶元素
栈中有栈顶下标,栈顶下标向下挪动一位,相当于栈中少了栈顶元素。
void StackPop(Stack* ps)// 删除栈顶元素
{
assert(ps&&ps->_top > 0);
--ps->_top;// 直接挪动下标即可
}
2.3.5 取栈顶元素
已知栈中元素的下标,直接按下标返回数组元素就是栈顶元素。
STDataType StackTop(Stack* ps)// 取栈顶元素
{
assert(ps&&ps->_top > 0);
return (ps->_a[ps->_top - 1]);
//return ps->_top - 1; // 这是错误的
//因为 ps->_top是下标,不是该下标代表的元素!!!
}
2.3.6 判栈空
根据栈顶下标判断栈中是否有元素,如果栈为空,则栈顶下标就为0。
bool StackEmpty(Stack* ps) // 判栈空
{
assert(ps);
return ps->_top==0;// 看下标是否为0
}
2.3.7 返回栈的大小
根据栈顶下标判断栈中有多少元素。
size_t StackSize(Stack* ps) // 栈大小
{
assert(ps);
return ps->_top; // 下标表示几个元素
}
2.3.8 打印栈
将栈顶下标当做循环条件,循环打印。
void StackPrint(Stack* ps)// 打印出栈所有元素
{
assert(ps&&ps->_top > 0);
while (ps->_top)
{
printf("%d ", ps->_top);
ps->_top--;
}
}
3. 队列 函数接口 及其 实现
3.1 队列的结构
typedef int QUDataType;
typedef struct QueueNode
{ // 队列中一个元素的结构
struct QueueNode* _next; // 指针域
QUDataType _data; // 数据域
}QueueNode;
typedef struct Queue
{ // 队列的两个指针
QueueNode* _front; // 队头
QueueNode* _tail; // 队尾
}Queue;
3.2 函数接口
void QueueInit(Queue* pq);//初始化
void QueueDestory(Queue* pq);//销毁
QueueNode* BuyQueueNode(QUDataType x);//建立新结点
void QueuePush(Queue* pq, QUDataType x);//入队列
void QueuePop(Queue* pq);//按顺序删除
QUDataType QueueFront(Queue* pq);//返回头结点的值
QUDataType QueueBack(Queue* pq);//返回尾结点的值
bool QueueEmpty(Queue* pq);//判队列是否为空
int QueueSize(Queue* pq);//队列大小
void QueuePrint(Queue* pq);//打印队列
3.3 接口实现
3.3.1 初始化
此时队列中没有元素,队列的两个指针置空。
void QueueInit(Queue* pq)//初始化
{
assert(pq);
pq->_front = NULL;
pq->_tail = NULL;
}
3.3.2 销毁
循环释放掉队列中的元素,并且将指针置空。
void QueueDestory(Queue* pq)//销毁
{
assert(pq);
QueueNode* cur = pq->_front;
while (cur)
{
QueueNode* next = cur->_next;
free(cur);
cur = next;
}
pq->_front = NULL;
pq->_tail = NULL;
}
3.3.3 建立新结点
动态开辟一个结点空间,数据域和指针域分别初始化。
QueueNode* BuyQueueNode(QUDataType x)//建立新结点
{
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
newnode->_data = x;
newnode->_next = NULL;
return newnode;
}
3.3.4 入队列
分两种情况,第一种是队列中原本没有元素,直接将新结点入队列;第二种是队列中原本有元素,在队尾插入新结点。
void QueuePush(Queue* pq, QUDataType x)//入队列
{
assert(pq);
QueueNode* newnode = BuyQueueNode(x);
if (pq->_tail == NULL)
{ // 新结点入空队列
pq->_front = pq->_tail = newnode;
}
else
{ // 新结点入有结点队列
pq->_tail->_next = newnode;
pq->_tail = newnode;
}
}
3.3.5 按顺序删除
等同于删除队头元素,用一个指针标记第二个元素,删掉队头元素,最后将头指针指向第二个元素。
void QueuePop(Queue* pq)//按顺序删除
{
assert(pq&&pq->_front != NULL);
QueueNode* next = pq->_front->_next;
free(pq->_front);
pq->_front = next;
if (pq->_front == NULL)
{
pq->_tail = NULL;
}
}
3.3.6 返回头结点的值
当队列不为空时,直接返回队头指针指向的结点的值。
QUDataType QueueFront(Queue* pq)//返回头结点的值
{
assert(pq&&pq->_front != NULL);
return pq->_front->_data;
}
3.3.7 返回尾结点的值
当队列不为空时,直接返回队尾指针指向的结点的值。
QUDataType QueueBack(Queue* pq)//返回尾结点的值
{
assert(pq&&pq->_tail != NULL);
return pq->_tail->_data;
}
3.3.8 判断队列是否为空
直接判断队头指针是否指向空,指向空,队列就为空。
bool QueueEmpty(Queue* pq)//判队列是否为空
{
assert(pq);
return pq->_front == NULL;
}
3.3.9 返回队列大小
定义一个指针,该指针循环遍历整个队列,定义一个计数器,记录循环的次数,即为队列元素个数。
int QueueSize(Queue* pq)//队列大小
{
assert(pq);
size_t count = 0;
QueueNode* cur = pq->_front;
while (cur != NULL)
{
count++;
cur = cur->_next;
}
return count;
}
3.3.10 打印队列
定义一个指针,循环遍历整个队列,依次打印。
void QueuePrint(Queue* pq)//打印队列
{
assert(pq);
if (pq->_front == pq->_tail)
{
printf("<==NULL\n");
return 0;
}
QueueNode* cur = pq->_front;
while (cur != pq->_tail)
{
printf("<==%d", cur->_data);
cur = cur->_next;
}
printf("<==%d<==\n", cur->_data);
}