对于双向队列而言,头部和尾部都可以执行入队和出队操作。换句话说,双向队列需要实现另一个对称方向的操作。为此,我们采用“双向链表”作为双向队列的底层数据结构。
如图 5-8 所示,我们将双向链表的头节点和尾节点视为双向队列的队首和队尾,同时实现在两端添加和删除节点的功能。
根据教程结合我自己的编程,我用代码实现如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdbool.h>
-
-
- typedef struct DoublyListNode {
- int val;
- struct DoublyListNode *prev;
- struct DoublyListNode *next;
- } DoublyListNode;
-
-
- DoublyListNode *newDoublyListNode(int val) {
- DoublyListNode *node = (DoublyListNode *)malloc(sizeof(DoublyListNode));
- if(node == NULL)
- {
- printf("malloc failed\n");
- return NULL;
- }
- node->val = val;
- node->prev = NULL;
- node->next = NULL;
- return node;
- }
-
-
- void freeDoublyListNode(DoublyListNode *node)
- {
- if(node != NULL)
- {
- printf("free node\n");
- free(node);
- }
- else {
- printf("错误输入参数\n");
- }
- }
-
-
- typedef struct DoublyLinkedListDeque {
- DoublyListNode *front;
- DoublyListNode *rear;
- int queSize;
- } DoublyLinkedListDeque;
-
-
- DoublyLinkedListDeque *newLinkedListDeque() {
- DoublyLinkedListDeque *deque = (DoublyLinkedListDeque *)malloc(sizeof(DoublyLinkedListDeque));
- if(deque == NULL)
- {
- printf("malloc failed\n");
- return NULL;
- }
- deque->front = NULL;
- deque->rear = NULL;
- deque->queSize = 0;
- return deque;
- }
-
-
- void freeLinkedListDeque(DoublyLinkedListDeque *deque)
- {
- if(deque != NULL)
- {
- printf("free deque\n");
- free(deque);
- }
- for(int i=0; i<deque->queSize && deque->front != NULL; i++)
- {
- DoublyListNode *node = deque->front;
- deque->front = deque->front->next;
- freeDoublyListNode(node);
- }
- free(deque);
- }
-
-
- int getLinkedListDequeSize(DoublyLinkedListDeque *deque, int *len)
- {
- if(deque == NULL)
- {
- printf("错误输入参数\n");
- return -1;
- }
- *len = deque->queSize;
- return 0;
- }
-
-
- int isLinkedListDequeEmpty(DoublyLinkedListDeque *deque, bool *flag)
- {
- if(deque == NULL)
- {
- printf("错误输入参数\n");
- return -1;
- }
- *flag = (deque->queSize == 0);
- return 0;
- }
-
-
- int push(DoublyLinkedListDeque *deque, int val, bool isFront) {
- if(deque == NULL)
- {
- printf("错误输入参数\n");
- return -1;
- }
- DoublyListNode *node = newDoublyListNode(val);
- if (node == NULL)
- {
- printf("malloc failed\n");
- return -1;
- }
- int ret = 0;
- bool flag;
- ret = isLinkedListDequeEmpty(deque, &flag);
- if(ret == 0)
- {
- if(flag)
- {
- deque->front = deque->rear = node;
- }
- else if(isFront) {
-
- node->next = deque->front;
- deque->front->prev = node;
- deque->front = node;
- }
- else
- {
-
- deque->rear->next = node;
- node->prev = deque->rear;
- deque->rear = node;
- }
- deque->queSize++;
- return 0;
- }
- return -1;
- }
-
-
- int pushFirst(DoublyLinkedListDeque *deque, int val)
- {
- int ret = push(deque, val, true);
- if(ret == 0)
- {
- printf("入队成功\n");
- return 0;
- }
- printf("入队失败\n");
- return -1;
- }
-
-
- int pushLast(DoublyLinkedListDeque *deque, int val)
- {
- int ret = push(deque, val, false);
- if(ret == 0)
- {
- printf("入队成功\n");
- return 0;
- }
- printf("入队失败\n");
- return -1;
- }
-
-
- int peekFirst(DoublyLinkedListDeque *deque, int *val)
- {
- if(deque == NULL)
- {
- printf("错误输入参数\n");
- return -1;
- }
- if(deque->front == NULL)
- {
- printf("队列为空\n");
- return -1;
- }
- *val = deque->front->val;
- return 0;
- }
-
-
- int peekLast(DoublyLinkedListDeque *deque, int *val)
- {
- if(deque == NULL)
- {
- printf("错误输入参数\n");
- return -1;
- }
- if(deque->rear == NULL)
- {
- printf("队列为空\n");
- return -1;
- }
- *val = deque->rear->val;
- return 0;
- }
-
-
- int pop(DoublyLinkedListDeque *deque, int * val, bool isFront)
- {
- if(deque == NULL)
- {
- printf("错误输入参数\n");
- return -1;
- }
- bool flag;
- int ret = isLinkedListDequeEmpty(deque, &flag);
- if(ret == 0)
- {
- if(flag)
- {
- printf("队列为空\n");
- return -1;
- }
-
- if(isFront)
- {
-
- ret = peekFirst(deque, val);
- if(ret != 0)
- {
- printf("队列为空\n");
- return -2;
- }
- DoublyListNode *fNext = deque->front->next;
- if(fNext != NULL)
- {
- fNext->prev = NULL;
- deque->front->next = NULL;
- }
- freeDoublyListNode(deque->front);
- deque->front = fNext;
- } else
- {
- ret = peekLast(deque, val);
- if(ret != 0)
- {
- printf("队列为空\n");
- return -2;
- }
- DoublyListNode *rPrev = deque->rear->prev;
- if(rPrev != NULL)
- {
- rPrev->next = NULL;
- deque->rear->prev = NULL;
- }
- freeDoublyListNode(deque->rear);
- deque->rear = rPrev;
- }
- deque->queSize--;
- return 0;
- }
- printf("队列为空\n");
- return -1;
- }
-
- int popFirst(DoublyLinkedListDeque *deque, int *val)
- {
- int ret = pop(deque, val, true);
- if(ret == 0)
- {
- printf("出队成功\n");
- return 0;
- }
- printf("出队失败\n");
- return -1;
- }
-
-
- int popLast(DoublyLinkedListDeque *deque, int *val)
- {
- int ret = pop(deque, val, false);
- if(ret == 0)
- {
- printf("出队成功\n");
- return 0;
- }
- printf("出队失败\n");
- return -1;
- }
-
-
- void printLinkedListDeque(DoublyLinkedListDeque *deque)
- {
- if(deque == NULL)
- {
- printf("错误输入参数\n");
- return;
- }
-
- DoublyListNode *node = deque->front;
- while (node != NULL)
- {
- printf("node val: %d\r\n", node->val);
- node = node->next;
- }
- }
-
- int main()
- {
-
- DoublyLinkedListDeque *deque = newLinkedListDeque();
- if(deque == NULL)
- {
- printf("malloc failed\n");
- return -1;
- }
- pushFirst(deque, 1);
- pushFirst(deque, 2);
- pushFirst(deque, 5);
- pushLast(deque, 3);
- printLinkedListDeque(deque);
- printf("开始出列\r\n");
- int val;
- popFirst(deque, &val);
- printf("出列的元素为: %d\r\n", val);
- printLinkedListDeque(deque);
- }
经编译后,测试结果如下:
- liujianhuadeiMac:pro_node liujianhua$ gcc linklist_deque.c -Wall
- liujianhuadeiMac:pro_node liujianhua$ ./a.out
- 入队成功
- 入队成功
- 入队成功
- 入队成功
- node val: 5
- node val: 2
- node val: 1
- node val: 3
- 开始出列
- free node
- 出队成功
- 出列的元素为: 5
- node val: 2
- node val: 1
- node val: 3
【学习小结】
经过自己亲自写代码,理解了如何实现双向队例的实现。双向队列可以实现从头插入,或者从尾部插入,出列也可以双向实现,使用起来非常的方便。