C#队列(数组模拟)

队列的基本概念

遵循先入先出的原则,即:先存入队列的数据,要先取出,后存入的要后取出。
就像排队打饭一样,来的早,走的也早(此早非彼早)

示意图:自己脑补

队列最基本的两个操作:
入队(enqueue),放一个数据到队列的尾部;
出队(dequeue)从队列头部取一个元素。

顺序队列和链式队列

用数组实现的队列叫顺序队列,用链表实现的队列叫链式队列。
我们先分析下基于数组实现的顺序队列:比如这里有一个Length为4的队列,默认是空值,啥也没有存入


image.png

队列有两个指针,队头,Head,队尾,Rear
队列初始状态

  • head = 0; 队头
  • rear = 0; 队尾

队列的大小为size,队列数组的第一个元素下标为0,最后一个元素的下标为size-1。
代码如下

        private int head=0;//队头
        private int rear=0;//队尾
        private int size=0;//长度
        private int[] arr;//队列数组
       //用构造函数初始化队列
       public  Queue(int size) 
        {
            this.size = size;
            arr = new int[size];
        }

入队

给数组队列加入数据6,7

image.png

每加入一个数据,rear(队尾) 就向后移动一位,队头(Head) 不动,当tail == size 时表示队列已满。
代码如下:

        //入队
        public void AddData(int num) 
        {
            //判断是否已满
            if (size==rear) 
            {
                Console.WriteLine("添加失败,队列已满");
                return;
            }
            arr[rear] = num;
            rear++;
            Console.WriteLine(num+":加入队列");
        }

出队

即 按照先进先出的原则,取出数据


image.png

当6出队之后,队头(Head) 指针向后移动一个位置,队尾指针rear指向不变,当head == rear 时表示队列为空。
代码如下:

  //出队
      public Integer dequeue() {
          // 判断队列是否为空
          if(head == rear) {
              return null;
          }
          int item = arr[head];
          head++;
          return item;
      }

话不多说,奉上全部代码

        private int head=0;//队头
        private int rear=0;//队尾
        private int size=0;//长度
        private int[] arr;//队列数组

       //初始化队列
       public  Queue(int size) 
        {
            this.size = size;
            arr = new int[size];
        }

        //入队
        public void AddData(int num) 
        {
            //判断是否已满
            if (size==rear) 
            {
                Console.WriteLine("添加失败,队列已满");
                return;
            }
            arr[rear] = num;
            rear++;
            Console.WriteLine(num+":加入队列");
        }

      //出队
      public Integer dequeue() {
          // 判断队列是否为空
          if(head == rear) {
              return null;
          }
          int item = arr[head];
          head++;
          return item;
      }

        //获取队列首位元素
        public void GetOneElement()
        {
            if (head==rear)
            {
                Console.WriteLine("获取失败,队列为空");
                return;
            }
            Console.WriteLine("首位元素:" + arr[head]);
        }

        //元素
        public void QueueList()
        {
            if (head==rear)
            {
              throw new Exception("队列为空");
            }
            Console.WriteLine("--------------------遍历队列-----------------------");
            foreach (var a in arr) 
            {
                Console.Write(" "+a);
            }
            Console.WriteLine();
        }

实现以上代码后,问题来了!!!

首先我这里重新定义一下队头和队尾
队尾:Head,队头:Tail
这里有两个需要特别注意的地方

  • 入队时判断队列已满条件tail == size
  • 出队时判断队列为空条件head == tail

随着不断的入队和出队操作,最后head和tail都会一直向队尾移动,当head == tail && tail == size的时候,如下图所示,即使队列有空闲空间也无法向队列中添加任何元素了,也就是说,我们上面创建的队列只能使用一次。

如何解决这个问题呢,我们可以使用循环队列,现在的队列是一条直线,如果我们把首尾相连就形成了一个环,如下图所示:

image.png

循环队列

我可以用循环队列来解决顺序队列只能使用一次的问题。在循环队列中,我们依然需要使用两个变量head(指向队列中的第一个元素,初始值为0)和tail(指向队列中最后一个元素的下一个位置,初始值为0)。

在顺序队列中,我们需要判断队空和队满的情况,同样在循环队列也需要判断队满和队空的情况。

image.png

上图中这个队列大小size为8,开始队列空时head和tail都指向下标0。依次添加元素a、b,此时如上图所示head位置不变,tail向后移指向下标为2的位置。继续添加元素c、d、e、f、g, 此时tail指向了最后一个位置。

数组实现的非循环队列中,队空的情况是head == tail,循环队列中队空的情况也是head == tail。非循环队列中队满的情况是tail == size,循环队列中队满的情况是(tail + 1) % size == head。

上图可以看出,当队列满时,tail指向的位置是没有存储元素的。如果我们想要最后一个位置也存储元素,那么tail需要继续向后移动一个位置,此时tail和head指向了同一个位置,与队列为空的情况是一样的条件head == tail,

所以我们约定牺牲一个存储空间来区分队空和队满的情况。

同样可以计算出队列中实际有效元素的个数为 (tail + size - head) % size。

下面我们使用代码来实现循环队列:

        private int[] arr;
        private int size;
        private int tail = 0;
        private int head = 0;

        public QueueLoop(int size)
        {
            this.size = size;
            arr = new int[size];
        }

        //入列
        public void Add(int num)
        {
            //判断队列是否已满
            if ((tail + 1) % size == head)
            {
                Console.WriteLine("队列已满,不能再添加");
                return;
            }
            arr[tail] = num;

            // (n+1) % size 相当于取 1~size的范围,(不包含size)
            tail = (tail + 1) % size;
        }

        //出列
        public void DeQueue()
        {
            //判断队列是否为空
            if (head == tail)
            {
                Console.WriteLine("队列元素为空");
                return;
            }
            Console.Write(" " + arr[head]);
            head = (head + 1) % size;
        }

        //获取头元素
        public void GetHeadElement()
        {
            //判断队列是否为空
            if (head == tail)
            {
                Console.WriteLine("队列元素为空");
                return;
            }
            Console.WriteLine("头元素" + arr[head]);
        }

        public void QueueList()
        {
            // 实际有效元素个数
            int num = (tail + size - head) % size;
            for (int i = head, len = head + num; i < len; i++)
            {
                Console.Write("   "+arr[i % size]);
            }
        } 

注意:素材来源于网络,仅作为学习笔记记录
本人充分尊重原创劳动成果:如有侵权纠纷,请留言反馈,谢谢

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容