zoukankan      html  css  js  c++  java
  • 数据结构之队列定义及基本操作实现

      数据结构学着就是有意思,真诚推荐郝斌老师的数据结构视频,真的讲解的非常详细,容易理解。

      一直在跟着郝斌老师的数据结构视频学习,看完了队列的视频,记录下来,总结一下。

      队列的定义:队列是一种特殊的线性表,只允许在表的头部(front处)进行删除操作,在表的尾部(rear处)进行插入操作的线性数据结构,这种结构就叫做队列。进行插入操作的一端称为队尾,进行删除操作的一端称为队尾。

      队列的类型:链式队列,即用链表实现的队列。静态队列:即用数组实现的队列。在这里,我们采用用数组实现的静态队列。因为用链表实现的队列,是一种动态队列,操作更加容易,所以我们这里采用的是静态队列。

      在静态队列中,郝斌老师讲的是一种更为复杂的静态循环队列。这里解释一下就是,假如我们采用的是静态队列,那就必然涉及到数组,如果我们在不断的从队列中删除数据,那么我们队列的头部(front处)就会不断的向上走(在这里说明一下,队列中front永远指向队列的头部元素,rear永远指向队列的最后一个元素的下一个元素),这样就会造成我们被删除的位置永远无法再被利用,就是造成空间的浪费,所以,如果这样,队列这种数据结构也就失去了原本存在的意义。所以,用静态数组实现的静态队列一般都是静态循环队列。那么,问题就来了,既然是静态循环队列,什么时候队列才是空呢?什么时候队列才是满呢?

      这里首先先说一下,什么时候队列才能为空,根据我们前面的讲解,队列在删除时,front会不断的向上移动,如下面的示意图:

    如上面的示意图,在初始状态下front和rear都处于0的位置,在插入元素时,rear会向上走,则填入一个元素后0的位置就会被填入,当再填入一个元素后1的位置则又被填满。此时rear在2的位置,front在0的位置,此时队列中有两个元素,分别位于0和1处。那么,怎么才算是队列为空呢?很简单,就是不断的删除元素,当元素全都被删完了以后就表示当前队列为空了。删除0的元素,front将会移动一个位置到1,再删除一个元素front将会移动一个位置到2,此时整个队列中没有元素存在,整个队列就为空。所以,表示队列是否为空的条件就是front和rear处于一个位置上。

      那么,何时才表示当前队列已满呢?可能大家也猜出来了,大家可能会认为当front和rear在同一位置时,整个队列也可以同时表示当前队列已满。那就是不断的插入元素,rear不断地移动位置,直到rear再次移动到0的位置后,所有的位置都被元素插满,此时整个队列已满。没错,此时整个队列确实已满。但是这样就会和我们的队列为空的条件重复,所以这里我们有两种办法来解决这种情况,我们可以定义一个表示count个数的值,表示当前队列中元素的个数。如果front和rear处于同一个位置,并且count为0则队列为空。如果front和rear处于同一个位置,并且count不为9,则表示当前队列已满。另外一个方法就是我们默认不全用整个属于,我们用n-1个元素,这样,当rear和front处于“紧挨着”的位置时,就表示当前队列已满,并且在下标来看,并没有严格的front和rear的大小关系。

      好了,如果前面大家已经理解,那么,接下来就可以来实现队列的基本操作了(代码都有注释,我就不再详细解释了)。

      队列的定义:

     1 /*
     2 定义队列
     3 队列是一种只能在一段插入一段删除的数据结构。
     4 这里采用静态循环队列,所以队列采用数组实现 
     5 */
     6 typedef struct Queue{
     7     int * pBase;  //用来存放数组 
     8     int front;  //用来表示当前为front,指向队列头 
     9     int rear;   //用来表示当前为rear,指向队列尾部的下一个结点 
    10 }QUEUE;

      队列的初始化操作:大家在这里也可以将队列的长度作为参数传入,我这里就直接写了

    1 /*
    2 队列初始化函数
    3 初始化一个空队列,就是给出队列一个长度,并且里面没有任何数值 
    4 */
    5 void init(QUEUE *pQ){
    6     pQ->pBase=(int *)malloc(sizeof(int)*6);  //给出一个6个整形长度的队列数组
    7     pQ->front=0;
    8     pQ->rear=0;  //将队列初始化为空    
    9 }

      队列的入队函数:

     1 /*
     2 判断当前队列是否已满的函数
     3 因为我们默认认为当一个n的队列已经存入了n-1个值后,就默认它已经满了,不允许它再存储了,所以,
     4 判断队列是否已满就是判断rear和front是否已经是“紧挨着”,即rear在移动一位就会和front重合。 
     5 */
     6 int full_queue(QUEUE *pQ){
     7     if((pQ->rear+1)%6==pQ->front){
     8         return 0;
     9     }
    10     else{
    11         return 1;
    12     }
    13 }
    14 
    15 /*
    16 入队函数
    17 根据队列的特性,入队只能在队列的尾部,即rear处进行,所以入队函数的算法就是将被插入的数据放在rear的位置
    18 插入完成后rear向后移动一位,使rear永远指向队列中最后一个元素的下一个元素。 
    19 在这里有一个需要注意的地方:在我们移动rear的位置时,如果当前rear的位置已经是数组的最后一个位置,应该怎么办?
    20 就应该让rear在回到0的位置,因为我们的队列默认设置的就是循环队列,也就是说,我们的队列是可以拐弯的,当队列没有满,
    21 但是rear却已经在队列的最后一个位置了,那我们就应该在将队列移动到0的位置。这种情形在数学上就是加1取余。 
    22 */
    23 int en_queue(QUEUE *pQ, int val){
    24     if(full_queue(pQ)==0){
    25         return 0;
    26     }    
    27     else{
    28         pQ->pBase[pQ->rear]=val;
    29         pQ->rear=(pQ->rear+1)%6;
    30         return 1; 
    31     }
    32 }

      队列的遍历函数:

     1 /*
     2 遍历队列的函数 
     3 因为这只是遍历一个队列,所以我们不能破坏原有的队列结构,所以,我们必然需要去定义一个新的i来表示当前所在的下标。
     4 遍历的语法非常简单,就是从头开始,直到队列的末尾,即i到了最后一个结点的下一个结点(rear处),遍历就算是结束了。 
     5 */
     6 void traverse_queue(QUEUE *pQ){
     7     int i=pQ->front;  //令i从“头”开始遍历
     8     
     9     while(i!=pQ->rear){
    10         printf("%d ",pQ->pBase[i]);
    11         i=(i+1)%6;  //将i向下移动一个位置 
    12     }    
    13 }

      出队函数:

     1 /*
     2 当前队列是否为空的函数 
     3 */
     4 int empty_queue(QUEUE *pQ){
     5     if(pQ->front==pQ->rear){
     6         return 0;
     7     }
     8     else{
     9         return 1;
    10     }
    11 } 
    12 
    13 /*
    14 出队函数 
    15 因为出队函数已经破换了队列原有的数据结构,所以我们就没有必要去重新定义一个新的下标
    16 出队函数的算法非常简单,就是在队列的头部(front处)进行删除,删除之后将front向下移动一个位置。 
    17 */
    18 int out_quene(QUEUE *pQ,int *pVal){
    19     if(empty_queue(pQ)==0){
    20         return 1;  //1表示当前队列为空 
    21     }
    22     else{
    23         *pVal=pQ->pBase[pQ->front];
    24         pQ->front=(pQ->front+1)%6;
    25         return 0;  //0表示当前当前出队成功 
    26     }    
    27 } 

      上述就是队列的定义及基本操作的代码实现。

    本文系原创,若转载请标明出处。

  • 相关阅读:
    SpringBoot exception异常处理机制源码解析
    集群时间同步
    VMware 克隆的相关设置
    MySQL安装
    MogliFS与spring mvc结合简单示例
    MogileFS与spring结合
    MogileFS表说明
    使用Maven编译项目遇到——“maven编码gbk的不可映射字符”解决办法
    IAT HOOK 简单实现
    进程加载_模块隐藏
  • 原文地址:https://www.cnblogs.com/WuNaiHuaLuo/p/4930296.html
Copyright © 2011-2022 走看看