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

简介: 原文:经典算法题每日演练——第十九题 双端队列     话说大学的时候老师说妹子比工作重要~,工作可以再换,妹子这个。。。所以。。。这两个月也就一直忙着Fall in love,嗨,慢慢调整心态吧, 这篇就选一个简单的数据结构聊一聊,话说有很多数据结构都在玩组合拳,比如说:块状链表,块状数组,当然还有本篇的双端队列,是的,它就是 栈和队列的组合体。
原文: 经典算法题每日演练——第十九题 双端队列

     话说大学的时候老师说妹子比工作重要~,工作可以再换,妹子这个。。。所以。。。这两个月也就一直忙着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 }

 

目录
打赏
0
0
0
0
217
分享
相关文章
内网监控管理软件:PHP 语言队列算法揭秘
在数字化办公环境中,内网监控管理软件对企业的稳定运行和信息安全至关重要。本文深入介绍PHP中的队列算法及其在内网监控软件中的应用,包括监控数据收集、任务调度和日志记录等场景,通过代码示例展示其实现方法。队列算法可提高性能、保证数据顺序并实现异步处理,为企业提供高效的安全保障。
88 1
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
115 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
深入理解操作系统:进程调度与优先级队列算法
【9月更文挑战第25天】在操作系统的复杂世界中,进程调度是维持系统稳定运行的核心机制之一。本文将深入探讨进程调度的基本概念,分析不同的进程调度算法,并着重介绍优先级队列算法的原理和实现。通过简洁明了的语言,我们将一起探索如何优化进程调度,提高操作系统的效率和响应速度。无论你是计算机科学的初学者还是希望深化理解的专业人士,这篇文章都将为你提供有价值的见解。
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
202 2
刷算法,你应该知道的队列经典应用
文章介绍了队列的基本特性和经典应用,包括如何用队列实现栈、使用优先级队列解决Top K问题,并通过LeetCode题目示例展示了队列在算法实现中的应用。
刷算法,你应该知道的队列经典应用
【数据结构与算法】优先级队列
【数据结构与算法】优先级队列
72 0
【数据结构与算法】队列(顺序存储)
【数据结构与算法】队列(顺序存储)
125 0

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问