数据结构《21》----2014 WAP 初试题----Immutable queue

本文深入探讨了如何使用两个栈实现不可变队列,并详细解析了析构函数优化与逆操作实现。通过实例代码展示,揭示了不同版本效率的巨大差异,提供了一种简洁高效的解决方案。

2014 WAP初试题----实现一个不可变的队列:

看似很简单。。实则,不同的版本效率的差距可能是巨大的。。甚至难以想象。。

之前用STL库的queue进行了对比,差别非常大。。


用上一篇文章的immutable stack 来实现 immutable queue.

其实就是用两个栈实现队列,具体的思想可以参考 编程之美。。

注意:代码中析构函数那一段代码的目的主要是为了避免析构函数递归调用时递归深度太大。。

通过将链表后序的节点的智能指针复制到局部的vector中,通过vector的析构函数自动调用成员的析构函数的规则来实现。。

可能有点绕,大家可以仔细琢磨以下。。


附加题:

实现一个reverse操作(这道题据说坑了不少同学,其实非常地简单,一句话就能搞定)

//copyrigt @ L.J.SHOU May.25, 2014
#include 
using namespace std;

/**
 * This class is a functional datatype, representing 
 *      an immutable first-in-first-out(FIFO) queue of objects.
 *
 * amortized O(1) cost
 *
 * implementation details:
 * 1. two lists are used as stacks to mimic queue
 *    front: for dequeue 
 *    rear:  for enqueue
 *    Once front is empty, rear are reversed and added to front
 *    so front is empty, if and only if rear is empty too.
 *
 * 2. std::shared_ptr is used to collect garbage
 */
template
class immutable_queue
{
  class List;
public:
  immutable_queue();
  immutable_queue(List front, List rear);
  ~immutable_queue();
  immutable_queue enqueue(const T &element);
  immutable_queue dequeue();
  immutable_queue reverse();
  immutable_queue append(immutable_queue & rhs) {
    immutable_queue res = *this;
    immutable_queue temp = rhs;
    while(!temp.empty())  {
      res = res.enqueue(temp.peek());
      temp = temp.dequeue();
    }
    return res;
  }
  T getMax();
  T peek();
  int size();
  bool empty() { 
    return front_.empty() && rear_.empty();
  }

private:
  List front_, rear_; // two stacks to mimic queue

  // utility list class
  class List
  {
    struct Node
    {
      Node(T x, shared_ptr &tail) 
        : val_(x), next_(tail), max_(x){
          if(tail)
            max_ = max(val_, tail->max_); 
        }

      /** 
       * To avoid too deep recursive call
       *
       * Normally, default destructor provided by c++ compiler is enough
       * but in some cases, where the list is too long,
       * the recursive call of this function would be too deep,
       * leading a stack overflow error.
       */
      ~Node() {
        shared_ptr *ptr = &next_, *next(nullptr);
        vector > vec;

        while(*ptr) {
          if((*ptr).unique() == false) break;
          next = &((*ptr)->next_);
          vec.push_back(*ptr);
          *ptr = nullptr;
          ptr = next;
        }
      }
      T val_;
      T max_;
      shared_ptr next_;
    };

  public:
    List(): count_(0), head_(nullptr) {}
    List(T x, List tail): head_(make_shared(x, tail.head_)){
      count_ = 1 + tail.count_;
    }

    int size() { return count_;}

    bool empty() { return count_ == 0;}

    T getMax() { assert(!empty()); return head_->max_;}

    T getHead() { assert(!empty()); return head_->val_;}

    List getTail() { assert(!empty()); return List(head_->next_, count_-1);}

    List addHead(const T &x) {
      return List(x, *this);
    }

    // *this should not be changed
    List reverse() {
      List new_list;
      List it = *this; // make a "copy" first
      for(int i=0; i tail, int count) 
      : head_(tail), count_(count) {}

    shared_ptr head_;
    int count_;
  };

};

/**
 * requires default ructor
 */
template
immutable_queue::immutable_queue()
{
  front_ = List();
  rear_ = List();
}

template
immutable_queue::immutable_queue(List front, List rear)
{
  // front is empty only if rear is empty too
  if(front.empty() && !rear.empty()) {
    this->front_ = rear.reverse();
    this->rear_ = List();
  }
  else {
    this->front_ = front;
    this->rear_ = rear;
  }
  front = List();
  rear = List();
}

/**
 * default destructor
 */
template
immutable_queue::~immutable_queue()
{
}

/**
 * Returns the queue that adds an item into the tail of this queue without
 * modifying this queue.
 * 
 * 
 * e.g.
 *  When this queue represents the queue (2,1,2,2,6) and we enqueue the value 4 into this queue,
 *  this method returns a new queue (2,1,2,2,6,4)
 *  and this object still represents the queue (2,1,2,2,6)
 * 
* * @param e * @return */ template immutable_queue immutable_queue::enqueue(const T &element) { //make this method faster return immutable_queue(front_, rear_.addHead(element)); } /** * Returns the queue that removes the object at the head of this queue * without modifying this queue. * *
 * e.g.
 *  When this queue represents the queue (7,1,3,3,5,1) .
 *  this method returns a new queue (1,3,3,5,1)
 *  and this object still represents the queue (7,1,3,3,5,1)
 * 
* * If this queue is empty, throws range_error * * @param e * @return */ template immutable_queue immutable_queue::dequeue() { //make this method faster if(empty()) { throw range_error("Opps, this queue is empty, nothing to dequeue"); } return immutable_queue(front_.getTail(), rear_); } template immutable_queue immutable_queue::reverse() { return immutable_queue(rear_, front_); } template T immutable_queue::getMax() { //make this method faster if(empty()) { throw range_error("Opps, this queue is empty"); } T res = front_.getMax(); if(!rear_.empty()) res = max(res, rear_.getMax()); return res; } /** * Looks at the object which is the head of this queue without removing it * from the queue. * *
 * e.g.
 *  When this queue represents the queue (7,1,3,3,5,1) .
 *  this method returns 7 and this object still represents the queue (7,1,3,3,5,1)
 * 
* * If this queue is empty, throws range_error * * @param e * @return */ template inline T immutable_queue::peek() { if(empty()) { throw range_error("Opps, this queue is empty. nothing to peek"); } return front_.getHead(); } /** * Return the number of objectes in this queue * @return */ template inline int immutable_queue::size() { return front_.size() + rear_.size(); } int main(void) { immutable_queue p1; p1 = p1.enqueue(1); p1 = p1.enqueue(2); p1 = p1.enqueue(3); assert(p1.size() == 3); immutable_queue p2 = p1.enqueue(0); p2 = p2.enqueue(4); p2 = p2.enqueue(5); p2 = p2.enqueue(6); assert(p2.size() == 7); assert(p1.size() == 3); p1 = p1.append(p2); assert(p1.size() == 10); assert(p2.getMax() == 6); immutable_queue temp = p2.reverse(); while(!temp.empty()) { cout << temp.peek() << " "; temp = temp.dequeue(); } cout << endl; return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值