基于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;
     }
 }
相关推荐
铁松溜达py1 分钟前
编译器/工具链环境:GCC vs LLVM/Clang,MSVCRT vs UCRT
开发语言·网络
everyStudy1 分钟前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
C-SDN花园GGbond2 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
迷迭所归处2 小时前
C++ —— 关于vector
开发语言·c++·算法
架构文摘JGWZ3 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
leon6253 小时前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
锦亦之22334 小时前
QT+OSG+OSG-earth如何在窗口显示一个地球
开发语言·qt
我是苏苏4 小时前
Web开发:ABP框架2——入门级别的增删改查Demo
java·开发语言
姜太公钓鲸2334 小时前
c++ static(详解)
开发语言·c++
菜菜想进步4 小时前
内存管理(C++版)
c语言·开发语言·c++