C语言【数据结构】栈与队列实现

目录

一.栈具体实现

1.创建结构体

2.初始化栈

3.销毁栈

4.入栈

5.出栈

6.判断栈是否为空

7.计算栈中数据个数

8.栈顶数据

二.队列具体实现

1.创建结构体

2.初始化队列

3.销毁队列

4.入队列

5.出队列

6.判断队列是否为空

7.计算队列数据个数

8.队列头数据

9.队列尾数据

三.栈代码

1.Stack.h

2.Stack.c

3.Test.c

四.队列代码

1.Queue.h

2.Queue.c

3.Test.c

五.测试结果

1.栈

2.队列


前言:通过前面的顺序表,链表的学习,这里的栈和队列会很简单,用的都是上面两种数据结构。

所以这里就把栈和队列放在一起来说。

一.栈具体实现

这个栈是使用动态顺序表来实现的,相对于使用链表要更好一些,当然也可以使用链表。

1.创建结构体

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;//栈顶的位置
	int capacity;//容量
}ST;

动态顺序表标配,只是这里用top来代替size,top就相当于栈顶。

2.初始化栈

void StackInit(ST* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

也是顺序表正常操作。

3.销毁栈

void StackDestory(ST* ps)
{
	assert(ps);

	free(ps->a);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

与顺序表一样。

4.入栈

void StackPush(ST *ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		else
		{
			ps->a = tmp;
			ps->capacity = newCapacity;
		}
	}
	ps->a[ps->top] = x;
	++ps->top;
}

这里因为栈只能在后面进,所以这里只有尾插,并且判断是否扩容也直接写在该函数里了。

如果ps->top == ps->capacity的时候就说明需要再次开辟空间(即扩容),这时定义一个新的newCapacity,然后通过realloc去进行扩容。

最后再把数据插入进去,并且++ps->top。

5.出栈

void StackPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	--ps->top;
}

直接--ps->top即可。

6.判断栈是否为空

bool StackEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

判断ps->top == 0,如果为0,说明为空,返回1,如果不为0,说明不为空,返回0.

7.计算栈中数据个数

int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

ps->top的值即为数据个数

8.栈顶数据

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}

首先这个栈里要有数据,所以断言assert(ps->top > 0)

然后当前栈顶的数据就为ps->a[ps->top - 1],因为是数组,所以要-1。

二.队列具体实现

这个队列是使用链表来实现的,相对于使用顺序表要更好一些,当然也可以使用顺序表。

1.创建结构体

typedef int QDataType;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;

以单链表为基础来实现,因为队列只要尾插和头删,所以可以通过再定义一个结构体,来保存这个头和尾,以实现时间复杂度为O(1)的队列。

2.初始化队列

void QueueInit(Queue* pq)
{
	assert(pq);

	pq->head = NULL;
	pq->tail = NULL;
}

要把head和tail置NULL。

3.销毁队列

void QueueDestorty(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	
	pq->head = NULL;
	pq->tail = NULL;
}

循环链表,分别进行free,然后通过next找到下一个节点的地址,继续循环,最后再把定义的pq->head和pq->tail置NULL。

4.入队列

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

创建新节点,然后进行分情况讨论。

当链表中没有节点时,我们分为一种情况,就是当tail和head都为空时,我们让这个tail和head都等于这个新节点,然后head就一直为该节点当做头节点,然后tail根据尾插的节点个数进行移动。

5.出队列

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail);

	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

出队列,也要分为两种情况,一种是只剩一个head头节点时,另一种时正常情况多个节点时。

当只有一个头节点时,即pq->head->next = NULL,这时候我们直接free掉head,然后把这个head和tail都置NULL。

而正常情况,就创建一个next来保存头节点的下一个节点的地址,然后free掉头节点,并让原本头节点的下一个节点变成新的头节点。

6.判断队列是否为空

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

如果头节点为空,则说明为空。

7.计算队列数据个数

size_t QueueSize(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		++size;
		cur = cur->next;
	}

	return size;
}

遍历链表,每有一个节点,就++size,最后返回size的值。

8.队列头数据

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);

	return pq->head->data;
}

头节点的数据则为队列头数据。

9.队列尾数据

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);

	return pq->tail->data;
}

尾节点的数据则为尾节点数据。

三.栈代码

1.Stack.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

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);//栈顶数据

2.Stack.c

#include "Stack.h"

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->top = 0;
	ps->capacity = 0;
}


void StackPush(ST *ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		else
		{
			ps->a = tmp;
			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;
}

int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}

3.Test.c

#include "Stack.h"

void TestStack()
{
	ST st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);

	printf("%d ", StackTop(&st));
	StackPop(&st);

	StackPush(&st, 3);
	StackPush(&st, 4);
	StackPush(&st, 5);
	StackPush(&st, 6);
	StackPush(&st, 7);
	StackPush(&st, 8);



	while (!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}
	printf("\n");

	StackDestory(&st);
}

int main()
{
	TestStack();

	return 0;
}

四.队列代码

1.Queue.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

typedef int QDataType;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;

void QueueInit(Queue* pq);//初始化队列

void QueueDestory(Queue* pq);//销毁队列

void QueuePush(Queue* pq, QDataType x);//入队列

void QueuePop(Queue* pq);//出队列

bool QueueEmpty(Queue* pq);//判断队列是否为空

size_t QueueSize(Queue* pq);//队列数据个数

QDataType QueueFront(Queue* pq);//队列头数据

QDataType QueueBack(Queue* pq);//队列尾数据

2.Queue.c

#include "Queue.h"

void QueueInit(Queue* pq)
{
	assert(pq);

	pq->head = NULL;
	pq->tail = NULL;
}

void QueueDestorty(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	
	pq->head = NULL;
	pq->tail = NULL;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail);

	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

size_t QueueSize(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		++size;
		cur = cur->next;
	}

	return size;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);

	return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);

	return pq->tail->data;
}

3.Test.c

#include "Queue.h"

void TestQueue()
{
	Queue q;

	QueueInit(&q);

	QueuePush(&q, 1);
	QueuePush(&q, 2);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);

	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);
	QueuePush(&q, 6);
	QueuePush(&q, 7);
	QueuePush(&q, 8);
	QueuePush(&q, 9);

	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");
}

int main()
{
	TestQueue();

	return 0;
}

五.测试结果

1.栈

2.队列

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰果滴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值