• 经典算法题每日演练——第十九题 双端队列


         话说大学的时候老师说妹子比工作重要~,工作可以再换,妹子这个。。。所以。。。这两个月也就一直忙着Fall in love,嗨,慢慢调整心态吧,

    这篇就选一个简单的数据结构聊一聊,话说有很多数据结构都在玩组合拳,比如说:块状链表,块状数组,当然还有本篇的双端队列,是的,它就是

    栈和队列的组合体。

    一:概念

         我们知道普通队列是限制级的一端进,另一端出的FIFO形式,栈是一端进出的LIFO形式,而双端队列就没有这样的限制级,也就是我们可以在

    队列两端进行插入或者删除操作。

    二:编码

    1:定义结构体

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

    现逻辑上的循环数组,如下图。

     1     public class MyQueue
     2     {
     3         public int head;
     4 
     5         public int tail;
     6 
     7         public int maxSize;
     8 
     9         public int size;
    10 
    11         public T[] list;
    12 
    13         public MyQueue()
    14         {
    15             head = tail = size = 0;
    16             maxSize = 3;
    17             list = new T[maxSize];
    18         }
    19     }

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

    2:队尾入队

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

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

     1     /// <summary>
     2     /// 队尾入队
     3     /// </summary>
     4     /// <param name="t"></param>
     5     /// <returns></returns>
     6     public bool Push_Tail(T t)
     7     {
     8         //判断队列是否已满
     9         if (myQueue.size == myQueue.list.Length)
    10             return false;
    11 
    12         myQueue.list[myQueue.tail] = t;
    13 
    14         //顺时针旋转
    15         myQueue.tail = (myQueue.tail + 1) % myQueue.maxSize;
    16 
    17         myQueue.size++;
    18 
    19         return true;
    20     }


    3:队尾出队

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

    所以需要tail+maxSize,即:myQueue.tail = (--myQueue.tail + myQueue.maxSize) % myQueue.maxSize;

     1     /// <summary>
     2     /// 队尾出队
     3     /// </summary>
     4     /// <param name="edges"></param>
     5     /// <param name="t"></param>
     6     public T Pop_Tail()
     7     {
     8         //判断队列是否已空
     9         if (myQueue.size == 0)
    10             return default(T);
    11 
    12         //逆时针旋转(防止负数)
    13         myQueue.tail = (--myQueue.tail + myQueue.maxSize) % myQueue.maxSize;
    14 
    15         var temp = myQueue.list[myQueue.tail];
    16 
    17         //赋予空值
    18         myQueue.list[myQueue.tail] = default(T);
    19 
    20         myQueue.size--;
    21 
    22         return temp;
    23     }

    4:队首入队

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

     1     /// <summary>
     2     /// 队首入队
     3     /// </summary>
     4     /// <param name="t"></param>
     5     /// <returns></returns>
     6     public bool Push_Head(T t)
     7     {
     8         //判断队列是否已满
     9         if (myQueue.size == myQueue.list.Length)
    10             return false;
    11 
    12         //逆时针旋转(防止负数产生)
    13         myQueue.head = (--myQueue.head + myQueue.maxSize) % myQueue.maxSize;
    14 
    15         //赋予元素
    16         myQueue.list[myQueue.head] = t;
    17 
    18         myQueue.size++;
    19 
    20         return true;
    21     }

    5:队首出队

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

     1     /// <summary>
     2     /// 队首出队
     3     /// </summary>
     4     /// <param name="edges"></param>
     5     /// <param name="t"></param>
     6     public T Pop_Head()
     7     {
     8         //判断队列是否已空
     9         if (myQueue.size == 0)
    10             return default(T);
    11 
    12         //获取队首元素
    13         var temp = myQueue.list[myQueue.head];
    14 
    15         //原来单位的值赋默认值
    16         myQueue.list[myQueue.head] = default(T);
    17 
    18         //顺时针旋转
    19         myQueue.head = (myQueue.head + 1) % myQueue.maxSize;
    20 
    21         myQueue.size--;
    22 
    23         return temp;
    24     }


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

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

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

    最后是全部代码:

    View Code
      1 using System.Net;
      2 using System;
      3 using System.IO;
      4 using System.Collections.Generic;
      5 using System.Text;
      6 using System.Drawing;
      7 using System.Drawing.Imaging;
      8 
      9 class Program
     10 {
     11     static void Main(string[] args)
     12     {
     13         DoubleQueue<int> queue = new DoubleQueue<int>();
     14 
     15         queue.Push_Tail(10);
     16         queue.Push_Tail(20);
     17         queue.Push_Tail(30);
     18 
     19         queue.Pop_Tail();
     20         queue.Pop_Tail();
     21         queue.Pop_Tail();
     22 
     23         queue.Push_Tail(10);
     24         queue.Push_Head(20);
     25         queue.Push_Head(30);
     26         queue.Push_Head(30);
     27 
     28         queue.Pop_Tail();
     29         queue.Pop_Tail();
     30         queue.Pop_Head();
     31 
     32         queue.Push_Head(40);
     33         queue.Push_Tail(50);
     34         queue.Push_Tail(60);
     35     }
     36 }
     37 
     38 /// <summary>
     39 /// 双端队列
     40 /// </summary>
     41 public class DoubleQueue<T>
     42 {
     43     public class MyQueue
     44     {
     45         public int head;
     46 
     47         public int tail;
     48 
     49         public int maxSize;
     50 
     51         public int size;
     52 
     53         public T[] list;
     54 
     55         public MyQueue()
     56         {
     57             head = tail = size = 0;
     58             maxSize = 3;
     59             list = new T[maxSize];
     60         }
     61     }
     62 
     63     MyQueue myQueue = new MyQueue();
     64 
     65     /// <summary>
     66     /// 队尾入队
     67     /// </summary>
     68     /// <param name="t"></param>
     69     /// <returns></returns>
     70     public bool Push_Tail(T t)
     71     {
     72         //判断队列是否已满
     73         if (myQueue.size == myQueue.list.Length)
     74             return false;
     75 
     76         myQueue.list[myQueue.tail] = t;
     77 
     78         //顺时针旋转
     79         myQueue.tail = (myQueue.tail + 1) % myQueue.maxSize;
     80 
     81         myQueue.size++;
     82 
     83         return true;
     84     }
     85 
     86     /// <summary>
     87     /// 队尾出队
     88     /// </summary>
     89     /// <param name="edges"></param>
     90     /// <param name="t"></param>
     91     public T Pop_Tail()
     92     {
     93         //判断队列是否已空
     94         if (myQueue.size == 0)
     95             return default(T);
     96 
     97         //逆时针旋转(防止负数)
     98         myQueue.tail = (--myQueue.tail + myQueue.maxSize) % myQueue.maxSize;
     99 
    100         var temp = myQueue.list[myQueue.tail];
    101 
    102         //赋予空值
    103         myQueue.list[myQueue.tail] = default(T);
    104 
    105         myQueue.size--;
    106 
    107         return temp;
    108     }
    109 
    110     /// <summary>
    111     /// 队首入队
    112     /// </summary>
    113     /// <param name="t"></param>
    114     /// <returns></returns>
    115     public bool Push_Head(T t)
    116     {
    117         //判断队列是否已满
    118         if (myQueue.size == myQueue.list.Length)
    119             return false;
    120 
    121         //逆时针旋转(防止负数产生)
    122         myQueue.head = (--myQueue.head + myQueue.maxSize) % myQueue.maxSize;
    123 
    124         //赋予元素
    125         myQueue.list[myQueue.head] = t;
    126 
    127         myQueue.size++;
    128 
    129         return true;
    130     }
    131 
    132     /// <summary>
    133     /// 队首出队
    134     /// </summary>
    135     /// <param name="edges"></param>
    136     /// <param name="t"></param>
    137     public T Pop_Head()
    138     {
    139         //判断队列是否已空
    140         if (myQueue.size == 0)
    141             return default(T);
    142 
    143         //获取队首元素
    144         var temp = myQueue.list[myQueue.head];
    145 
    146         //原来单位的值赋默认值
    147         myQueue.list[myQueue.head] = default(T);
    148 
    149         //顺时针旋转
    150         myQueue.head = (myQueue.head + 1) % myQueue.maxSize;
    151 
    152         myQueue.size--;
    153 
    154         return temp;
    155     }
    156 }
  • 相关阅读:
    SharePoint Development
    win32- copyfile的使用
    SetWindowHookEx的复习
    C++ vector的使用
    关于char * 和 char [] 的一点理解
    CreateThread
    C++字符串大写字母转小写字母
    字符串逆序
    使用RegSetValueEx创建键值
    EnumColorProfiles WcsGetDefaultColorProfile WcsSetDefaultColorProfile的使用
  • 原文地址:https://www.cnblogs.com/huangxincheng/p/2971671.html
Copyright © 2020-2023  润新知