首页 > 技术文章 > C语言设计循环双端队列

caso 2020-01-16 00:43 原文

题目描述

你的实现需要支持以下操作:
MyCircularDeque(k):构造函数,双端队列的大小为k。
insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。
insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。
deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。
deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。
getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。
getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。
isEmpty():检查双端队列是否为空。
isFull():检查双端队列是否满了。

设计思路

存储结构如下:

typedef struct {
    int *data;
    int head;
    int tail;
    int capacity;
} MyCircularDeque;

实现该循环队列,需要注意以下几点:

  1. 判断队列为空? 当收尾指针相等,队列为空,head == tail
  2. 判断队列已满? 当尾指针的下一位等于头指针,队列已满,(tail + 1 + capacity) % capacity == head;
  3. 初始化队列时? 首尾指针从0开始, head = tail = 0
  4. 从头部插入数据? head 指针向前移动, head = (head - 1 + capacity) % capacity
  5. 从尾部插入数据? tail 指针向后移动, tail = (tail + 1) % capacity
  6. 从头部删除数据? head 指针向后移动, head = (head + 1) % capacity
  7. 从尾部删除数据? tail 指针向前移动, tail = (tail - 1 + capacity) % capacity
  8. 从尾部读取数据? 考虑头部插入(head 前移一位)和尾部插入(插入后,tail后移一位),所以读取data[(tail - 1 + capacity) % capacity]

代码实现

本题目选自 Leetcode 641 题,以下为 C 语言实现代码
实现细节学习引用 Leetcode 题解,题解入口

typedef struct {
    int *data;
    int head;
    int tail;
    int capacity;
} MyCircularDeque;

// 建立双端循环队列及初始化
MyCircularDeque* myCircularDequeCreate(int k) {
    MyCircularDeque *Dq = (MyCircularDeque *)malloc(sizeof(MyCircularDeque));
    if(!Dq)
        return NULL;
    Dq -> data = (int *)malloc(sizeof(int) * (k + 1));
    if(!Dq -> data)
        return NULL;
    Dq -> head = 0;
    Dq -> tail = 0;
    Dq -> capacity = k + 1;
    return Dq;
}

bool myCircularDequeIsFull(MyCircularDeque* obj);
// 从队头插入数据,成功返回true
bool myCircularDequeInsertFront(MyCircularDeque* obj, int value) {
    if(myCircularDequeIsFull(obj)) {
        return false;
    }
    obj -> head = (obj -> head - 1 + obj -> capacity) % obj -> capacity;
    obj -> data[obj -> head] = value;
    return true;
}

// 从队尾插入数据,成功返回true
bool myCircularDequeInsertLast(MyCircularDeque* obj, int value) {
    if(myCircularDequeIsFull(obj)) {
        return false;
    }
    obj -> data[obj -> tail] = value;
    obj -> tail = (obj -> tail + 1) % obj -> capacity;
    return true;
}

bool myCircularDequeIsEmpty(MyCircularDeque* obj);
// 从队头删除数据,成功返回true
bool myCircularDequeDeleteFront(MyCircularDeque* obj) {
    if(myCircularDequeIsEmpty(obj)) {
        return false;
    }
    obj -> head = (obj -> head + 1) % obj -> capacity;
    return true;
}

//从队尾删除数据,成功返回true
bool myCircularDequeDeleteLast(MyCircularDeque* obj) {
    if(myCircularDequeIsEmpty(obj)) {
        return false;
    }
    obj -> tail = (obj -> tail - 1 + obj -> capacity) % obj -> capacity;
    return true;
}

// Get the front item from the deque
int myCircularDequeGetFront(MyCircularDeque* obj) {
    if(myCircularDequeIsEmpty(obj)) {
        return -1;
    }
    return obj -> data[obj -> head];
}

// Get the last item from the deque
int myCircularDequeGetRear(MyCircularDeque* obj) {
    if(myCircularDequeIsEmpty(obj)) {
        return -1;
    }
    return obj -> data[(obj -> tail - 1 + obj -> capacity) % obj -> capacity];
}

// Checks whether the circular deque is empty or not.
bool myCircularDequeIsEmpty(MyCircularDeque* obj) {
    return (obj -> head == obj -> tail);
}

// Checks whether the circular deque is full or not
bool myCircularDequeIsFull(MyCircularDeque* obj) {
    return ((obj -> tail + 1) % obj -> capacity == obj -> head);
}

void myCircularDequeFree(MyCircularDeque* obj) {
    free(obj -> data);
    obj -> data = NULL;
    free(obj);
    obj = NULL;
}

推荐阅读