经典数据结构和算法 双端队列 java

本文探讨了双端队列这一数据结构,它是栈和队列的结合体,允许在两端进行插入和删除操作。文章通过Java代码详细解释了如何定义结构体、队尾入队、队尾出队、队首入队和队首出队的过程,并指出当仅使用特定方法时,双端队列可以模拟栈或队列的行为。
摘要由CSDN通过智能技术生成

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

栈和队列的组合体。

一:概念

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

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

二:编码

1:定义结构体

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

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

 

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:队尾入队

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

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

/// <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;
}

 


3:队尾出队

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

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

/// <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;
}

 

4:队首入队

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

/// <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;
 }

 

 

5:队首出队

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

/// <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的话,那它就是队列。

最后是全部代码:

 

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;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值