c ++队列模板

时间:2010-04-20 21:50:07

标签: c++ queue

好的,请原谅我凌乱的代码。下面是我的队列类。

#include <iostream>
using namespace std; 
#ifndef QUEUE
#define QUEUE

/*----------------------------------------------------------------------------
Student Class

# Methods #
Student()               // default constructor
Student(string, int)    // constructor
display()               // out puts a student

# Data Members #
Name                    // string name
Id                      // int id
----------------------------------------------------------------------------*/
class Student { 
public: 
    Student() { } 
    Student(string iname, int iid) { 
        name = iname; 
        id = iid; 
    } 
    void display(ostream &out) const { 
        out << "Student Name: " << name << "\tStudent Id: " << id
            << "\tAddress: " << this << endl;  
    }  

private: 
    string name; 
    int id; 
}; 


// define a typedef of a pointer to a student. 
typedef Student * StudentPointer;

template <typename T> 

class Queue
{
public:
    /*------------------------------------------------------------------------
    Queue Default Constructor

    Preconditions: none
    Postconditions: assigns default values for front and back to 0

    description: constructs a default empty Queue. 
    ------------------------------------------------------------------------*/
    Queue() : myFront(0), myBack(0) {}


    /*------------------------------------------------------------------------
    Copy Constructor

    Preconditions: requres a reference to a value for which you are copying
    Postconditions: assigns a copy to the parent Queue. 

    description: Copys a queue and assigns it to the parent Queue. 
    ------------------------------------------------------------------------*/
    Queue(const T & q) { 
        myFront = myBack = 0; 
        if(!q.empty()) { 
            // copy the first node
            myFront = myBack = new Node(q.front()); 
            NodePointer qPtr = q.myFront->next; 
            while(qPtr != NULL) { 
                myBack->next = new Node(qPtr->data); 
                myBack = myBack->next; 
                qPtr = qPtr->next; 
            } 
        } 

    }
    /*------------------------------------------------------------------------
    Destructor

    Preconditions: none
    Postconditions: deallocates the dynamic memory for the Queue

    description: deletes the memory stored for a Queue. 
    ------------------------------------------------------------------------*/
    ~Queue() { 
        NodePointer prev = myFront, ptr; 
        while(prev != NULL) { 
            ptr = prev->next; 
            delete prev; 
            prev = ptr; 
        } 
    } 
    /*------------------------------------------------------------------------
    Empty()

    Preconditions: none
    Postconditions: returns a boolean value. 

    description: returns true/false based on if the queue is empty or full. 
    ------------------------------------------------------------------------*/
    bool empty() const { 
        return (myFront == NULL); 
    }
    /*------------------------------------------------------------------------
    Enqueue

    Preconditions: requires a constant reference
    Postconditions: allocates memory and appends a value at the end of a queue

    description: 
    ------------------------------------------------------------------------*/
    void enqueue(const T & value) {
        NodePointer newNodePtr = new Node(value); 
        if(empty()) { 
            myFront = myBack = newNodePtr; 
            newNodePtr->next = NULL; 
        } else { 
            myBack->next = newNodePtr; 
            myBack = newNodePtr; 
            newNodePtr->next = NULL; 
        } 
    }
    /*------------------------------------------------------------------------
    Display

    Preconditions: requires a reference of type ostream
    Postconditions: returns the ostream value (for chaining)

    description: outputs the contents of a queue. 
    ------------------------------------------------------------------------*/
    void display(ostream & out) const {
        NodePointer ptr; 
        ptr = myFront; 

        while(ptr != NULL) { 
            out << ptr->data << " "; 
            ptr = ptr->next; 
        } 
        out << endl; 
    }
    /*------------------------------------------------------------------------
    Front

    Preconditions: none
    Postconditions: returns a value of type T

    description: returns the first value in the parent Queue. 
    ------------------------------------------------------------------------*/
    T front() const {
       if ( !empty() ) 
          return (myFront->data);
       else
       {
          cerr << "*** Queue is empty -- returning garbage value ***\n";
          T * temp = new(T); 
          T garbage = * temp;
          delete temp; 
          return garbage;
       }
    }
    /*------------------------------------------------------------------------
    Dequeue

    Preconditions: none
    Postconditions: removes the first value in a queue
    ------------------------------------------------------------------------*/
    void dequeue() {
        if ( !empty() ) { 
            NodePointer ptr = myFront; 
            myFront = myFront->next; 
            delete ptr; 
            if(myFront == NULL) 
                myBack = NULL; 

        } else {
            cerr << "*** Queue is empty -- "
              "can't remove a value ***\n";
            exit(1);
        }
    }
    /*------------------------------------------------------------------------
    pverloaded = operator

    Preconditions: requires a constant reference
    Postconditions: returns a const type T

    description: this allows assigning of queues to queues
    ------------------------------------------------------------------------*/
    Queue<T> & operator=(const T &q) { 
    // make sure we arent reassigning ourself
    // e.g. thisQueue = thisQueue. 
        if(this != &q) { 
            this->~Queue(); 
            if(q.empty()) { 
                myFront = myBack = NULL; 
            } else { 
                myFront = myBack = new Node(q.front()); 
                NodePointer qPtr = q.myFront->next; 
                while(qPtr != NULL) { 
                    myBack->next = new Node(qPtr->data); 
                    myBack = myBack->next; 
                    qPtr = qPtr->next; 
                } 
            } 
        } 
        return *this; 
    }

private:
    class Node { 
    public: 
        T data; 
        Node * next; 
        Node(T value, Node * first = 0) : data(value),
                                          next(first) {}

    };  
    typedef Node * NodePointer; 

    NodePointer myFront,
               myBack,
               queueSize; 


}; 

/*------------------------------------------------------------------------
join

Preconditions: requires 2 queue values
Postconditions: appends queue2 to the end of queue1

description: this function joins 2 queues into 1. 
------------------------------------------------------------------------*/

template <typename T>
Queue<T> join(Queue<T> q1, Queue<T> q2) {
    Queue<T> q1Copy(q1), q2Copy(q2); 
    Queue<T> jQueue; 


    while(!q1Copy.empty()) { 
        jQueue.enqueue(q1Copy.front()); 
        q1Copy.dequeue(); 
    } 

    while(!q2Copy.empty()) { 
        jQueue.enqueue(q2Copy.front()); 
        q2Copy.dequeue(); 
    } 
    cout << jQueue << endl; 
    return jQueue;   

} 
/*----------------------------------------------------------------------------
Overloaded << operator 

Preconditions: requires a constant reference and a Queue of type T
Postconditions: returns the ostream (for chaining)

description: this function is overloaded for outputing a queue with <<
----------------------------------------------------------------------------*/
template <typename T>
ostream & operator<<(ostream &out, Queue<T> &s) { 
    s.display(out);  
    return out; 
} 

/*----------------------------------------------------------------------------
Overloaded << operator

Preconditions: requires a constant reference and a reference of type Student
Postconditions: none

description: this function is overloaded for outputing an object of type
             Student. 
----------------------------------------------------------------------------*/
ostream & operator<<(ostream &out, Student &s) { 
    s.display(out); 
}

/*----------------------------------------------------------------------------
Overloaded << operator

Preconditions: requires a constant reference and a reference of a pointer to
               a Student object. 
Postconditions: none

description: this function is overloaded for outputing pointers to Students
----------------------------------------------------------------------------*/
ostream & operator<<(ostream &out, StudentPointer &s) { 
    s->display(out); 
}
#endif

现在我遇到了一些问题。首先,当我向队列添加0然后我像这样输出队列..

Queue<double> qdub; 
qdub.enqueue(0); 
cout << qdub << endl; 

可行,它将输出0.但是,例如,如果我以任何方式修改该队列..比如...将其分配给不同的队列..

Queue<double> qdub1; 
Queue<double> qdub2; 
qdub1.enqueue(0; 
qdub2 = qdub1; 
cout << qdub2 << endl; 

它会为我提供奇怪的值,如.. 7.86914e-316。

非常感谢帮助!

4 个答案:

答案 0 :(得分:6)

您尚未定义复制构造函数或赋值运算符。您已经获取了排队类型的实例,而不是另一个队列。对于自己分配和复制队列,编译器仍然会使用自动生成的队列来做错误的事情。

(这可能无法解释该特定片段的输出。)

另一件事是完全错误的(尽管,再次,代码片段永远不会调用此函数,或者你会在整个地方遇到编译器错误):

Queue<T> & operator=(const T &q) {
// make sure we arent reassigning ourself
// e.g. thisQueue = thisQueue.
    if(this != &q) {
        this->~Queue();

明确地调用析构函数,然后继续使用该实例是不允许的。显式析构函数调用只与构建具有新位置的对象密切相关。

operator=通常是根据复制构造函数和交换方法(在两个实例之间交换内部表示)实现的:

void swap(Queue<T>& rhv)
{
   std::swap(myFront, rhv.myFront);
   std::swap(myBack, rhv.myBack);
   std::swap(queueSize, rhv.queueSize);
}

Queue<T>& operator=(const Queue<T>& rhv)
{
   Queue<T> copy(rhv);
   this->swap(copy);
} //the destructor of copy releases the previous contents of *this

答案 1 :(得分:1)

我没有在那里看到赋值运算符,这意味着您将获得编译器生成的默认值,这将执行浅拷贝。您可能需要自己提供深度复制。你的评论所谓的副本ctor也不是真正的副本。复制ctor 总是对正在复制的对象进行const引用,因此签名将是: Queue(Queue const &original);

答案 2 :(得分:1)

您需要一个合适的赋值运算符。您的示例可能无法按照您提供课程的方式进行编译。

即使我错了,代码中的主要错误是你的operator=称它为自己的析构函数。这是非常错误的。析构函数稍后也会被称为“自然”。这意味着您的对象将被删除两次。 (因为您没有在析构函数中为Queue.myFront指定NULL。)

Don't manually call destructors.

对于基本练习,我建议您在第qdub2 = qdub1行上放置一个断点,然后逐步调试以查看您的代码真正做了什么。

答案 3 :(得分:0)

根据一般编码标准,您不应该致电

this->~Queue()

通过这个语句,一个对象试图删除自己。 尝试将数据复制到新队列中,如果超出范围则将其删除。否则保持不变。

另一个example用于理解C ++模板