队列——限定性的数据结构

159 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情


一、队列的定义与操作

1.定义

1.概念

  1. 队列:只能在线性表一端进行插入操作,在另一端进行访问和删除操作的线性表

  2. 队尾:将进行插入操作的一端

  3. 队头:可以进行访问和删除操作的一端

2.顺序:先进先出

2.链队列

1.定义

typedef struct clNode{
    int data;
    clNode* next;
}*cqNode;
struct chainQueue{
    cqNode front;//头结点
    cqNode rear;//尾结点
    chainQueue():front(NULL),rear(NULL){}
};

2.操作

bool empty(chainQueue cq) {
    return cq.front == NULL;
}
void push(chainQueue& cq, int x) {
    cqNode tmp = new clNode;//创建新节点
    tmp->data = x;
    tmp->next = NULL;
    if (empty(cq)) {//如果链队列没有元素
        cq.front = new clNode;
        cq.front->next = tmp;
    }
    else {
        cq.rear->next = tmp;//新加入的结点加入当前链队列队尾的后面
    }
    cq.rear = tmp;//队尾始终为新加入的结点
}
int front(chainQueue cq) {
    if (empty(cq)) {
        cout << "队列为空" << endl;
        return -1;
    }
    return cq.front->next->data;//返回队头元素
}
void pop(chainQueue& cq) {
    if (empty(cq)) {
        cout << "队列为空" << endl;
        return;
    }
    cqNode tmp = cq.front->next;//队头结点
    cq.front->next = tmp->next;
    delete tmp;
    tmp = NULL;
    if (cq.front->next == NULL) {//链队列中元素被全部删除
        delete cq.front;
        cq.front = NULL;
        cq.rear = NULL;
    }
}
void cq_traverse(chainQueue& cq) {
    while (!empty(cq)) {
        cout << front(cq) << " ";
        pop(cq);
    }
}

3.循环队列

1.定义

1.概念:下标最大的元素的下一个元素的下标为0

#define N 100
#define next(x) ((x)==N-1?0:(x)+1)
typedef struct sqNode{
    int data[N];
    int front;
    int rear;
    sqNode():front(0),rear(-1){}
}seqQueue;

判断队空的条件next(sq.rear)=sq.front

判断队满的条件next(next(sq.rear))=sq.front因此队中有一个元素为空

2.操作

//判断队空
bool empty(seqQueue sq) {
    return next(sq.rear) == sq.front;
}
//判断队满
bool full(seqQueue sq) {
    return next(next(sq.rear)) == sq.front;
}
void push(seqQueue& sq, int x) {
    if (full(sq))
    {
        cout << "队满" << endl;
        return;
    }
    sq.rear = next(sq.rear);//队尾后移一位
    sq.data[sq.rear] = x;
}
int front(seqQueue sq) {
    if (empty(sq)) {
        cout << "队空" << endl;
        return - 1;
    }
    return sq.data[sq.front];
}
void pop(seqQueue& sq) {
    if (empty(sq)) {
        cout << "队空" << endl;
        return;
    }
    sq.front = next(sq.front);//队头后移一位
}
void sq_traverse(seqQueue& sq) {
    while (!empty(sq)) {
        cout << front(sq) << ' ';
        pop(sq);
    }
}

二、STL队列

1.queue

1.头文件:#include<queue>

1.定义

queue<int>q1;
queue<char, list<char>>q1;
//用list容器实现的queue 
queue<int,vector<int>>q1;//底层容器为vector

2.操作

	qu.push(3);//入队
	cout << qu.size() << endl;//队列中元素的个数
	cout << qu.back() << endl;//返回尾元素
	while (!qu.empty()) {//判断队列是否为空
		cout << qu.front() << endl;//获取队头元素
		qu.pop();//出队
	}

2.deque

1.定义

deque<int>dq;//创建空对象
	deque<int>dq2(12, 5);//创建一个含有12个元素的deque对象,元素的初始值都为5
	int a[] = { 1,3,7 };
	deque<int>dq3(a, a + 2);//创建含有4个元素的deque对象

2.操作

	dq.push_front(7);//插入队头
	dq.pop_back();

三、队列应用

1.二项式

1.实现

  1. 首先向队列中添加0,即为每一行都最后的0以及下一行的第一个0

  2. 取队列q的队头元素,假设其值为f1,出队;再取q的队头元素,假设其值为f2,出队

  3. 将f1+f2入队

  4. 如果f2不为0,则输出f2,回到第2步,如果f2=0,则一行输出结束,回到第1步

2.代码

void chineseTriangle(int n) {
    int f1, f2, flag, w = 4;
    queue<int>qu;
    qu.push(0), qu.push(1);//初始化
    while (n--) {
        qu.push(0);//每一行都最后一个0,也是下一行的第一个0
        flag = 0;//flag=0表示当前为每一行都第一个数字
        do {
            f1 = qu.front();
            qu.pop();//获取第一个值,并出队
            f2 = qu.front();//获取第二个值
            if (f2) {
                if (!flag) {
                    flag = 1;
                    cout << setw(w * n + 1) << f2;//第一个数字的宽度特别处理
                }
                else
                    cout << setw(2 * w) << f2;
            }
            else
                cout << endl;//f2=0,一行结束
            qu.push(f1 + f2);//f1+f2入队
        } while (f2 != 0);
    }
}

四、单调队列

1.定义

1.概念:队列的元素按从队头到队尾的顺序为严格单调递增,称为递增队列;如果队列的元素按从队头到队尾的顺序为严格单调递减,则称为递减队列

2.应用

1.利用单调队列求固定长度区间的最大值

1.步骤

  1. 定义一个双端队列dq,队列中存放的是数组a的下标。一次考虑a的每一个元素,对于元素a[i],可分为三步

  2. 去尾操作。如果dq不空,且a[i]≥dq的队尾元素值,则将dq的队尾出队,并继续上述操作,直到a[i]<dq的队尾元素值或dq为空。a[i]入队。这一操作保证队列中的元素递减

  3. 掐头操作。如果dq队头元素与a[i]的距离不小于m,则将dq的队头出队,这一操作保证队头元素在以a[i]为右端点的滑动窗口内

  4. dq队头元素即为当前滑动窗口中的最大值,输出该最大值

void rangeMax(vector<int>ve,int m){
    deque<int> dq;
    for(int i=0;i<ve.size();i++){
        while(!dq.empty()&&ve[dq.back()]<ve[i])//队尾
            dq.pop_back();
        dq.push_back(i);//下标入队
        if(i>=m-1){
            if(!dq.empty()&&i-dq.front()>=m)//掐头
                dq.pop_front();
            cout<<ve[dq.front()]<<' ';//输出队头
        }
    }
    
}