数据结构-栈和队列


 

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值