数据结构学习——队列

考试前复习下数据结构,把一些知识点整理在这!主要参考了殷人昆主编的《数据结构(用面向对象方法与C++语言描述)》这本书,以及中山大学刘聪老师的课件内容!


概念与性质

一些概念

队列是一种操作受限制的线性表,它只允许在表的一端插入,在另一端删除。

  • 队尾:允许插入的一端
  • 队头:允许删除的一端

队列的性质

由于队列是一种运算受限的线性表,只允许在表的一端进行插入,另一端进行删除,所以队列具有一些特殊的性质。给定队列Q=(a1, a2, …, an),则最先入队的元素a1为队头,最后入队的元素an为队尾,按a1, a2, …, an的顺序入队,出队的顺序与入队的一致,即a1先出队,an最后出队,就如同在车站排队买票一样。这样的性质可以概括为先进先出(FIFO)

队列的操作

队列有几个主要的操作:

  • 建立一个空队列(构造函数Queue());
  • 在队尾添加一个新元素,如果队列未满(append() );
  • 在队头删除一个元素,如果队列不空(serve() );
  • 检查队列是否空(isEmpty());
  • 取得队头元素,如果队列不空(retrieve())。

队列的抽象数据类型主要有两种存储表示:基于数组的存储表示(顺序队列)和基于链表的存储表示(链式队列)。


顺序队列

利用一个一维数组作为队列元素的存储结构,并设置两个指针front和rear,分别指示队列的队头和队尾的位置。
其中,front指向队头元素所在位置,rear指向队尾位置的后一位置。有元素入队时,更新rear指针;有元素出队时,更新front指针。


那么,问题来了。当rear == maxSize时,队列满,如果再加入新元素,就会产生“溢出”。但是,这种“溢出”可能是假溢出,因为数组的前端可能还有空位置。那么,要怎么解决这种浪费空间的问题呢?

我们可以采用循环队列的存储方式,即把数组的前端和后端连接起来,形成一个环形的表。
此时,每次更新两个指针时,不再是简单的+1了,而需要用到取余运算。

front = (front+1) % maxSize;
rear = (rear+1) % maxSize;

当队头指针追上队尾指针,即front == rear时,队列就变为空队列。为了区别队空和队满的状态,用(rear+1) % maxSize == front来判断是否队已满,也就是说让rear指到front的前一位置就认为队已满,所以在队满时实际空了一个元素的位置。注意:循环队列中最多只能存放maxSize-1个元素。(当然,这只是循环队列的一种实现方式,也可以使用其他方法判断队空队满)。

循环队列数组实现

// 定义两个异常处理类
class EmptyQueueException : public runtime_error {
  public:
    EmptyQueueException() : runtime_error("The queue is empty.") {}
};

class FullQueueException : public runtime_error {
  public:
    FullQueueException() : runtime_error("The queue is full.") {}
};

template <typename T>
class Queue {
  public:
    Queue(int size = 10) : rear(0), front(0), maxSize(size) {
        elements = new T[maxSize];
    }

    ~Queue() {
        delete []elements;
    }

    bool isEmpty() const {
        return front == rear;
    }

    bool isFull() const {
        return (rear+1) % maxSize == front;
    }

    int getSize() const {
        return (rear-front+maxSize) % maxSize;
    }

    T retrieve() {
        if (isEmpty()) {
            throw EmptyQueueException();
        }
        return elements[front];
    }

    void append(const T& x) {
        if (isFull()) {
            throw FullQueueException();
        }
        elements[rear] = x;
        rear = (rear+1) % maxSize;
    }

    T serve() {
        if (isEmpty()) {
            throw EmptyQueueException();
        }
        T x = elements[front];
        front = (front + 1) % maxSize;
        return x;
    }

  private:
    int rear;      // 队尾指针
    int front;     // 队头指针
    T * elements;  // 存放队列元素的数组
    int maxSize;   // 队列可容纳的最大元素个数
};

链式队列

链式队列是基于单链表的一种存储方式。

队列的队头指针指向单链表的第一个结点,队尾指针指向单链表的最后一个结点。
用单链表表示的链式队列适用于数据元素变动比较大的情形,而且不存在队列满而溢出的情况。

// 定义异常处理类
class EmptyQueueException : public runtime_error {
  public:
    EmptyQueueException() : runtime_error("The queue is empty.") {}
};

template <typename T>
class Queue {
  public:
    Queue() : rear(NULL), front(NULL) {}

    ~Queue() {
        Node* p;
      while (front != NULL) {
        p = front;
        front = front->next;
        delete p;
      }
    }

    bool isEmpty() const {
        return front == NULL;
    }

    int getSize() const {
      Node* p = front;
      int count = 0;
        while (p != NULL) {
        p = p->next;
        count++;
      }
      return count;
    }

    T retrieve() {
        if (isEmpty()) {
            throw EmptyQueueException();
        }
        return front->data;
    }

    void append(const T& x) {
        if (front == NULL) {
        front = rear = new Node;
        front->data = x;
        front->next = NULL;
        return;
      }
      Node *newNode = new Node;
      newNode->next = NULL;
      newNode->data = x;
      rear->next = newNode;
      rear = rear->next;
    }

    T serve() {
        if (isEmpty()) {
            throw EmptyQueueException();
        }
        Node* temp = front;
      T firstData = front->data;
      front = front->next;
      delete temp;
      return firstData;
    }

  private:
    struct Node {
      T data;
      Node * next;
    };
    Node* front;  // 队头指针
    Node* rear;   // 队尾指针
};

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值