【数据结构】使用C语言实现的栈和队列

一、栈

        1.1栈(Stack)的实现

        1.2栈的特点

二、队列

        2.1队列(Queue)的实现

        2.2队列的特点


一、栈

在数据结构中,栈(Stack)是一种特殊的线性数据结构,它遵循先进后出(Last In, First Out,LIFO)的原则。栈可以看作是一摞盘子或者一组装有圆柱体的容器,只能从容器的顶部进行插入和移除操作。

栈只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。

栈有两个基本操作:

入栈(Push):将元素添加到栈的顶部,也称为压栈或推入栈。
出栈(Pop):从栈的顶部移除元素,也称为弹栈或弹出栈。栈的删除操作叫做出栈。出数据也在栈顶

除了这两个基本操作外,栈还可以支持其他操作,如查看栈顶元素(Top)和判断栈是否为空(Empty)。


1.1栈(Stack)的实现

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

void StackInit(Stack* ps)初始化栈的函数。接收一个指向栈结构的指针作为参数。函数内部将栈的成员变量(元素数组、容量和栈顶位置)进行初始化。

// 初始化栈
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void StackPush(Stack* ps, STDataType x):入栈操作的函数。接收一个指向栈结构的指针和要插入的元素作为参数。函数首先判断栈是否已满,如果已满则通过realloc函数动态扩容,然后将元素插入栈顶。

// 入栈
void StackPush(Stack* ps, STDataType x)
{
	assert(ps);
	if (ps->capacity == ps->top)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType)*newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top++] = x;
}

void StackPop(Stack* ps):出栈操作的函数。接收一个指向栈结构的指针作为参数。函数首先判断栈是否为空,如果不为空则将栈顶元素移除。

// 出栈
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}

STDataType StackTop(Stack* ps):获取栈顶元素的函数。接收一个指向栈结构的指针作为参数。函数首先判断栈是否为空,如果不为空则返回栈顶元素的值。

// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}

int StackSize(Stack* ps):获取栈中有效元素个数的函数。接收一个指向栈结构的指针作为参数。函数返回栈的top成员变量的值,即栈中元素的个数。

// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;
}

bool StackEmpty(Stack* ps):检测栈是否为空的函数。接收一个指向栈结构的指针作为参数。函数返回栈的top成员变量是否等于0的结果,如果等于0表示栈为空,返回true;否则返回false。

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}

void StackDestroy(Stack* ps):销毁栈的函数。接收一个指向栈结构的指针作为参数。函数首先释放栈的元素数组所占用的内存,然后将栈的成员变量恢复到初始状态。

// 销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

这段代码实现了一个动态扩容的栈,可以方便地进行入栈、出栈、获取栈顶元素等操作,并且具备栈空判断和销毁栈的功能。


1.2栈的特点

  • 元素的插入和删除只能在栈的顶部进行,即后进先出的顺序。
  • 栈没有指定大小,可以动态调整容量。
  • 栈的插入和删除操作的时间复杂度都是O(1),即常数时间。

栈的应用场景广泛,例如:

        函数调用:函数调用时会使用栈来存储局部变量、返回地址等信息。
        表达式求值:通过栈可以实现中缀表达式转后缀表达式,并计算其值。
        浏览器的后退和前进功能:浏览器的历史记录可以通过栈来管理。
        括号匹配:通过栈可以检查表达式中的括号是否匹配。

总之,栈是一种简单而强大的数据结构,在很多计算机科学问题中都有广泛的应用。


二、队列

 队列是一种常见的数据结构,它遵循先进先出(FIFO)的原则。可以想象成排队等候的人群,先到的人先离开。

队列有两个主要的操作:

入队(enqueue):将元素插入到队列的尾部。
出队(dequeue):从队列的头部移除元素,并返回被移除的元素。

队列可以用于许多实际应用,例如处理请求、任务调度、广度优先搜索等。

2.1队列(Queue)的实现

这是一个用C语言实现的栈数据结构的代码。栈是一种后进先出(LIFO)的数据结构,它具有以下几个基本操作:

初始化栈(StackInit):该函数用于初始化一个栈对象。它将栈的指针(ps)赋值为NULL,容量(capacity)为0,栈顶(top)为0。

void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

入栈(StackPush):该函数将一个元素(x)压入栈中。首先会判断栈是否已满(即当前容量是否等于栈顶),如果已满,则需要动态增加栈的容量。我们使用realloc函数来重新分配内存,将栈的容量扩大为原容量的2倍。如果内存分配失败,则会输出错误信息并退出程序。接着,将元素(x)存储到栈的栈顶位置,然后将栈顶(top)加1。

void StackPush(Stack* ps, STDataType x)
{
	assert(ps);
	if (ps->capacity == ps->top)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType)*newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top++] = x;
}

出栈(StackPop):该函数用于弹出栈顶元素,即将栈顶(top)减1。

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

获取栈顶元素(StackTop):该函数返回栈顶元素,即栈顶位置上的元素。

STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}

获取栈中有效元素个数(StackSize):该函数返回栈中有效元素的个数,即栈的栈顶位置(top)。

int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;
}

检测栈是否为空(StackEmpty):该函数检测栈是否为空,如果栈为空(即栈顶位置为0),则返回非零结果;否则,返回0。

bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}

销毁栈(StackDestroy):该函数用于销毁栈对象。首先释放动态分配的内存,将栈的指针(ps)赋值为NULL,容量(capacity)和栈顶(top)都设为0。

void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

这些函数可以帮助你创建一个栈对象,并实现栈的基本功能,比如入栈、出栈、获取栈顶元素等操作。你可以根据自己的需求使用这些函数来管理栈中的数据。

 2.2队列的特点

  • 元素顺序:队列中的元素按照它们进入队列的顺序排列,最先进入队列的元素在队列的前端,而最后进入队列的元素在队列的后端。
  • 入队和出队:只能从队列的一端(称为队尾)进行入队操作,即将元素添加到队列的末尾;只能从队列的另一端(称为队首)进行出队操作,即将队列中的第一个元素移除。
  • 先进先出:队列中的元素按照它们进入队列的顺序进行处理。先入队的元素会先被出队,后入队的元素会后被出队,保持了元素的顺序性。
  • 队空和队满:队列有两种状态,即队空和队满。当队列中没有任何元素时,称为队空状态。当队列中的元素填满了队列的所有位置时,称为队满状态。在一些实现中,可以选择使用固定大小的数组来实现队列,或者使用动态分配内存的方式来实现可变长度的队列。

栈的应用场景广泛,例如:

队列常用于模拟排队系统,例如处理请求、作业调度、消息传递等。

在计算机科学中,队列也有许多派生的数据结构,如优先队列、循环队列等。

总而言之,队列是一种具有先进先出特点的数据结构,适用于需要按照顺序处理元素的场景。它提供了入队和出队操作,保证了元素的顺序性,并且可以应用于各种领域的问题求解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

无敌岩雀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值