【数据结构】认识和实现栈和队列


栈和队列是两种重要的线性结构。从数据结构角度看,栈和队列也是线性表,其特殊性在于栈和队列的基本操作是线性表操作的子集,它们是操作受限的线性表,因此,可称为限定性的数据结构。接下来我们将一起学习栈和队列的定义与实现。

栈的概念及结构

栈是一种特殊的线性表,是限定仅在表尾进行插入或删除操作的线性表。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底,不含元素的空表称为空栈。
假设栈S=(a1,a2,…,an),则称a1为栈底元素,an为栈顶元素。栈中元素按a1,a2,…,an的次序进栈,退栈的第一个元素应为栈顶元素。即栈中元素遵循后进先出LIFO(Last In First Out)的原则。
在这里插入图片描述
在这里插入图片描述

栈的实现

栈的实现一般可以使用数组或链表来实现,由于栈是在表尾实现插入删除,所以用数组操作更方便一些。因为数组在尾上插入代价更小。
在这里插入图片描述

下面我们将实现动态增长的数组栈。

定义顺序栈结构体
top用于记录栈顶元素的后一位置,此时top值等于栈中元素个数

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

我们主要实现以下函数 :

(1)void StackInit(Stack* ps); // 初始化栈  
(2)void StackPush(Stack* ps, STDataType data);  // 入栈  
(3)void StackPop(Stack* ps); // 出栈  
(4)STDataType StackTop(Stack* ps);   // 获取栈顶元素  
(5)int StackSize(Stack* ps);  // 获取栈中有效元素个数  
(6)int StackEmpty(Stack* ps);    // 检测栈是否为空
(7)void StackDestroy(Stack* ps);    // 销毁栈  
初始化栈
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;  //top指向栈顶元素的下一位置
	ps->capacity = 0;
}
入栈
   插入前先检测栈容量是否已满。如果满了就要扩容。top指向栈顶元素下一个,所以插入时先在top位置插入数据,然后再给top值加1.
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		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] = data;
	ps->top++;
}
出栈
// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0); 
	ps->top--;
}
获取栈顶元素
}
// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}
获取栈中元素个数
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;
}
判断栈是否为空
int StackEmpty(Stack* ps)
{
	assert(ps);
	if (ps->top == 0)
		return 1;
	return 0;
}
销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

队列

队列的概念及结构

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。
在这里插入图片描述

队列的实现

同栈一样,队列也可以用数组和链表这两种结构来实现。但是队列是在对头出数据,用数组结构来实现的话出数据效率会很低,所以我们将一起学习用链表来实现队列。
在这里插入图片描述

我们主要实现以下函数:

(1)void QueueInit(Queue* q); // 初始化队列
(2)void QueuePush(Queueq,QDataType data);// 入队列
(3)void QueuePop(Queue
q);// 队头出队列
(4)QDataType QueueFront(Queue* q);// 获取队列头部元素 (5)QDataType QueueBack(Queue* q);// 获取队列队尾元素
(6)int QueueSize(Queue* q);//获取队列中有效元素个数 (7)int QueueEmpty(Queue* q);// 检测队列是否为空
(8)void QueueDestroy(Queue* q);// 销毁队列

初始化
void QueueInit(Queue* q)
{
	assert(q);
	q->front = q->rear = NULL;
	q->size = 0;
}
入队列

入队列分为两种情况,一是队列为空时,要注意同时修改头指针尾指针;而是队列不为空的情况,只需修改尾指针。不要忘记修改size的值。

void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = data;
	newnode->next = NULL;

	if (q->rear == NULL)
	{
		q->front = q->rear = newnode;
	}
	else
	{
		q->rear->next = newnode;
		q->rear = q->rear->next;
	}
	q->size++;
}
出队列
void QueuePop(Queue* q)
{
	assert(q);
	//空
	assert(q->size);
	QNode* tmp = q->front;
	q->front = q->front->next;
	free(tmp);
	if (q->front == NULL)
	{
		q->rear = NULL;
	}
	q->size--;
}
获取队头元素
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->front);
	return q->front->data;
}
获取队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->rear);
	return q->rear->data;
}
获取元素个数
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
判断是否为空
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->front == NULL;
}
销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->front;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->front = q->rear = NULL;
	q->size = 0;
}
  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

今天学习了吗•

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

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

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

打赏作者

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

抵扣说明:

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

余额充值