DS007-队列的原理-操作受限的线性表-queue的使用

本篇介绍基于顺序表的队列和基于单链表的队列的原理和实现。

最后介绍一下C++ STL 模板库 queue的使用。

一、什么是队列

有些应用,处理的对象是线性关系,用线性表存储,

但这些应用又有自己的特点,在一端进行插入操作,在另一端进行删除操作,

中间不允许插入删除

就像生活中的队列一样。

插入数据的一端称为队头,删除数据的一端称为队尾。

有两种存储方式,顺序的和链式的,那么队列也有两类实现方式,

一类是基于顺序表的,一类是基于链表的。

我们下面介绍基于顺序表的循环队列,基于单链表的队列。

二、基于顺序表的循环队列

我们知道,对于顺序表,在低下标处插入和删除数据,需要移动大量元素,效率低,在高下标处插入和删除数据,效率高。

这样一来,让高下标方向作为队尾非常自然,插入数据很简便;

而在低下标处删除数据,按照顺序表常规做法需要把后面的数据前移,效率低。

改进的方法,

设立队头、队尾两个指针,

队头和队尾之间是数据。

插入数据时,队尾指针处插入数据,指针后移

删除数据时,队头指针后移,这样就把队头数据排除在范围之外,相当于删除了。

#include <iostream>
using namespace std;

template<typename T>class queue
{
    T* elem;//连续空间首地址
    int listsize;//空间大小
    int length;//存储的实际元素个数
    int head;//队头下标
    int rear;//队尾元素下标
public:
    queue()
    {
        int L = 1;
        elem = new T[L];
        listsize = L;
        length = 0;
        head = 0;
        rear = -1;
    }

    void enlarge()
    {
        T* newbase = new T[listsize * 2];
        int i=head, j=0;
        int count = 1;//计数器
        while (count<=length)//每个元素都要拷贝
        {
            newbase[j] = elem[i];
            i = (i + 1) % listsize;
            j++;
            count++;
        }        
        
        delete elem;

        listsize *= 2;
        elem = newbase;
        head = 0;
        rear = length-1;
    }

    void push(T x)
    {//入队,在队尾插入元素
        if (length == listsize)
        {
            enlarge();
        }
        rear = (rear + 1) % listsize;
        elem[rear] = x;

        length++;
        
        
    }
    void pop()
    {//出队
        
        head =(head +1)%listsize;
        length--;
    }

    T front()
    {//得到队头元素
        return elem[head];
    }
    void print()
    {//从前到后打印队列元素
        int i=head;
        int count;
        for (count = 1; count <= length; count++)
        {
            cout << elem[i] << " ";
            i = (i + 1) % listsize;
        }
        
        cout << endl;
    }
    int size()
    {//得到队列长度
        return length;
    }


    ~queue()
    {
        delete elem;
    }
};


int main()
{
    queue<int> q;
    q.push(1);
    q.print();
    
    q.push(2);
    q.print();
    q.push(3);
    q.print();
    q.push(4);
    q.print();
    cout << q.front() << endl;//打印队头元素
    q.pop();
    q.print();


}

三、基于单链表的队列

对于一般单链表而言,在表头结点后面插入和删除数据都很简便,

而在表尾插入数据需要先找到表尾,遍历整个链表。

在表尾删除数据需要先找到表尾前一个结点,遍历整个链表。

即在表尾插入和删除数据都是O(n).

改造的方法,设置一个指向表尾结点的指针,这样在表尾插入数据就很方便了。

这样,表头就是队头,表尾就是队尾。

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
using namespace std;

template<typename T>class queue
{//单链表表示队列
    struct node
    {
        T data;
        node* next;
    };
    node* head;//头指针
    node* tail;//尾指针
    
    int length;//存储的实际元素个数
    
public:
    queue()
    {
        head = tail = new node;
        head->next = 0;
        length = 0;
        
    }


    void push(T x)
    {//入队,在队尾插入元素
        node* t = new node;
        t->data = x;
        t->next = 0;
        tail->next = t;
        tail = t;
        length++;      
        
    }
    void pop()
    {//出队
        if (length == 1)
        {//删除尾结点时要注意
            delete tail;
            tail = head;
        }
        else
        {
            node* t = head->next;
            head->next = t->next;
            delete t;
        }        
        
        length--;
    }

    T front()
    {//得到队头元素
        return head->next->data;
    }
    void print()
    {//从前到后打印队列元素
        node* p = head->next;
        while (p)
        {
            cout << p->data << " ";
            p = p->next;
        }
        cout << endl;        
       
    }
    int size()
    {//得到队列长度
        return length;
    }


    ~queue()
    {
        node* p;
        while (head->next)
        {
            p = head->next;
            head->next = p->next;
            delete p;
        }
        delete head;

    }
};


int main()
{
    queue<int> q;
    q.push(1);
    q.print();
    
    q.push(2);
    q.print();
    q.push(3);
    q.print();
    q.push(4);
    q.print();
    cout << q.front() << endl;//打印队头元素
    q.pop();
    q.print();


}

四、C++ STL 模板queue

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include<queue>
#include <iostream>
using namespace std;

template<typename T>
void print(queue<T> q)
{
    T x;
    while (q.size())
    {
        x = q.front();
        cout << x << "  ";
        q.pop();
    }
    cout << endl;
}


int main()
{
    queue<int> q;
    q.push(1);
    print(q);
    
    
    q.push(2);
    print(q);
    
    q.push(3);
    print(q);
    
    q.push(4);
    print(q);
    
    cout << q.front() << endl;//打印队头元素
    q.pop();
    print(q);
    


}

猜你喜欢

转载自blog.csdn.net/weixin_43917370/article/details/108593535