C语言实现栈, 队列

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈:栈的删除操作叫做出栈。出数据也在栈顶

后进先出

typedef int STDataType;
typedef struct Stack
{
    STDataType* a;	// 存储数据的空间
    int top;		// 栈中已存储元素个数, 总是指向栈位, 取栈顶元素时, 假设共有3元素, 即a[2] --- a[top - 1]
    int capacity;	// 栈总内存大小(最大可存储的元素个数)
}ST;

常见函数接口实现

// 初始化栈
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
    pst->top = 0;
    pst->capacity = 0;
}

// 判断栈中是否还有元素
bool STEmpty(ST* pst)
{
    return pst->top == 0;
}

// 压栈, 向栈中存数据
void STPush(ST* pst, STDatatype x)
{
    assert(pst);	// 判断指针不是NULL
    if(pst->top == pst->capacity)	// 先判断栈是否空间已满, 已满则重新开辟空间
    {
        int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
        // 有可能第一次开辟空间, 第一次开辟空间固定给4, 直接使用pst->capacity * 2得到的还是0, 所以特殊处理
        pst->tem = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
        if(tem == NULL)
        {
            perror("realloc fail");
            return;
        }
		pst->a = tem;	// 指向新的空间
        pst->capacity = newcapacity;	// 更新总空间大小
    }
}

// 出栈, 出数据
void STPop(ST* pst)
{
    assert(pst);	// 判断指针不是NULL
    assert(!STEmpty(pst));	// 栈内还有元素
    pst->top--;
    // 伪删除, 因为我们只能通过top取栈顶元素, 只要top--, 那么需要删除的数据就不会再被访问了, 相当于被删除了
}

// 销毁栈, 栈使用完之后, 需要将空间释放, 否则会造成空间泄露
void STDestroy(ST* pst)
{
    pst->a = pst->capacity = 0;
    free(pst->a);
    pst->a = NULL;
}

// 获取栈顶数据
STDataType STTop(ST* pst)
{
    assert(pst);
    assert(!STEmpty)
    return pst->a[pst->top - 1];
}

// 获取栈的已存储数据的数量
int STStize(ST* pst)
{
    assert(pst);
    return pst->top;
}

队列

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

先进先出

队列:结构体实现

typedef int QDataType;
typedef struce QueueNode	// 队列的节点
{
    struct QueueNode* next;
    QDataType data;
}QNode;

struct Queue	// 队列
{
    QNode* phead;	// 队头节点
    QNode* tail;	// 队尾节点
    int size;		// 队列的长度
};

常见函数接口实现

// 队列的初始化
void QueueInit(Queue* pq)
{
    assert(pq);
    pq->phead = NULL;
    pq->tail = NULL;
    pq->size = 0;
}

// 队列的销毁, 使用完队列之后, 需要将空间释放还给操作系统, 一面造成内存泄漏
void QueueDestroy(Queue* pq)
{
    assert(pq);	// 确保队列合法
    Qnode* cur = pq->phead;
    while(cur)
    {
        Qnode* next = cur->next;	// 这里需要先记录下一个节点, 如果先执行free, 那么下一个节点就找不到了
        free(cur);
        cur = next;
    }
    pq->phead = pq->tail = NULL;
    pq->size = 0;
}

// 入队
void QueuePuhs(Queue* pq, QDataType x)
{
    assert(pq);
    QNode* newnode = (QNode*)malloc(sizeof(QNode));	// 先创建出新节点
    if(newnode == NULL)
    {
        perror("malloc fail\n");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;	// 完成新节点的数据初始化
    if(pq->tail == NULL)	// 如果队列在插入之前为空, 那么就需要将头尾指针都改变
    {
        assert(pq->phead == NULL);
        pq->phead = pq->tail = newnode;
    }
    else
    {
        pq->tail->next = newnode;	// 队列插入之前不为空, 只需要改变尾指针
	    qp->tail = newnode;
    }
    pq->size++;	// 队列长度增加
}

// 判断队列是否为空
bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->size == 0;
}

// 出队
void QueuePop(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));
    if(pq->phead->next == NULL)	// 判断列表是否只有这一个数据, 如果只有这一个数据, 那么同样需要同时改变头尾指针
    {
        free(pq->next);
        pq->phead = pq->tail = NULL;
    }
    else
    {
        QNode* 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;
}

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值