画解数据结构之队列

一。概念

队列 是仅限在 一端 进行 插入另一端 进行 删除 的 线性表
  队列 又被称为 先进先出 (First In First Out) 的线性表,简称 FIFO 。

进行元素删除的一端为队首

插入的一段为队尾

二。队列的顺序表实现

1.数据结构实现

struct queue{
Datatype data[maxn];
int head,tail;
}

2.入对

void QueueEnqueue(struct Queue *que, DataType dt) {  // (1)
    que->data[ que->tail ] = dt;                     // (2)
    que->tail = que->tail + 1;                       // (3)
}

3.出队

que->head++;

 如图所示,橙色元素 为原先的 队首元素,执行 出队 操作以后,黃色元素 成为当前的 队首元素,执行完毕以后,队首指针加一。由于是顺序表实现,队首元素前面的那些元素已经变成无效的了,具体来看下代码实现

4.清空

que->head=que->tail=0;

5.其他

DataType QueueGetFront(struct Queue* que) {
    return que->data[ que->head ];      // (1)
}
int QueueGetSize(struct Queue* que) {
    return que->tail - que->head;       // (2)
}
int QueueIsEmpty(struct Queue* que) {
    return !QueueGetSize(que);          // (3)
}

三。链表实现

1.数据结构定义

struct queuenode;
struct queuenode{
int data;
struct queuenode *next;
}
struct queue{
struct queuenode*head,tail;
int size;
}

2.入队(类似尾插法)

void queueinsert(struct queue*que,int dt)
{
struct queuenode*insertnode=(struct queuenode*)malloc(sizeof(struct queuenode));
queuenode->data=dt;
queuenode->next=NULL;
if(que->tail)//如果队尾不为空
{
que->tail->next=insertnode;
que->tail=insertnode;
}
else{
que->tail=que->head=insertnode;
}
++que->size;
}

3.出队(即删除头结点)

void dequeue(struct queue*que)
{
struct queuenode*temp=que->head;
que->head=que->next;
free(temp);
--que->size;
if(!que->size)//如果此次出队之后队列为空,那么出队之前head=tail=temp
//上述操作将head置空,因此还要将tail置空
que->tail=NULL;
}
}

4.清空

清空队列 可以理解为:不断的 出队,直到 队列元素 个数为零为止。由于链表结点是动态申请的内存,所以在没有其它结点引用时,是需要释放内存的,不像数组那样直接将 队首指针 和 队尾指针 置空就行的。

void QueueClear(struct Queue* que) {
    while(!QueueIsEmpty(que)) {     // (1)
        QueueDequeue(que);          // (2)
    }
}

5.其他

DataType QueueGetFront(struct Queue* que) {
    return que->head->data;              // (1)
}
int QueueGetSize(struct Queue* que) {
    return que->size;                    // (2)
}
int QueueIsEmpty(struct Queue* que) {
    return !QueueGetSize(que);           // (3)
}

四。优缺点

1、顺序表实现

  在利用顺序表实现队列时,入队 和 出队 的常数时间复杂度低,且 清空队列 操作相比 链表实现 能做到 O(1)O(1),唯一的不足之处是:需要预先申请好空间,而且当空间不够时,需要进行扩容,扩容方式本文未提及,可以参考以下文章:《C/C++ 面试 100 例》(四)vector 扩容策略
  当然,可以采用 循环队列,能够很大程度上避免扩容问题,但是当 入队速度 大于 出队速度 时,不免还是会遇到扩容的问题。

2、链表实现

  在利用链表实现队列时,入队 和 出队 的常数时间复杂度略高,主要是每插入一个队列元素都需要申请空间,每删除一个队列元素都需要释放空间,且 清空队列 操作是 O(n)O(n) 的,直接将 队首指针 和 队尾指针 置空会导致内存泄漏。
  好处就是:不需要预先分配空间,且在内存允许范围内,可以一直 入队,没有顺序表的限制。当然,链表的实现明显比数组实现要复杂,编码的时候容易出错。


  需要注意的是,本文在讲解过程中,顺序表实现 的 队尾 和 链表实现 的 队尾 不是一个概念,顺序表实现的队尾没有实际元素值,而链表实现的则不然,请自行加以区分。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值