代码改变世界

数据结构-队列

2011-09-06 19:58  Clingingboy  阅读(1264)  评论(0编辑  收藏  举报

 

排队规则:进入队列的人永远都在队尾,出队的人永远都在队首.

1.队列初始化

用rear和front表示队尾和队首.

在数组表示队列,如下有5个大小的数组A,

1,2,3,4,5

那么如果只有入队的操作,队尾从1转移到了5,5是当前的队尾

出队的时候数组A的1为第一个队首,随着出队的操作,也慢慢向队尾的方向移动.

这说明一个情况,队首和队尾,刚开始是同个地方,即使是操作也是相同的(在数组中操作就是添加索引值)

rear=front=0;

2.判断队空

第一个反应是应该有一个变量count来记录元素大小
如果在没有count变量的情况下,那么第二个反应是rear==front==0,那因为我们还是想着依赖某个变量记录元素大小的思维来思考(rear==front==0肯定是对的,但只是其中的一种情况,我们需要一种绝对式,适应不同的情况),一旦发生入队或者出队不一致就会导致队不为空.
第三个假设:在现实中,从队列移除是真正的移除,而数组的数量却没有改变,只不过更改了队尾和队首在数组中的位置而已,理解这一点至关重要.

rear==front==(0,1,2,3,4)都是可以的,即保持入队和出队一致就可以了

3.判断队满

第一个反应判断rear是否等于数组大小

以下代码适用于只有入队的操作

template<typename Type> bool SeqQueue<Type>::Append(const Type item){
    if((m_nrear+1)==m_nMaxSize){
        cout<<"The queue is full!"<<endl;
        return 0;
    }
    m_pelements[m_nrear]=item;
    m_nrear=m_nrear+1;
    return 1;
}

上面的代码有一个假设,就是没有出队.换一种思路思考就是rear和front的距离.

如下操作,入队到满位置,然后再出队,入队,那么rear+1就会导致数组溢出,由于数组前面索引的元素已经出队,就可以再次使用,所以将rear值恢复到数组0索引值

m_nrear=(m_nrear+1)%m_nMaxSize;

由于rear和front都是索引值增加,比较值当间隔是1时,就表示为队满(rear和front值不为0)

if((m_nrear+1)%m_nMaxSize==m_nfront){
    cout<<"The queue is full!"<<endl;
    return 0;
}

完整代码示例:

template<typename Type> class SeqQueue{
public:
    SeqQueue(int sz):m_nrear(0),m_nfront(0),m_nMaxSize(sz){
        m_pelements=new Type[sz];
        if(m_pelements==NULL){
            cout<<"Application Error!"<<endl;
            exit(1);
        }
    }
    ~SeqQueue(){
        delete[] m_pelements;
    }
    void MakeEmpty();               //make the queue empty
    bool IsEmpty();
    bool IsFull();
    bool Append(const Type item);   //insert data
    Type Delete();                  //delete data
    Type Get();                     //get data
    void Print();                   //print the queue

private:
    int m_nrear;
    int m_nfront;
    int m_nMaxSize;
    Type *m_pelements;
    
};

template<typename Type> void SeqQueue<Type>::MakeEmpty(){
    this->m_nfront=0;
    this->m_nrear=0;
}

template<typename Type> bool SeqQueue<Type>::IsEmpty(){
    return m_nrear==m_nfront;
}

template<typename Type> bool SeqQueue<Type>::IsFull(){
    return (m_nrear+1)%m_nMaxSize==m_nfront;
}

template<typename Type> bool SeqQueue<Type>::Append(const Type item){
    if(IsFull()){
        cout<<"The queue is full!"<<endl;
        return 0;
    }
    m_pelements[m_nrear]=item;
    m_nrear=(m_nrear+1)%m_nMaxSize;
    return 1;
}

template<typename Type> Type SeqQueue<Type>::Delete(){
    if(IsEmpty()){
        cout<<"There is no element!"<<endl;
        exit(1);
    }
    Type temp=m_pelements[m_nfront];
    m_nfront=(m_nfront+1)%m_nMaxSize;
    return temp;
}

template<typename Type> Type SeqQueue<Type>::Get(){
    if(IsEmpty()){
        cout<<"There is no element!"<<endl;
        exit(1);
    }
    return m_pelements[m_nfront];
}

template<typename Type> void SeqQueue<Type>::Print(){
    cout<<"front";
    for(int i=0;i<m_ncount;i++){
        cout<<"--->"<<m_pelements[(m_nfront+i+m_nMaxSize)%m_nMaxSize];
    }
    cout<<"--->rear"<<endl<<endl<<endl;
}

求队列的队尾元素

思路:只有全部出队,才能知道队尾元素,先全部出队求出队尾元素存在一个暂存的队列中,然后将暂存的队列中数据还原到原先队列中

添加一个记录元素count个数的变量

添加这个变量后的好处有三点

  1. 能够快速求出队尾元素
  2. 方便队满和空的计算
  3. 可以移除rear变量,以count的计算rear的值

添加了count以后就好理解很多,当然也不一定要移除front变量

template<typename Type> bool SeqQueue<Type>::IsEmpty(){
    return m_ncount==0;
}

template<typename Type> bool SeqQueue<Type>::IsFull(){
    return m_ncount==m_nMaxSize;
}

template<typename Type> bool SeqQueue<Type>::Append(const Type item){
    if(IsFull()){
        cout<<"The queue is full!"<<endl;
        return 0;
    }
    int rear=(m_nfront+m_ncount)%m_nMaxSize;
    m_pelements[rear]=item;
    m_ncount++;
    return 1;
}

template<typename Type> Type SeqQueue<Type>::Delete(){
    if(IsEmpty()){
        cout<<"There is no element!"<<endl;
        exit(1);
    }
    Type temp=m_pelements[m_nfront];
    m_nfront=(m_nfront+1)%m_nMaxSize;
    m_ncount--;
    return temp;
}

链队

好处:不会溢出,所以就没有IsFull的概念,入队和出队的概念一样

template<typename Type> class QueueNode{
private:
    friend class LinkQueue<Type>;
    QueueNode(const Type item,QueueNode<Type> *next=NULL)
        :m_data(item),m_pnext(next){}
private:
    Type m_data;
    QueueNode<Type> *m_pnext;
};

template<typename Type> class LinkQueue{
public:
    LinkQueue():m_prear(NULL),m_pfront(NULL){}
    ~LinkQueue(){
        MakeEmpty();
    }
    void Append(const Type item);   //insert data
    Type Delete();                  //delete data
    Type GetFront();                //get data
    void MakeEmpty();               //make the queue empty
    void Print();                   //print the queue

    bool IsEmpty() const{
        return m_pfront==NULL;
    }

private:
    QueueNode<Type> *m_prear,*m_pfront;
};

template<typename Type> void LinkQueue<Type>::MakeEmpty(){
    QueueNode<Type> *pdel;
    while(m_pfront){
        pdel=m_pfront;
        m_pfront=m_pfront->m_pnext;
        delete pdel;
    }
}

template<typename Type> void LinkQueue<Type>::Append(const Type item){
    if(m_pfront==NULL){
        m_pfront=m_prear=new QueueNode<Type>(item);
    }
    else{
        m_prear=m_prear->m_pnext=new QueueNode<Type>(item);
    }
}

template<typename Type> Type LinkQueue<Type>::Delete(){
    if(IsEmpty()){
        cout<<"There is no element!"<<endl;
        exit(1);
    }
    QueueNode<Type> *pdel=m_pfront;
    Type temp=m_pfront->m_data;
    m_pfront=m_pfront->m_pnext;
    delete pdel;
    return temp;
}

template<typename Type> Type LinkQueue<Type>::GetFront(){
    if(IsEmpty()){
        cout<<"There is no element!"<<endl;
        exit(1);
    }
    return m_pfront->m_data;
}

template<typename Type> void LinkQueue<Type>::Print(){
    QueueNode<Type> *pmove=m_pfront;
    cout<<"front";
    while(pmove){
        cout<<"--->"<<pmove->m_data;
        pmove=pmove->m_pnext;
    }
    cout<<"--->rear"<<endl<<endl<<endl;
}