数据结构-队列(下)

73 阅读3分钟

队列(下)

上篇文章最后,我们说到了在队列中,链表结构可以代替顺序表结构,从而形成链式队列。并阐述了如果采用链式队列,应该采用什么样的链表来实现,这篇文章将结束队列这部分内容,包括链式队列的具体实现和双端队列。

链式队列结构体和链式队列的初始化

struct node_q {
    int data;
    node_q *next;
};

struct queue_l {
    node_q *front, *rear;
};

queue_l *new_queue() {
    queue_l *q = new queue_l;
    q->front = q->rear = new node_q;
    q->front->next = NULL;
    return q;
}

创建链式队列结构体首先要创建链表的结构,再创建链式队列。链表结点node_q就是常规的单链表结点,包括datanext指针;链式队列queue_l包括链式队列的队头指针front和队尾指针rear

初始化链式队列函数首先new一个新的链式队列q,队列qfrontnext都指向一个新node_q结点,同时让队列q的队头指针的next指针指向NULL,最后return队列q

判队列空

bool isEmpty(queue_l q) {
    if (q.front == q.rear) return true;
    return false;
}

就是和之前一样的,很普通的判空操作,当front==rear时返回true

入队列

void EnQueue(queue_l &q, int x) {
    node_q *s = new node_q;
    s->data = x;
    s->next = NULL;
    q.rear->next = s;
    q.rear = s;
}

入队列是一种插入操作,所以本质上和单链表的插入是一样的。创建一个新的链表结点s,让sdata值等于参数x,再让s结点的next指向NULL,之后让队尾指针指向的结点的next指针指向结点s,最后把队尾指针指向s。基本上就是单链表尾插法插入节点的操作,而且看起来更加直观。

出队列

int DeQueue(queue_l &q) {
    if (q.front == q.rear) return -9999;
    node_q *s = q.front->next;
    int x = s->data;
    q.front->next = s->next;
    if (q.rear == s) q.rear = q.front;
    delete s;
    return x;
}

出队列就是一种删除结点释放内存空间的操作,这里采用的int型函数,最后会返回已删除结点的data值。首先要对队列进行判空,如果队列是空的则返回-9999(代表队列中没有数据元素)。之后保存队头指针的next指针指向的结点(代表含有队头数据元素的结点),并用变量x保存该结点data的值。

让队头指针的next指针指向要删除结点的next指针指向的结点。如果删除后队列为空,则让队尾指针rear等于队头指针front,之后释放要删除结点的内存空间,最后返回变量x的值。

双端队列

双端队列,顾名思义,就是允许队列两端都可以进行插入和删除操作的队列,这也是狭义上的双端队列。

广义上的双端队列可以包括以下几种情况:

  • 一端允许插入和删除,另一端只允许插入;
  • 一端允许插入和删除,另一端只允许删除;
  • 两端都允许插入和删除。

这些都可以称之为双端队列,在关于队列的问题中,常常会见到关于队列入队出队顺序的排列问题,不同情况下的双端队列也会影响到数据元素入队出队的次序。