13. 双端队列

一、什么是双端队列

  双端队列是只允许从两端插入和删除的线性表。

双端队列

ADT Deque
{
Data:
    双端队列D∈Deque, 队头元素Item∈ElementType;
Operation:
    Deque CreateDeque(void);                        // 生成一个空的双端队列
    int IsEmpty(Deque PtrD);                        // 双端队列是否为空
    void OfferFirst(Deque PtrD, ElementType X);     // 队头添加元素
    void OfferLast(Deque PtrD, ElementType X);      // 队尾添加元素
    ElementType PollFirst(Deque PtrD);              // 队头删除元素
    ElementType PollLast(Deque PtrD);               // 队尾删除元素
    ElementType PeekFirst(Deque PtrD);              // 查看队头元素
    ElementType PeekLast(Deque PtrD);               // 查看队尾元素
} ADT Deque;

二、双端队列的顺序存储实现

2.1、双端队列的顺序存储

顺序双端队列

#define MAX_SIZE 10

typedef int ElementType;

typedef struct DNode
{
    int Data[MAX_SIZE];
    int Front;
    int Rear;
}DNode, * Deque;

这里,队列,我们只使用 MAX_SIZE - 1 个元素,如果使用 MAX_SIZE 元素,则 Front == Rear 是无法判断队列是空的还是满的。如果使用 MAX_SIZE - 1 个元素,则 Front == Rear 是队列是空的,(Rear + 1) % MAX_SIZE == Front 时,队列是满的。

2.2、创建空的双端队列

/**
 * @brief 创建一个带头节点的双端队列
 * 
 * @return Deque 指向双端队列的指针
 */
Deque CreateDeque(void)
{
    Deque PtrD = (Deque)malloc(sizeof(DNode));
    memset(PtrD->Data, 0, sizeof(ElementType) * MAX_SIZE);
    PtrD->Front = PtrD->Rear = 0;

    return PtrD;
}

2.3、判断双端队列是否为空

/**
 * @brief 判断双端队列是否为空
 * 
 * @param PtrD 双端队列
 * @return int 0: 非空; 1: 空
 */
int IsEmpty(Deque PtrD)
{
    return PtrD->Front == PtrD->Rear;
}

2.4、队头插入元素

/**
 * @brief 队头插入元素
 * 
 * @param PtrD 双端队列
 * @param X 插入的元素
 */
void OfferFirst(Deque PtrD, ElementType X)
{
    if ((PtrD->Rear + 1) % MAX_SIZE == PtrD->Front)
    {
        printf("队列已满!\n");
        return;
    }
    PtrD->Data[PtrD->Front] = X;
    PtrD->Front = (PtrD->Front - 1 > 0) ? (PtrD->Front - 1) : (MAX_SIZE - 1);
}

2.5、队尾插入元素

/**
 * @brief 队尾插入元素
 * 
 * @param PtrD 双端队列
 * @param X 插入的元素
 */
void OfferLast(Deque PtrD, ElementType X)
{
    if ((PtrD->Rear + 1) % MAX_SIZE == PtrD->Front)
    {
        printf("队列已满!\n");
        return;
    }
    PtrD->Rear = (PtrD->Rear + 1) % MAX_SIZE;
    PtrD->Data[PtrD->Rear] = X;
}

2.6、队头删除元素

/**
 * @brief 删除队头元素
 * 
 * @param PtrD 双端队列
 * @return ElementType 队头元素
 */
ElementType PollFirst(Deque PtrD)
{
    if (PtrD->Front == PtrD->Rear)
    {
        printf("队列为空!\n");
        return NULL;
    }
    PtrD->Front = (PtrD->Front + 1) % MAX_SIZE;
    return PtrD->Data[PtrD->Front];
}

2.7、队尾删除元素

/**
 * @brief 删除队尾元素
 * 
 * @param PtrD 双端队列
 * @return ElementType 队尾元素
 */
ElementType PollLast(Deque PtrD)
{
    ElementType x = 0;
    if (PtrD->Front == PtrD->Rear)
    {
        printf("队列为空!\n");
        return NULL;
    }
    x = PtrD->Data[PtrD->Rear];
    PtrD->Rear = (PtrD->Rear - 1 > 0) ? (PtrD->Rear - 1) : (MAX_SIZE - 1);
    return x;
}

2.8、查看队头元素

/**
 * @brief 查看队头元素
 * 
 * @param PtrD 双端队列
 * @return ElementType 队头元素
 */
ElementType PeekFirst(Deque PtrD)
{
    if (PtrD->Front == PtrD->Rear)
    {
        printf("队列为空!\n");
        return NULL;
    }
    return PtrD->Data[(PtrD->Front + 1) % MAX_SIZE];
}

2.9、查看队尾元素

/**
 * @brief 查看队尾元素
 * 
 * @param PtrD 双端队列
 * @return ElementType 队尾元素
 */

ElementType PeekLast(Deque PtrD)
{
    if (PtrD->Front == PtrD->Rear)
    {
        printf("队列为空!\n");
        return NULL;
    }
    return PtrD->Data[PtrD->Rear];
}

2.10、遍历双端队列

/**
 * @brief 遍历双端队列
 * 
 * @param PtrD 双端队列
 */
void PrintDeque(Deque PtrD)
{
    if (PtrD->Front == PtrD->Rear)
    {
        return;
    }

    int i = PtrD->Front + 1;
    while (i != PtrD->Rear)
    {
        printf("%d ", PtrD->Data[i]);
        i = (i + 1) % MAX_SIZE;
    }
    printf("%d\n", PtrD->Data[PtrD->Rear]);
}

三、双端队列的链式存储实现

3.1、双端队列的链式存储

链式双端队列

typedef int ElementType;

typedef struct DNode
{
    ElementType Data;
    struct DNode * Prior;
    struct DNode * Next;
} DNode, * Deque;

3.2、创建空的双端队列

/**
 * @brief 创建一个带头节点的双端队列
 * 
 * @return Deque 指向双端队列的指针
 */
Deque CreateDeque(void)
{
    Deque PtrD = (Deque)malloc(sizeof(DNode));
    PtrD->Data = 0;
    PtrD->Next = PtrD->Prior = PtrD;

    return PtrD;
}

3.3、判断双端队列是否为空

/**
 * @brief 判断双端队列是否为空
 * 
 * @param PtrD 双端队列
 * @return int 0: 非空; 1: 空
 */
int IsEmpty(Deque PtrD)
{
    return PtrD->Next == PtrD;
}

3.4、队头插入元素

/**
 * @brief 队头插入元素
 * 
 * @param PtrD 双端队列
 * @param X 插入的元素
 */
void OfferFirst(Deque PtrD, ElementType X)
{
    Deque NewNode = (Deque)malloc(sizeof(DNode));
    NewNode->Data = X;
    NewNode->Next = PtrD->Next;
    NewNode->Prior = PtrD;

    PtrD->Next->Prior = NewNode;
    PtrD->Next = NewNode;
}

3.5、队尾插入元素

/**
 * @brief 队尾插入元素
 * 
 * @param PtrD 双端队列
 * @param X 插入的元素
 */
void OfferLast(Deque PtrD, ElementType X)
{
    Deque NewNode = (Deque)malloc(sizeof(DNode));
    NewNode->Data = X;
    NewNode->Next = PtrD;
    NewNode->Prior = PtrD->Prior;

    PtrD->Prior->Next = NewNode;
    PtrD->Prior = NewNode;
}

3.6、队头删除元素

/**
 * @brief 删除队头元素
 * 
 * @param PtrD 双端队列
 * @return ElementType 队头元素
 */
ElementType PollFirst(Deque PtrD)
{
    Deque FirstNode = PtrD->Next;
    ElementType X = FirstNode->Data;

    if (PtrD == NULL || PtrD->Next == PtrD)
    {
        printf("双端队列已空!\n");
        return NULL;
    }
  

    PtrD->Next = FirstNode->Next;
    FirstNode->Next->Prior = PtrD;
    free(FirstNode);

    return X;
}

3.7、队尾删除元素

/**
 * @brief 删除队尾元素
 * 
 * @param PtrD 双端队列
 * @return ElementType 队尾元素
 */
ElementType PollLast(Deque PtrD)
{
    Deque LastNode = PtrD->Prior;
    ElementType X = LastNode->Data;

    if (PtrD == NULL || PtrD->Next == PtrD)
    {
        printf("双端队列已空!\n");
        return NULL;
    }

    PtrD->Prior = LastNode->Prior;
    LastNode->Prior->Next = PtrD;
    free(LastNode);
    return X;
}

3.8、查看队头元素

/**
 * @brief 查看队头元素
 * 
 * @param PtrD 双端队列
 * @return ElementType 队头元素
 */
ElementType PeekFirst(Deque PtrD)
{
    if (PtrD == NULL || PtrD->Next == PtrD)
    {
        printf("双端队列已空!\n");
        return NULL;
    }

    return PtrD->Next->Data;
}

3.9、查看队尾元素

/**
 * @brief 查看队尾元素
 * 
 * @param PtrD 双端队列
 * @return ElementType 队尾元素
 */

ElementType PeekLast(Deque PtrD)
{
    if (PtrD == NULL || PtrD->Next == PtrD)
    {
        printf("双端队列已空!\n");
        return NULL;
    }

    return PtrD->Prior->Data;
}

3.10、遍历双端队列

/**
 * @brief 遍历双端队列
 * 
 * @param PtrD 双端队列
 */
void PrintDeque(Deque PtrD)
{
    if (PtrD == NULL || PtrD->Next == PtrD)
    {
        return;
    }

    Deque P = PtrD->Next;
    while (P != PtrD)
    {
        printf("%d ", P->Data);
        P = P->Next;
   }
}
posted @ 2023-07-09 20:10  星光樱梦  阅读(9)  评论(0编辑  收藏  举报