队列(Queue)是插入操作限定在表的尾部而其它操作限定在表的头部进行的线性表。把进行插入操作的表尾称为队尾(Rear),把进行其它操作的头部称为队头(Front)。当对列中没有数据元素时称为空对列(Empty Queue)。对列的操作是按照先进先出(First In First Out)或后进后出( Last In Last Out)的原则进行的,因此,队列又称为FIFO表或LILO表。队列Q的操作示意图如图所示。

  队列的形式化定义为:队列(Queue)简记为 Q,是一个二元组,

  Q = (D, R)

    其中:D 是数据元素的有限集合;

    R 是数据元素之间关系的有限集合。

  队列的操作是线性表操作的一个子集。队列的操作主要包括在队尾插入元素、在队头删除元素、取队头元素和判断队列是否为空等。与栈一样,队列的运算是定义在逻辑结构层次上的,而运算的具体实现是建立在物理存储结构层次上的。因此,把队列的操作作为逻辑结构的一部分,每个操作的具体实现只有在确定了队列的存储结构之后才能完成。

  队列接口 IQueue<T>的定义如下所示。

public interface IQueue<T>//队列接口的定义
    {
        int GetLength(); //求队列的长度
        bool IsEmpty(); //判断对列是否为空
        void Clear(); //清空队列
        void In(T item); //入队
        T Out(); //出队
        T GetFront(); //取对头元素
    }

队列的存储和运算实现

  1. 顺序队列

用一片连续的存储空间来存储队列中的数据元素, 这样的队列称为顺序队列 (Sequence Queue)。类似于顺序栈,用一维数组来存放顺序队列中的数据元素。队头位置设在数组下标为 0 的端,用 front 表示;队尾位置设在数组的另一端,用 rear 表示。 front 和 rear 随着插入和删除而变化。 当队列为空时, front=rear=-1。图是顺序队列的两个指示器与队列中数据元素的关系图。

  当有数据元素入队时,队尾指示器 rear 加 1,当有数据元素出队时,队头指示器 front 加 1。当 front=rear 时,表示队列为空,队尾指示器 rear 到达数组的上限处而 front 为-1 时,队列为满,如图 (c)所示。队尾指示器 rear 的值大于队头指示器 front 的值,队列中元素的个数可以由 rear-front 求得。由图 (d)可知,如果再有一个数据元素入队就会出现溢出。但事实上队列中并未满,还有空闲空间,把这种现象称为“假溢出” 。这是由于队列“队尾入队头出”的操作原则造成的。解决假溢出的方法是将顺序队列看成是首尾相接的循环结构,头尾指示器的关系不变,这种队列叫循环顺序队列( Circular sequenceQueue )。循环队列如图所示。

  当队尾指示器 rear 到达数组的上限时, 如果还有数据元素入队并且数组的第0 个空间空闲时,队尾指示器 rear 指向数组的 0 端。所以,队尾指示器的加 1 操作修改为:rear = (rear + 1) % maxsize。队头指示器的操作也是如此。当队头指示器 front 到达数组的上限时,如果还有数据元素出队,队头指示器 front 指向数组的 0 端。所以,队头指示器的加1 操作修改为:front = (front + 1) % maxsize。循环顺序队列操作示意图如图所示。

  由图可知,队尾指示器 rear 的值不一定大于队头指示器 front 的值,并且队满和队空时都有 rear=front。也就是说,队满和队空的条件都是相同的。解决这个问题的方法一般是少用一个空间, 如图 (d)所示, 把这种情况视为队满。所以,判断队空的条件是:rear==front,判断队满的条件是:(rear + 1) %maxsize==front。求循环队列中数据元素的个数可由(rear-front+maxsize)%maxsize公式求得。

  把循环顺序队列看作是一个泛型类,用数组来存储循环顺序队列中的元素,在类中用字段 data 来表示。用字段maxsize 表示循环顺序队列的容量, maxsize 的值可以根据实际需要修改,这通过类的构造器中的参数 size 来实现, 循环顺序队列中的元素由 data[0]开始依次顺序存放。字段 front 表示队头, front 的范围是 0 到 maxsize-1。 字段rear表示队尾, rear 的范围也是 0 到 maxsize-1。 如果循环顺序队列为空, front=rear=-1。当执行入队列操作时需要判断循环顺序队列是否已满,如果循环顺序队列已满,(rear + 1) % maxsize==front,循环顺序队列已满不能插入元素。

  循环顺序队列类 CSeqQueue<T>的实现说明如下所示。

public class CSeqQueue<T> : IQueue<T>//循环顺序队列类的实现
    {
        private int maxsize;
        private T[] data;
        private int front;
        private int rear;

        public int Maxsize
        {
            get { return maxsize; }
            set { maxsize = value; }
        }
        public int Front
        {
            get { return front; }
            set { front = value; }
        }
        public int Rear
        {
            get { return rear; }
            set { rear = value; }
        }
        public T this[int index]
        {
            get { return data[index]; }
            set { data[index] = value; }
        }
        public CSeqQueue(int size)
        {
            data = new T[size];
            maxsize = size;
            front = rear = -1;
        }
        /*
         循环顺序队列的长度取决于队尾指示器 rear 和队头指示器 front。一般情
        况下,rear 大于 front,因为入队的元素肯定比出队的元素多。特殊的情况是
        rear 到达数组的上限之后又从数组的低端开始,此时,rear 是小于 front 的。
        所以,rear 的大小要加上 maxsize。因此,循环顺序队列的长度应该是:
        (rear-front+maxsize)%maxsize。
         */
        public int GetLength()
        {
            return (rear - front + maxsize) % maxsize;
        }

        public bool IsEmpty()
        {
            return front == rear;
        }

        public void Clear()
        {
            rear = front = -1;
        }

        public bool IsFull()
        {
            return (rear + 1) % maxsize == front;
        }

        public void In(T item)
        {
            if (IsFull())
            {
                Console.WriteLine("Queue is full");
                return;
            }
            data[++rear] = item;
        }

        public T Out()
        {
            T tmp = default(T);
            if (IsEmpty())
            {
                Console.WriteLine("Queue is empty");
                return tmp;
            }
            tmp = data[++front];
            return tmp;
        }

        public T GetFront()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Queue is empty!");
                return default(T);
            }
            return data[front + 1];
        }
    }

  2、链队列

  队列的另外一种存储方式是链式存储,这样的队列称为链队列(Linked Queue)。同链栈一样,链队列通常用单链表来表示,它的实现是单链表的简化。所以,链队列的结点的结构与单链表一样。由于链队列的操作只是在一端进行,为了操作方便,把队头设在链表的头部,并且不需要头结点。

  链队列结点类(Node<T>)的实现如下所示:

public class Node<T>//链队列结点类
    {
        private T data; //数据域
        private Node<T> next; //引用域
        //构造器
        public Node(T val, Node<T> p)
        {
            data = val;
            next = p;
        }
        //构造器
        public Node(Node<T> p)
        {
            next = p;
        }
        //构造器
        public Node(T val)
        {
            data = val;
            next = null;
        }
        //构造器
        public Node()
        {
            data = default(T);
            next = null;
        }
        //数据域属性
        public T Data
        {
            get { return data; }
            set { data = value; }
        }
        //引用域属性
        public Node<T> Next
        {
            get { return next; }
            set { next = value; }
        }
    }

  把链队列看作一个泛型类,类中有两个字段 front 和 rear,表示队头指示器和队尾指示器。由于队列只能访问队头的数据元素,而链队列的队头指示器和队尾指示器又不能指示队列的元素个数,所以,与链栈一样,在类增设一个字段 num 表示链队列中结点的个数。

链队列类 LinkQueue<T>的实现说明如下所示。

public class LinkQueue<T> : IQueue<T>//链队列类的实现
    {
        private Node<T> front; //队列头指示器
        private Node<T> rear; //队列尾指示器
        private int num; //队列结点个数

        //队头属性
        public Node<T> Front
        {
            get { return front; }
            set { front = value; }
        }
        //队尾属性
        public Node<T> Rear
        {
            get { return rear; }
            set { rear = value; }
        }
        //队列结点个数属性
        public int Num
        {
            get { return num; }
            set { num = value; }
        }

        public LinkQueue()
        {
            front = rear = null;
            num = 0;
        }

        public int GetLength()
        {
            return num;
        }

        public bool IsEmpty()
        {
            return front == rear && num == 0;
        }

        public void Clear()
        {
            front = rear = null;
            num = 0;
        }

        public void In(T item)
        {
            Node<T> node = new Node<T>(item);
            if (rear == null)
            {
                rear = node;
            }
            rear.Next = node;
            rear = node;
            ++num;
        }

        public T Out()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Queue is empty!");
                return default(T);
            }
            Node<T> node = front;
            front = front.Next;
            if (front == null)
            {
                rear = null;
            }
            --num;
            return front.Data;
        }

        public T GetFront()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Queue is empty!");
                return default(T);
            }
            return front.Data;
        }
    }

C#队列的更多相关文章

  1. 消息队列——RabbitMQ学习笔记

    消息队列--RabbitMQ学习笔记 1. 写在前面 昨天简单学习了一个消息队列项目--RabbitMQ,今天趁热打铁,将学到的东西记录下来. 学习的资料主要是官网给出的6个基本的消息发送/接收模型, ...

  2. 消息队列 Kafka 的基本知识及 .NET Core 客户端

    前言 最新项目中要用到消息队列来做消息的传输,之所以选着 Kafka 是因为要配合其他 java 项目中,所以就对 Kafka 了解了一下,也算是做个笔记吧. 本篇不谈论 Kafka 和其他的一些消息 ...

  3. Beanstalkd一个高性能分布式内存队列系统

    高性能离不开异步,异步离不开队列,内部是Producer-Consumer模型的原理. 设计中的核心概念: job:一个需要异步处理的任务,是beanstalkd中得基本单元,需要放在一个tube中: ...

  4. .net 分布式架构之业务消息队列

    开源QQ群: .net 开源基础服务  238543768 开源地址: http://git.oschina.net/chejiangyi/Dyd.BusinessMQ ## 业务消息队列 ##业务消 ...

  5. 【原创经验分享】WCF之消息队列

    最近都在鼓捣这个WCF,因为看到说WCF比WebService功能要强大许多,另外也看了一些公司的招聘信息,貌似一些中.高级的程序员招聘,都有提及到WCF这一块,所以,自己也关心关心一下,虽然目前工作 ...

  6. 缓存、队列(Memcached、redis、RabbitMQ)

    本章内容: Memcached 简介.安装.使用 Python 操作 Memcached 天生支持集群 redis 简介.安装.使用.实例 Python 操作 Redis String.Hash.Li ...

  7. Java消息队列--ActiveMq 实战

    1.下载安装ActiveMQ ActiveMQ官网下载地址:http://activemq.apache.org/download.html ActiveMQ 提供了Windows 和Linux.Un ...

  8. Java消息队列--JMS概述

    1.什么是JMS JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送 ...

  9. 消息队列性能对比——ActiveMQ、RabbitMQ与ZeroMQ(译文)

    Dissecting Message Queues 概述: 我花了一些时间解剖各种库执行分布式消息.在这个分析中,我看了几个不同的方面,包括API特性,易于部署和维护,以及性能质量..消息队列已经被分 ...

  10. [数据结构]——链表(list)、队列(queue)和栈(stack)

    在前面几篇博文中曾经提到链表(list).队列(queue)和(stack),为了更加系统化,这里统一介绍着三种数据结构及相应实现. 1)链表 首先回想一下基本的数据类型,当需要存储多个相同类型的数据 ...

随机推荐

  1. NGUI制作属于自己Button

    1.收集一些PNG或PSD格式的button按钮图片(放在img文件夹下,全选) 2.选择需要制作button的图片,NGUI--Atlas Maker--Create,会出现三个命名一样的东西,1个 ...

  2. jquery笔记之属性选择器 查找以某种条件开头的页面元素

    jquery笔记之属性选择器 查找以某种条件开头的页面元素 转载:http://www.blogbus.com/amyqiong-logs/78340326.html $("div[id]& ...

  3. spring.net 配置文件需要注意换行问题

    今天在做Spring.NET Demo时写配置文件写ObjectNames 节点的Value成这样 <object id="ProxyCreator" type=" ...

  4. jquery validate表单验证插件

    1 表单验证的准备工作 在开启长篇大论之前,首先将表单验证的效果展示给大家.     1.点击表单项,显示帮助提示 2.鼠标离开表单项时,开始校验元素  3.鼠标离开后的正确.错误提示及鼠标移入时的帮 ...

  5. git pull 和本地文件冲突问题解决

    具体方法如下 git pull origin 分支 //出现错误 git stash  缓存起来 git pull origin 分支 git stash pop //还原 git stash cle ...

  6. python安装supervisor

    1.下载supervisor-3.3.1.tar.gz    http://pan.baidu.com/s/1dEPhGEd 2.下载meld3-1.0.2.tar.gz   http://pan.b ...

  7. linux设备模型

    device_driver和device必须依附总线.总线.驱动.设备最终会落实为sysfs中的一个目录.kobject对应sysfs的一个目录. attribute直接落实sysfs中的一个文件,如 ...

  8. 保存配置文件的appSetting

    /// <summary> /// 保存appSetting /// </summary> /// <param name="key">appS ...

  9. css3实现逐渐变大的圆填充div背景的效果

    手机端现在的一些应用会运用上这样一个效果,就是duang的一下出现一个圆变大直到填充整个div,动感十足. 想到css3的scale属性,就自己来实现一下. <div id="bcd& ...

  10. Anjs分词器以及关键词抓取使用的方法

    首先介绍一下这个网址非常有用本文所有的关于Anjs起源来自这里请先查看一下 https://github.com/NLPchina/ansj_seg 在本次测试使用的是     import java ...