基于C#实现双端队列

话说有很多数据结构都在玩组合拳,比如说:块状链表,块状数组,当然还有本篇的双端队列,是的,它就是栈和队列的组合体。

一、概念

我们知道普通队列是限制级的一端进,另一端出的 FIFO 形式,栈是一端进出的 LIFO 形式,而双端队列就没有这样的限制,也就是我们可以在队列两端进行插入或者删除操作。

二、编码

2.1、定义结构体

通常情况下,队列的内部都是采用数组来实现,而且带有两个指针 head 和 tail 来指向数组的区间段,为了充分利用数组空间,我们也会用 % 来实现逻辑上的循环数组,如下图。

csharp 复制代码
 public class MyQueue
 {
     public int head;

     public int tail;

     public int maxSize;

     public int size;

     public T[] list;

     public MyQueue()
     {
         head = tail = size = 0;
         maxSize = 3;
         list = new T[maxSize];
     }
 }

这里有一个注意的细节就是"size 字段",它是为了方便统计队列是否为满或者队列是否为空。

2.2、队尾入队

刚才也说了,双端队列是可以在队列的两端进行插入和删除的,要注意的是我们用 head 和 tail 指针的时候,tail 指针是指向元素的下一个位置,

而 head 指针是指向当前元素,所以我们可以从 tail 端 push 数据的时候只要"顺时针"下移一个位置即可。

csharp 复制代码
 /// <summary>
 /// 队尾入队
 /// </summary>
 /// <param name="t"></param>
 /// <returns></returns>
 public bool Push_Tail(T t)
 {
     //判断队列是否已满
     if (myQueue.size == myQueue.list.Length)
         return false;

     myQueue.list[myQueue.tail] = t;

     //顺时针旋转
     myQueue.tail = (myQueue.tail + 1) % myQueue.maxSize;

     myQueue.size++;

     return true;
 }

2.3、队尾出队

和队尾入队一样,我们只要将 tail 指针"逆时针"下移一个位置,当然有一个细节需要注意,就是 tail 指针有存在负值的情况,毕竟我们是做"--操作"的,所以需要 tail+maxSize,即:

csharp 复制代码
myQueue.tail = (--myQueue.tail + myQueue.maxSize) % myQueue.maxSize;
csharp 复制代码
 /// <summary>
 /// 队尾出队
 /// </summary>
 /// <param name="edges"></param>
 /// <param name="t"></param>
 public T Pop_Tail()
 {
     //判断队列是否已空
     if (myQueue.size == 0)
         return default(T);

     //逆时针旋转(防止负数)
     myQueue.tail = (--myQueue.tail + myQueue.maxSize) % myQueue.maxSize;

     var temp = myQueue.list[myQueue.tail];

     //赋予空值
     myQueue.list[myQueue.tail] = default(T);

     myQueue.size--;

     return temp;
 }

2.4、队首入队

从 head 端来说,我们 push 数据的时候是 head 指针"逆时针"旋转,要注意的是同样要防止负数的产生,并且 head 指针是指向当前元素。

csharp 复制代码
 /// <summary>
 /// 队首入队
 /// </summary>
 /// <param name="t"></param>
 /// <returns></returns>
 public bool Push_Head(T t)
 {
     //判断队列是否已满
     if (myQueue.size == myQueue.list.Length)
         return false;

     //逆时针旋转(防止负数产生)
     myQueue.head = (--myQueue.head + myQueue.maxSize) % myQueue.maxSize;

     //赋予元素
     myQueue.list[myQueue.head] = t;

     myQueue.size++;

     return true;
 }

2.5、队首出队

说到这个方法,我想大家应该都懂了双端队列的大概流程了,这个方法我也不用赘叙了。

csharp 复制代码
 /// <summary>
 /// 队首出队
 /// </summary>
 /// <param name="edges"></param>
 /// <param name="t"></param>
 public T Pop_Head()
 {
     //判断队列是否已空
     if (myQueue.size == 0)
         return default(T);

     //获取队首元素
     var temp = myQueue.list[myQueue.head];

     //原来单位的值赋默认值
     myQueue.list[myQueue.head] = default(T);

     //顺时针旋转
     myQueue.head = (myQueue.head + 1) % myQueue.maxSize;

     myQueue.size--;

     return temp;
 }

从上面的四个方法可以看出:

当我们只使用 Push_Tail 和 Pop_Tail 的话,那它就是栈。

当我们只使用 Push_Tail 和 Pop_Head 的话,那它就是队列。

最后是全部代码:

csharp 复制代码
 using System.Net;
 using System;
 using System.IO;
 using System.Collections.Generic;
 using System.Text;
 using System.Drawing;
 using System.Drawing.Imaging;
 
 class Program
 {
     static void Main(string[] args)
     {
         DoubleQueue<int> queue = new DoubleQueue<int>();
 
         queue.Push_Tail(10);
         queue.Push_Tail(20);
         queue.Push_Tail(30);
 
         queue.Pop_Tail();
         queue.Pop_Tail();
         queue.Pop_Tail();
 
         queue.Push_Tail(10);
         queue.Push_Head(20);
         queue.Push_Head(30);
         queue.Push_Head(30);
 
         queue.Pop_Tail();
         queue.Pop_Tail();
         queue.Pop_Head();
 
         queue.Push_Head(40);
         queue.Push_Tail(50);
         queue.Push_Tail(60);
     }
 }
 
 /// <summary>
 /// 双端队列
 /// </summary>
 public class DoubleQueue<T>
 {
     public class MyQueue
     {
         public int head;
 
         public int tail;
 
         public int maxSize;
 
         public int size;
 
         public T[] list;
 
         public MyQueue()
         {
             head = tail = size = 0;
             maxSize = 3;
             list = new T[maxSize];
         }
     }
 
     MyQueue myQueue = new MyQueue();
 
     /// <summary>
     /// 队尾入队
     /// </summary>
     /// <param name="t"></param>
     /// <returns></returns>
     public bool Push_Tail(T t)
     {
         //判断队列是否已满
         if (myQueue.size == myQueue.list.Length)
             return false;
 
         myQueue.list[myQueue.tail] = t;
 
         //顺时针旋转
         myQueue.tail = (myQueue.tail + 1) % myQueue.maxSize;
 
         myQueue.size++;
 
         return true;
     }
 
     /// <summary>
     /// 队尾出队
     /// </summary>
     /// <param name="edges"></param>
     /// <param name="t"></param>
     public T Pop_Tail()
     {
         //判断队列是否已空
         if (myQueue.size == 0)
             return default(T);
 
         //逆时针旋转(防止负数)
         myQueue.tail = (--myQueue.tail + myQueue.maxSize) % myQueue.maxSize;
 
         var temp = myQueue.list[myQueue.tail];
 
         //赋予空值
         myQueue.list[myQueue.tail] = default(T);
 
         myQueue.size--;
 
         return temp;
     }
 
     /// <summary>
     /// 队首入队
     /// </summary>
     /// <param name="t"></param>
     /// <returns></returns>
     public bool Push_Head(T t)
     {
         //判断队列是否已满
         if (myQueue.size == myQueue.list.Length)
             return false;
 
         //逆时针旋转(防止负数产生)
         myQueue.head = (--myQueue.head + myQueue.maxSize) % myQueue.maxSize;
 
         //赋予元素
         myQueue.list[myQueue.head] = t;
 
         myQueue.size++;
 
         return true;
     }
 
     /// <summary>
     /// 队首出队
     /// </summary>
     /// <param name="edges"></param>
     /// <param name="t"></param>
     public T Pop_Head()
     {
         //判断队列是否已空
         if (myQueue.size == 0)
             return default(T);
 
         //获取队首元素
         var temp = myQueue.list[myQueue.head];
 
         //原来单位的值赋默认值
         myQueue.list[myQueue.head] = default(T);
 
         //顺时针旋转
         myQueue.head = (myQueue.head + 1) % myQueue.maxSize;
 
         myQueue.size--;
 
         return temp;
     }
 }
相关推荐
天之涯上上几秒前
JAVA开发 在 Spring Boot 中集成 Swagger
java·开发语言·spring boot
2402_857583491 分钟前
“协同过滤技术实战”:网上书城系统的设计与实现
java·开发语言·vue.js·科技·mfc
爱学习的白杨树8 分钟前
MyBatis的一级、二级缓存
java·开发语言·spring
OTWOL13 分钟前
两道数组有关的OJ练习题
c语言·开发语言·数据结构·c++·算法
问道飞鱼17 分钟前
【前端知识】强大的js动画组件anime.js
开发语言·前端·javascript·anime.js
拓端研究室17 分钟前
R基于贝叶斯加法回归树BART、MCMC的DLNM分布滞后非线性模型分析母婴PM2.5暴露与出生体重数据及GAM模型对比、关键窗口识别
android·开发语言·kotlin
Code成立18 分钟前
《Java核心技术I》Swing的网格包布局
java·开发语言·swing
Auc2423 分钟前
使用scrapy框架爬取微博热搜榜
开发语言·python
QQ同步助手30 分钟前
C++ 指针进阶:动态内存与复杂应用
开发语言·c++
凯子坚持 c36 分钟前
仓颉编程语言深入教程:基础概念和数据类型
开发语言·华为