栈和队列详解---(下)

上一篇我们讲了栈,使用了数组来实现栈,今天我们来讲队列。

队列

队列的定义

队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的规则,进行插入操作的一端成为队尾,进行删除的一端是队头。

队列的实现

队列的实现我们一般用单链表,其实双链表也行,但是单链表肯定是更能提高效率,所以我们使用单链表来实现。

队列的一般接口

趋势就是我们写链表的那几个接口,然后还变简单了,所以我们是很容易实现的。

// 初始化队列 
void QueueInit(Queue* q); 
// 队尾入队列 
void QueuePush(Queue* q, QDataType data); 
// 队头出队列 
void QueuePop(Queue* q); 
// 获取队列头部元素 
QDataType QueueFront(Queue* q); 
// 获取队列队尾元素 
QDataType QueueBack(Queue* q); 
// 获取队列中有效元素个数 
int QueueSize(Queue* q); 
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q); 
// 销毁队列 
void QueueDestroy(Queue* q);

实现队列前的准备工作

队列是由节点来组成的,第一个结构体是定义的节点,第二个结构体是定义的队列,包括队头和队尾。

接口实现

//定义节点
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;

}QNode;
//队列的结构体
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;

}Queue;

1.初始化队列

初始化队列做的就是队头和队尾都让他们为空指针,队列大小为0。

// 初始化队列 
void QueueInit(Queue* q)
{
	assert(q);
	q->phead = q->ptail = NULL;
	q->size = 0;

}

2.队尾入队列

如图所示,我们入队列是头插,出队列是尾删,那就简单多了。看代码。

// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
	assert(q);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		return;

	}

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

	if (q->ptail == NULL)
	{
		q->phead = q->ptail = newnode;
		q->size++;

	}
	else
	{
		q->ptail->next = newnode;
		q->ptail = q->ptail->next;
		q->size++;

	}
}

首先开辟空间,然后判断开辟的这个是否为空,然后插入进去,值得注意的是,当这个队列为空的时候我们也要分情况,就像上面代码写的。

3.队头出队列

上面就说了,我们出队列是尾删。看代码。

// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->phead);//先保证进来的不是空的

	if (q->phead->next == NULL)//删除
	{
		free(q->phead);
		q->phead = q->ptail = NULL;

	}
	else
	{
		QNode* next = q->phead->next;
		free(q->phead);
		q->phead = next;

	}
	q->size--;//队列大小减小
	
}

                                                                                                                                                                                                                                                                                                              但是我们碰到了这种情况怎么办,我们让phead为空,释放这个节点,但是ptail不处理,那就回让他成为野指针。所以就有了上面的if语句。这是这个代码唯一要解释的地方。

4.获取队列头部的元素

这个很简单,直接返回队头的值就行了。

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->phead);
	return q->phead->val;
}

5.获取队列尾部的元素

这个也和上面一样,所以我们直接看代码。

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->ptail);
	return q->ptail->val;

}

6.获取队列中有效元素个数

这个也很简单,早在准备工作的时候我们就为队列定义了大小了,所以也可以直接返回。

// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;

}

7.检测队列是否为空,如果为空返回非零结果,如果非空返回0

判空就是返回一个关系式,如果是对的就返回对,如果是错的就返回错。

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->phead == NULL;

}

8.销毁队列

销毁队列就是和链表一样将节点一个一个销毁,这个流程应该已经很熟悉了吧。看代码。

// 销毁队列 
void QueueDestroy(Queue* q)
{
	QNode* cur = q->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;

	}
	q->phead = q->ptail = NULL;
	q->size = 0;

}

总结

其实不管是栈还是队列都是对顺序表实现的一种考验,看我们前面学的扎不扎实,如果已经学的比较熟练了,就会发现其实这些还更加简单呢。不管怎么样,动脑筋,写代码就是王道。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值