我让你知道我有啥

  • 零、读前说明
  • 一、队列的概述
  • 二、队列的操作
  • 三、队列的两种存储结构的模型概述
  • 四、顺序存储结构的队列及实现
    • 4.1、顺序存储结构的传统队列简易实现与测试
    • 4.2、顺序存储结构的队列的模型选择
    • 4.3、顺序存储结构队列的代码实现
      • 4.3.1、测试工程的目录结构
      • 4.3.2、seqqueue.h文件
      • 4.3.3、seqqueue.c文件
    • 4.4、顺序存储结构队列的测试案例
    • 4.5、测试案例构建编译
    • 4.6、测试结果
  • 五、链式存储结构的队列及实现
    • 5.1、链式存储结构的传统队列简易实现与测试
    • 5.2、链式存储结构的队列模型的业务节点转换
    • 5.3、链式存储结构队列的代码实现
      • 5.3.1、测试工程的目录结构
      • 5.3.2、linkqueue.h文件
      • 5.3.3、linkqueue.c文件
    • 5.4、链式存储结构队列的测试案例
    • 5.5、测试案例构建编译
    • 5.6、测试结果
  • 六、强行来个总结
  • 七、简单说明 -- 栈和队列的异同
    • 7.1、栈和队列的共同点
    • 7.2、栈和队列的不同点
  • 八、一句话的总结

零、读前说明

  • 本文中没有涉及到很多的相关理论知识,也没有做深入的了解,所以,您如果是想要系统的学习、想要多学习关于理论的知识等,那么本文可能并不合适您。
  • 本文中所有设计的代码均通过测试,并且在功能性方面均实现应有的功能。
  • 设计的代码并非全部公开,部分无关紧要代码并没有贴出来。
  • 如果你也对此感兴趣、也想测试源码的话,可以私聊我,非常欢迎一起探讨学习。
  • 由于时间、水平、精力有限,文中难免会出现不准确、甚至错误的地方,也很欢迎大佬看见的话批评指正。
  • 嘻嘻。。。。 。。。。。。。。收!

一、队列的概述

  在使用的电脑的过程中,有时候会出现在敲键盘的突然间没有任何现象,然后又突然间出现一串刚才输入的字母,这其实就是在系统中好多个程序在运行的过程中需要一个通道,按照先后的顺序排队等待造成的。
  还有在排队买自己喜欢的奶茶的时候,看着前面的一个一个慢慢往前挪心里着实着急的不行,但是却只能按照这个次序一步一步的来(当然要是面子大插队的,只能给你说 :嘻嘻,QNMD,杠精!!!)。
  上面这种通道的情况可以用先进先出的排队功能,其实就是队列啦。

  队列是一种特殊的线性表,它只允许在线性表的前端(front)进行删除操作,而在线性表的后端(rear)进行插入操作。

  简单总结为:

  • 队列也是一种特殊的线性表,是一种操作受限制的线性表。
  • 队列仅在线性表的两端进行操作
      队列头部:从获取队列中数据元素的一端 – 出队
      队列尾部:往队列中插入数据元素的一端 – 入队

二、队列的操作

  和栈的一样,队列的操作主要也包括下面这些。

  • 创建队列 SeqQueue_Create
  • 清空队列 SeqQueue_Clear
  • 销毁队列 SeqQueue_Destory
  • 入队列 SeqQueue_Append
  • 出队列 SeqQueue_Subtract
  • 获取队列头部元素 SeqQueue_Header
  • 获取队列长度 SeqQueue_Length

  如果是用顺序表模拟的队列,那么还需要做下队列最大容量的问题,所以额外添加一个接口

  • 获取队列的最大容量 SeqQueue_Capacity

三、队列的两种存储结构的模型概述

  线性表有顺序存储和链式储存,队列 作为一种特殊的线性表,也有同样的存储结构。
  下面就简单说明一下两种存储结构形式的队列模型。
  顺序存储结构链式存储结构的模型的队列,也存在着左右先后的选择的问题。


  只不过,这次的选择貌似并不是那么的难。

四、顺序存储结构的队列及实现

4.1、顺序存储结构的传统队列简易实现与测试

  那么先呢来来热热身体,为了能持久做点铺垫,一个简单的传统实现方式让你直观的感受一下队列这个东东。
  首先,直接糊上代码,有没有闻到一股麦芽的香味~~~

#include <stdio.h>
#include <stdlib.h>#define CAPACITY 10//数据类型
typedef int data_t;
//队列类型
typedef struct
{data_t a[CAPACITY];int front; //队头的下标int rear;  //队尾的下一个下标
} seqqueue_t;//创建空的队列
seqqueue_t *seqqueue_create()
{seqqueue_t *queue = (seqqueue_t *)malloc(sizeof(seqqueue_t));if (queue == NULL)return NULL;queue->front = 0;queue->rear = 0;return queue;
}//空return 1  非空return 0
int seqqueue_is_empty(seqqueue_t *queue)
{if (queue == NULL)return -1;return queue->rear == queue->front ? 1 : 0;
}//满return 1  不满return 0
int seqqueue_is_full(seqqueue_t *queue)
{if (queue == NULL)return -1;return (queue->rear + 1) % CAPACITY == queue->front ? 1 : 0;
}//入队(rear)
int seqqueue_input(seqqueue_t *queue, data_t value)
{if (queue == NULL)return -1;if (seqqueue_is_full(queue))return -1;queue->a[queue->rear] = value;queue->rear = (queue->rear + 1) % CAPACITY;return 0;
}//出队(front)
data_t seqqueue_output(seqqueue_t *queue)
{if (queue == NULL)return (data_t)-1;if (seqqueue_is_empty(queue))return (data_t)-1;data_t value = queue->a[queue->front];queue->front = (queue->front + 1) % CAPACITY;return value;
}int main(int argc, const char *argv[])
{int i = 0;seqqueue_t *queue = seqqueue_create();if (queue == NULL)return -1;printf("\n入队数据:");while (!seqqueue_is_full(queue)){i++;printf("%d\t", i * 10);seqqueue_input(queue, i * 10);}printf("\n出队数据:");while (!seqqueue_is_empty(queue)){printf("%d\t", seqqueue_output(queue));}putchar(10);putchar(10);return 0;
}

  可惜大叔牙口不好,那么直接编译运行咯

  有那个意思了哈,那咱们继续往下。。。

4.2、顺序存储结构的队列的模型选择

  由上面的简单描述可知顺序存储结构的队列有两种形式。
  第一种:
    队尾 <–> 入队 <–> 顺序表的头部
    队头 <–> 出队 <–> 顺序表的尾部
  第二种:
    队尾 <–> 入队 <–> 顺序表的尾部
    队头 <–> 出队 <–> 顺序表的头部
  其简单的示意图可以如下图所示。

  有图片显示可以看出来,对于上面的两种模型的队列,由于队列只能操作两端(头、尾),所以其实上面两种模型没有什么区别了。
  (PS:虽然是废话,但是还是需要简单的提一下的)

4.3、顺序存储结构队列的代码实现

4.3.1、测试工程的目录结构

  为了负责人起见呢,我还是再简单的说明一下本人测试使用的目录结构。为了兼容unixwindows系统以及方便进行工程管理,特意使用Cmake工具进行编译等,目前测试工程的目录结构如下所示。

seqqueue/
├── CMakeLists.txt
├── README.md
├── build
├── main
│   └── main.c
├── runtime
└── src├── seqlist│   ├── seqlist.c│   └── seqlist.h└── seqqueue├── seqqueue.c└── seqqueue.h6 directories, 7 files
4.3.2、seqqueue.h文件

  seqqueue.h文件主要申明和定义用户自定义变量和函数接口等,其中内容如下。

#ifndef __SeqQueue_H__
#define __SeqQueue_H__#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "../seqlist/seqlist.h"#define null NULL
typedef void SeqQueue;
typedef void SeqQueueNode;typedef struct func_SeqQueue
{SeqQueue *(*create)();int (*destroy)(SeqQueue *);int (*clear)(SeqQueue *);int (*length)(SeqQueue *);int (*capacity)(SeqQueue *);int (*append)(SeqQueue *, SeqQueueNode *);SeqQueueNode *(*header)(SeqQueue *);SeqQueueNode *(*subtract)(SeqQueue *);
} func_SeqQueue;#endif
4.3.3、seqqueue.c文件

  seqqueue.c文件主要为队列的功能实现等,其中内容如下。

#include "seqqueue.h"#ifndef null
define null NULL
#endif/*** 通过下面的定义来选择队列饿模型的选择 * 如果定义 TAIL_HEADER,第一种模型* 如果不定义 TAIL_HEADER,第二种模型**/
// #define TAIL_HEADERextern funSeqList SeqListfunc;/*** 功 能:*      创建一个队列* 参 数:*      capacity:队列的最大容量* 返回值:*      成功:操作句柄*      失败:NULL**/
SeqQueue *SeqQueue_Create(int capacity)
{return SeqListfunc.create(capacity);
}
/*** 功 能:*      销毁一个队列* 参 数:*      Queue:要操作的队列* 返回值:*      成功:0*      失败:-1**/
int SeqQueue_Destory(SeqQueue *Queue)
{return SeqListfunc.destory(Queue);
}
/*** 功 能:*      清空一个队列* 参 数:*      Queue:要操作的队列* 返回值:*      成功:0*      失败:-1**/
int SeqQueue_Clear(SeqQueue *Queue)
{return SeqListfunc.clear(Queue);
}/*** 功 能:*      获取队列的长度* 参 数:*      Queue:要操作的队列* 返回值:*      成功:队列的长度*      失败:-1**/
int SeqQueue_Length(SeqQueue *Queue)
{return SeqListfunc.length(Queue);
}/*** 功 能:*      获取队列的最大容量* 参 数:*      Queue:要操作的队列* 返回值:*      成功:队列得容量*      失败:-1**/
int SeqQueue_Capacity(SeqQueue *Queue)
{return SeqListfunc.capacity(Queue);
}/*** 功 能:*      插入元素* 参 数:*      Queue:要操作的队列*      node : 要插入的元素* 返回值:*      成功:0*      失败:-1**/
int SeqQueue_Append(SeqQueue *Queue, SeqQueueNode *node)
{#ifdef TAIL_HEADERreturn SeqListfunc.insert(Queue, node, 0);
#elsereturn SeqListfunc.insert(Queue, node, SeqListfunc.length(Queue));
#endif
}
/*** 功 能:*      获取队列的元素* 参 数:*      Queue:要操作的队列* 返回值:*      成功:操作句柄*      失败:NULL**/
SeqQueueNode *SeqQueue_Header(SeqQueue *Queue)
{#ifdef TAIL_HEADERreturn SeqListfunc.get(Queue, SeqListfunc.length(Queue) - 1);
#elsereturn SeqListfunc.get(Queue, 0);
#endif
}/*** 功 能:*      删除队列* 参 数:*      Queue:要操作的队列* 返回值:*      成功:删除后的元素*      失败:NULL**/
SeqQueueNode *SeqQueue_Subtract(SeqQueue *Queue)
{#ifdef TAIL_HEADERreturn SeqListfunc.delete(Queue, SeqListfunc.length(Queue) - 1);
#elsereturn SeqListfunc.delete(Queue, 0);
#endif
}func_SeqQueue fun_SeqQueue = {SeqQueue_Create,SeqQueue_Destory,SeqQueue_Clear,SeqQueue_Length,SeqQueue_Capacity,SeqQueue_Append,SeqQueue_Header,SeqQueue_Subtract
};

4.4、顺序存储结构队列的测试案例

  前面已经说明整体工程的结构,以及需要的文件,下面是测试底层功能函数的测试demo,说到底就是 main 函数功能,详细代码如下。

#include "../src/seqqueue/seqqueue.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* 声明底层链表的函数库 */
extern func_SeqQueue fun_SeqQueue;#define CAPACITY 10int main(int argc, const char *argv[])
{int i = 0;int a[CAPACITY] = {0};SeqQueue *queue = fun_SeqQueue.create(CAPACITY);if (queue == NULL)return -1;// 压队列for (i = 0; i < CAPACITY - 1; i++){a[i] = i + 1;fun_SeqQueue.append(queue, &a[i]);}printf("最大容量为 : %d\n", fun_SeqQueue.capacity(queue));printf("目前长度为 : %d\n", fun_SeqQueue.length(queue));printf("队列顶数据为 : %d\n", *((int *)fun_SeqQueue.header(queue)));printf("\n");while (fun_SeqQueue.length(queue) > 0){printf("出队列的数据为 :%d\n", *((int *)fun_SeqQueue.subtract(queue)));}printf("\n");return 0;
}

4.5、测试案例构建编译

  前面的所有的内容都是在 windows 环进行编写并完成的,本次由于一些问题,本次测试暂时转到linux(Ubuntu 16.06 LTS) 环境下进行,其他系统等详细说明在README.md中查看。
  使用Cmake编译,使用下面指令。

cd build
cmake -G"Unix Makefiles" .. # 注意 .. ,表示上级目录
make

  效果其实和windows是一样的,如下图所示。

4.6、测试结果

  经过cmake编译之后,配置cmake可执行文件放在固定目录runtime下,可以使用在当前目录下使用指令 ./../runtime/seqqueue来运行可执行程序,也可以进入到目录runtime中,然后使用指令 ./seqqueue ,即可运行测试程序。实际测试的结果如下图所示。

五、链式存储结构的队列及实现

5.1、链式存储结构的传统队列简易实现与测试

  惯例热身,直接代码。

/*链式的队列:先进先出*/#include <stdio.h>
#include <stdlib.h>//数据类型
typedef int data_t;//节点类型
typedef struct node
{data_t data;      //存储数据struct node *next; //存储下一个节点地址
} linknode_t;//队列类型
typedef struct
{linknode_t *front; //队头的地址linknode_t *rear;  //队尾的地址
} linkqueue_t;//创建空的队列
linkqueue_t *linkqueue_create()
{// 开辟头节点的空间linknode_t *head = (linknode_t *)malloc(sizeof(linknode_t));if (head == NULL)return NULL;head->next = NULL;// 开辟两个指针空间linkqueue_t *queue = (linkqueue_t *)malloc(sizeof(linkqueue_t));if (queue == NULL){free(head);head = NULL;return NULL;}queue->front = head;queue->rear = head;return queue;
}//入队(尾插入 rear)
int linkqueue_input(linkqueue_t *queue, data_t value)
{if (queue == NULL)return -1;linknode_t *node = (linknode_t *)malloc(sizeof(linknode_t)); //开辟新节点的空间if (node == NULL)return -1;node->data = value;node->next = NULL;queue->rear->next = node; //最后一个节点与新节点相连queue->rear = node;       //使指向新的最后一个节点return 0;
}//空return 1  非空return 0
int linkqueue_is_empty(linkqueue_t *queue)
{if (queue == NULL)return -1;
#if 0return queue->front->next == NULL  ? 1 : 0;
#elsereturn queue->front == queue->rear ? 1 : 0;
#endif
}//出队(头删除 front)
data_t linkqueue_output(linkqueue_t *queue)
{if (queue == NULL)return (data_t)-1;if (linkqueue_is_empty(queue))return (data_t)-1;linknode_t *temp = queue->front->next; //临时记录要出队的节点data_t value = temp->data;            //临时记录要出队的数据queue->front->next = temp->next; //头节点与第二个节点连接(头删)free(temp);temp = NULL;if (queue->front->next == NULL) //当队列为空时是指针rear指向头queue->rear = queue->front;return value;
}int main(int argc, const char *argv[])
{int i = 0;linkqueue_t *queue = linkqueue_create();if (queue == NULL)return -1;printf("\n入队数据:");for (i = 1; i < 10; i++){printf("%d\t", i * 10);linkqueue_input(queue, i * 10);}printf("\n出队数据:");while (!linkqueue_is_empty(queue)){printf("%d\t", linkqueue_output(queue));}putchar(10);putchar(10);return 0;
}

  效果看图。

  现在好啦,身也热完了,那就开干咯。

5.2、链式存储结构的队列模型的业务节点转换

  链式存储结构的队列也有两种形式。只是这两种形式其实和顺序结构的一模一样。往前面看一下就知道是什么样子的了,这儿就不再凑热闹了。

  按照原来线性表的测试案例,如果想要把业务节点插入到链表中,那么就要业务节点去包含链表节点,那么现在还有一个问题就是如何将栈的业务节点转化成一个链表的业务节点呢。
  我们已经在 数据结构(三) – C语言版 – 线性表的链式存储 - 单链表 的 4.7、调用测试用例 章节已经说明了,通用链表并不关心业务节点是什么样式的,只是让业务节点去包含链表节点即可形成链表,那么现在在进行栈的操作中我们也需要将栈的业务节点转换成链表的业务节点。其实,就像前文中的 “老师节点”、“学生节点” 一样 ,我们也需要将链表节点包含到栈的节点中即可,那么,本文中的节点的定义可以为这样。
  定义存在于文件 linkqueue.h中。

// 定义队列的业务节点类型
typedef struct _tag_LinkQueueNode
{LinkListNode node;   // 链表的业务节点LinkQueueNode *item; // 队列的业务节点
} TLinkQueueNode;

  而原本的链表的业务节点的定义为这样的,定义存在于文件 linklist.h中。

typedef void Linklist;
#define null NULLtypedef struct _tag_linklistNode
{struct _tag_linklistNode *next;
} LinkListNode;typedef struct _tag_Linklist
{LinkListNode header;int length;
} TLinklist;

  通过这样的包含关系,那么栈的节点已经包含了链表的节点。

  是的,上面这些文字在上一篇栈的文章已经写了,而且这儿出现和那个是一模一样的。

5.3、链式存储结构队列的代码实现

5.3.1、测试工程的目录结构

  目录结构都是一样的,除了个别文件的文件名称不一样、文件的多少、文件内容不一样外。

5.3.2、linkqueue.h文件

  linkqueue.h文件内容如下所示。

#ifndef __LINKQUEUE_H__
#define __LINKQUEUE_H__#include "../linklist/linklist.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define null NULLtypedef void LinkQueue;
typedef void LinkQueueNode;// 定义队列的业务节点类型
typedef struct _tag_LinkQueueNode
{LinkListNode node;   // 链表的业务节点LinkQueueNode *item; // 队列的业务节点
} TLinkQueueNode;typedef struct func_LinkQueue
{LinkQueue *(*create)();int (*destroy)(LinkQueue *);int (*clear)(LinkQueue *);int (*length)(LinkQueue *);int (*append)(LinkQueue *, LinkQueueNode *);LinkQueueNode *(*header)(LinkQueue *);LinkQueueNode *(*subtract)(LinkQueue *);
} func_LinkQueue;#endif
5.3.3、linkqueue.c文件

  linkqueue.c文件内容如下所示。

#include "linkqueue.h"extern func_linklist fun_linklist;#ifndef null
define null NULL
#endif/*** 通过下面的定义来选择队列饿模型的选择 * 如果定义 TAIL_HEADER,第一种模型* 如果不定义 TAIL_HEADER,第二种模型**/
// #define ABCDEFGH/*** 功 能:*      创建一个队列* 参 数:*      无* 返回值:*      成功:操作句柄*      失败:NULL**/
LinkQueue *LinkQueue_Create(void)
{return fun_linklist.create();
}/*** 功 能:*      插入元素,压队列* 参 数:*      queue:要操作的队列*      node : 要插入的元素,队列的业务节点* 返回值:*      成功:0*      失败:-1**/
int LinkQueue_Append(LinkQueue *queue, LinkQueueNode *node)
{if (queue == NULL || node == NULL)return -1;TLinkQueueNode *temp = NULL;int ret = 0;temp = (TLinkQueueNode *)malloc(sizeof(TLinkQueueNode));if (temp == NULL)return -1;memset(temp, 0, sizeof(TLinkQueueNode));temp->item = node;
#ifdef ABCDEFGHret = fun_linklist.insert(queue, (LinkListNode *)temp, fun_linklist.length(queue));
#elseret = fun_linklist.insert(queue, (LinkListNode *)temp, 0);
#endifif (ret != 0 && temp != NULL)free(temp);return ret;
}/*** 功 能:*      弹出队列元素* 参 数:*      queue:要操作的队列* 返回值:*      成功:删除后的元素*      失败:NULL**/
LinkQueueNode *LinkQueue_Subtract(LinkQueue *queue)
{if (queue == NULL)return NULL;LinkQueueNode *item = NULL;TLinkQueueNode *temp = NULL;#ifdef ABCDEFGHtemp = (TLinkQueueNode *)fun_linklist.delete(queue, 0);
#elsetemp = (TLinkQueueNode *)fun_linklist.delete(queue, fun_linklist.length(queue) - 1);
#endifif (temp == NULL)return NULL;// 把线性表的业务节点转换成队列的业务节点item = temp->item;// 在 insert 的时候malloc的内存需要free掉if (temp != NULL)free(temp);return item;
}/*** 功 能:*      清空一个队列* 参 数:*      queue:要操作的队列* 返回值:*      成功:0*      失败:-1**/
int LinkQueue_Clear(LinkQueue *queue)
{if (queue == NULL)return -1;while (fun_linklist.length(queue) > 0){/*涉及到队列的元素声明周期的处理所有入队列的节点都是通过mallo静态申请的,那么想要清空队列的时候,需要将malloc的节点free掉所以需要将队列中元素全都pop掉,并且free节点的内存*/LinkQueueNode *temp = LinkQueue_Subtract(queue);if (temp == NULL){return -1;}}return 0;
}/*** 功 能:*      销毁一个队列* 参 数:*      queue:要操作的队列* 返回值:*      成功:0*      失败:-1**/
int LinkQueue_Destory(LinkQueue *queue)
{LinkQueue_Clear(queue);return fun_linklist.destory(&queue);
}/*** 功 能:*      获取队列的长度* 参 数:*      queue:要操作的队列* 返回值:*      成功:队列的长度*      失败:-1**/
int LinkQueue_Length(LinkQueue *queue)
{return fun_linklist.length(queue);
}/*** 功 能:*      获取队列顶的元素* 参 数:*      queue:要操作的队列* 返回值:*      成功:操作句柄*      失败:NULL**/
LinkQueueNode *LinkQueue_Header(LinkQueue *queue)
{if (queue == NULL)return NULL;TLinkQueueNode *temp = NULL;
#ifdef ABCDEFGHtemp = (TLinkQueueNode *)fun_linklist.get(queue, 0);
#elsetemp = (TLinkQueueNode *)fun_linklist.get(queue, fun_linklist.length(queue) - 1);
#endifif (temp == NULL)return NULL;return temp->item;
}func_LinkQueue fun_LinkQueue = {LinkQueue_Create,LinkQueue_Destory,LinkQueue_Clear,LinkQueue_Length,LinkQueue_Append,LinkQueue_Header,LinkQueue_Subtract
};

5.4、链式存储结构队列的测试案例

  是呀,好听了就叫测试案例,其实就是 main 函数所在文件,那么main.c文件内容如下所示。

#include "../src/linkqueue/linkqueue.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* 声明底层栈的函数库 */
extern func_LinkQueue fun_LinkQueue;#define CAPACITY 10int main(int argc, const char *argv[])
{int i = 0;int a[CAPACITY] = {0};LinkQueue *queue = fun_LinkQueue.create();if (queue == NULL)return -1;// 压栈printf("入栈的数据为 :");for (i = 0; i < CAPACITY; i++){a[i] = i + 1;printf("%d ", a[i]);fun_LinkQueue.append(queue, &a[i]);}printf("\n\n");printf("目前长度为 : %d\n", fun_LinkQueue.length(queue));printf("栈顶数据为 : %d\n", *((int *)fun_LinkQueue.header(queue)));printf("\n");printf("出栈的数据为 :");while (fun_LinkQueue.length(queue) > 0){LinkQueueNode *tmp = fun_LinkQueue.subtract(queue);printf("%d ", *((int *)tmp));}printf("\n\n");return 0;
}

5.5、测试案例构建编译

  和上面的一样,CMake,没什么可解释的,直接上去啪啪啪就是几个命令干就完事儿了。

5.6、测试结果

  说多了就矫情,直接上图图图图。

六、强行来个总结

  • 和栈一样,可以用线性表的顺序存储结构、线性表的链式存储结构分别来模拟栈
  • 和栈不一样的就是 先进先出,可以用来做 缓冲
  • 顺序结构实现的队列可以有空、满的判断,但是本文使用的是长度
  • 是的,这么一堆说下来,其实栈是一样的

七、简单说明 – 栈和队列的异同

7.1、栈和队列的共同点

  • 都是一种操作受限的线性结构。
  • 只允许在端点处插入和删除元素(头部、尾部)
  • 都可以通过顺序结构和链式结构来模拟实现
  • 有相同的基本操作(创建、销毁、清空、入栈/队列、出栈/队列、获取栈/队列元素)
  • 入栈/队列、出栈/队列的操作的时间复杂度都可以是O(1),在空间复杂度上两者也一样(但是本文中的队列没有引入rear指针,所以队列的复杂度为O(1)、O(n))。
  • 多链栈和多链队列的管理模式可以相同。

7.2、栈和队列的不同点

  • 栈和队列的操作形式不同,栈先进后出队列先进先出
  • 栈的操作都在线性表的一端(要么头部,要么尾部)、队列的操作是在线性表的两端(一端入队列,一端出队列)
  • 获取元素的操作的速度不同,
  • 应用场景不同(最主要特性新不同导致)
  • 顺序结构的栈可以实现多栈空间的共享、而顺序结构队列却不能

八、一句话的总结

  吃多了吐就是栈
  吃多了拉就是队列

上一篇:数据结构(七) – C语言版 – 栈和队列 - 栈的应用解析
下一篇:数据结构(九) – C语言版 – 栈和队列 - 队列的特殊实现

数据结构(八) -- C语言版 -- 栈和队列 - 队列的设计与实现相关推荐

  1. 数据结构(C语言版) 第 三 章 栈与队列 知识梳理 + 作业习题详解

    目录 一.栈 0.栈的基本概念 1.栈的实现 2.栈与递归 3.Hanoi塔问题 二.队列 0.队列的基本概念 1.队列的实现 2.循环队列 2.1循环队列的相关条件和公式: 3.链队列 4.链队列完 ...

  2. 数据结构(C语言版) 第 八 章 排序 知识梳理 + 习题详解

    目录 一.归并排序 二.交换排序 1.快速排序 2.冒泡排序 三.插入排序 1.直接插入排序(基于顺序查找) 2.折半插入排序(基于折半查找) 3.希尔排序(基于逐趟缩小增量) 四.选择排序 0.直接 ...

  3. c语言编写队列元素逆置,数据结构与算法实验—利用栈逆置队列元素.doc

    数据结构与算法实验-利用栈逆置队列元素 利用栈逆置队列元素实验报告 通信1204班 谢崇赟 实验名称 利用堆栈将队列中的元素逆置 实验目的 会定义顺序栈和链栈的结点类型. 掌握栈的插入和删除结点在操作 ...

  4. 资料分享:送你一本《数据结构(C#语言版)》电子书!

    对于信息类专业的学生而言,数据结构与算法是一门必修的课程.只有学好这门课程,熟练掌握线性表.栈.队列.树.图等基本结构,以及在这些结构上的各种算法,才能利用计算机去解决实际问题. 如何学好这门课程呢, ...

  5. 资料分享:送你一本《数据结构(C语言版)》电子书!

    要想写出可复用.可扩展.易维护.灵活性好的代码,「数据结构」这一关必须要过啊! 在数据结构与算法的众多教材中,奉为经典的当属清华大学严蔚敏老师的著作.很多学校也选择这本书作为考研指定教材. 正在学习数 ...

  6. 数据结构(C语言版) 第 六 章 图 知识梳理 + 习题详解

    目录 一. 图的基本定义和术语 一.图的基本概念 1.度 2.连通 (1)连通图 (2)强连通/强连通图 3.回路 4.完全图 二.图的三种存储结构 1.邻接矩阵表示法 2.邻接表(链式)表示法 3. ...

  7. 数据结构(C语言版 第2版)课后习题答案 严蔚敏 等 编著

    数据结构(C语言版 第2版)课后习题答案 严蔚敏 等 编著,仅供参考,还是自己认真做了再看 第1章  绪论 5.选择题 (1)在数据结构中,从逻辑上可以把数据结构分成(  C ). A.动态结构和静态 ...

  8. 严蔚敏版数据结构(C语言版)算法实现代码

    严蔚敏版数据结构(C语言版)算法实现代码 数据结构(C语言版)代码实现 线性表 顺序表 链表 单向链表 静态链表01 静态链表02 双向循环链表 栈与队列 栈 顺序栈 进制转换 行编辑器 未完待续.. ...

  9. 数据结构(C语言版 第2版)课后习题答案 严蔚敏版

    数据结构(C语言版 第2版)课后习题答案 严蔚敏 等 编著,仅供参考,还是自己认真做了再看 第1章  绪论 5.选择题 (1)在数据结构中,从逻辑上可以把数据结构分成(  C ). A.动态结构和静态 ...

最新文章

  1. ZooKeeper伪分布式集群安装
  2. windows的php如何安装目录结构,禅道的目录结构
  3. python 在线编程 实现_Python进阶开发之网络编程,socket实现在线聊天机器人
  4. php 和new date,将JavaScript new Date()转换为php DateTime()
  5. Iwfu-GitHubclient使用
  6. L1-064 估值一亿的AI核心代码 (20 分)—团体程序设计天梯赛
  7. 打开文件对话框在xp和win7上的实现文件任意多选
  8. micropython支持stm32型号_轻松几步实现在STM32上运行FreeRTOS任务
  9. 调用阿里语音合成接口(文字转语音)
  10. 烽火软件测试的笔试难不难,烽火科技软件测试面试经验
  11. 零售的哲学 零售心理战 读后感--7-11这个产品不错!
  12. Notepad++的列编辑模式_小技巧
  13. SpringCloud-Netflix
  14. js 删除节点小案例
  15. 北京:一个大学生每年要花多少钱
  16. 又是暴力裁员?腾讯 7 年老员工一朝被裁,官方回应了...
  17. 怎么禁止计算机安装程序,电脑如何禁止安装软件,教你win10电脑禁止安装软件的设置教程...
  18. Flink任务链Operator Chains
  19. MT8516处理器简介—MT8516芯片技术资料解析
  20. Mysql查询至少有一门课与学号为“s001”的同学所学相同的同学的学号和姓名

热门文章

  1. Java处理json编程之Jackson使用篇
  2. 【新手基础教程】片上外设之 WDT(看门狗) 的使用
  3. 中国高新技术产业导报专访:区块链或将进入去伪存真时代
  4. 一种非信任证书自动更新方法(可用于Windows Vista, Windows Server 2008,Windows 7,Windows Server 2008 R2)
  5. SQL Server实验
  6. win10锁定计算机命令,锁定Windows 10 PC的10种方法
  7. Windows远程桌面连接设置——同时让两人连接
  8. 2023年律师事务所研究报告
  9. 焊接培训,焊工培训的这些坑人套路你知道?
  10. 【iOS 仿写计算器】