整理的人脸系列学习经验:包括人脸检测、人脸关键点检测、人脸优选、人脸对齐、人脸特征提取等过程总结,有需要的可以参考,仅供学习,请勿盗用。https://blog.csdn.net/TheDayIn_CSDN/article/details/93199307
在做人脸状态分析过程中,需要连续保存经过人脸检测、人脸关键点检测之后,经过关键点计算的人脸旋转角度、睁眼闭眼、张嘴闭嘴等状态信息,而且需要保存五到十帧数据状态信息并统计输出,并一直连续更新人脸状态信息。所以这里考虑使用循环队列实现,主要是新建一个循环队列,在队列尾部输入没帧数据状态,在队列满之后统计状态,并删除队首一帧数据,重新再队尾插入数据,然后继续统计队列数据状态信息,这样就可以做到实时刷新状态信息。如下图示:
队列是一种先进先出(FIFO,First-In-First-Out)的线性表,通常用链表或者数组来实现。队列只能在队尾插入元素,只能在队首删除元素。
循环队列的一些性质:
1.在循环队列里,如果容量没有达到上限,当队尾队首标记达到数组上界后,就跳转到数组起始位置
2.在线性队列里,当 tail 达到队列上限后,继续插入就会发生“假上溢”的情况
3.循环队列里可通过统计队列里元素个数,判断能否继续往队列里插入元素
首先,我们增加一个count变量来计算入队的元素个数,这样的话,当count = length的时候,才表示真正的队列“上溢”,所以呢,对于循环队列的入队操作,可分两种情况讨论:
1.如果队尾指针此时并未指向队列的最后一位,那么队尾指针直接前移 tail = tail + 1
2.当队尾指针此时指向最后一位时,那么当队列未满时,则队尾指针将跳转至数组起始位置 tail = (tail + 1)% length
3.队首元素出队列 head = (head + 1) % length
这里特别需要注意的是,循环队列的遍历输出时,循环截止条件不再是head <= tail,而是head != tail +1,这是为什么呢?原因其实也很简单,因为当队尾队首标记达到数组上界后,就跳转到数组起始位置,所以tail是可能小于head的,而无论是head
for(int i = head;i != tail + 1;i = (i + 1)%length){ //从队首一直遍历到队尾,当遍历到最后一位时,跳转至数组起始位置
//特别注意此时循环截止的条件应该是i != tail + 1,因此可能tail的值小于head
cout << data[i] << " ";
}
完整代码实现:
#include
using namespace std;
class Queue{
private:
int *data; //定义指向整型的指针,从而动态开辟内存
int head,tail,length,count; //head指向队首,tail指向队尾,length表示队列的长度,count用于记录队列中元素个数,从而判断队列是否已满
public:
Queue (int length_input){ //构造函数,对新声明的队列对象进行初始化
data = new int [length_input]; //动态开辟100个整型数据的空间
length = length_input; //为队列的长度赋初始值
head = 0; //起初head为0,表示head值未改变的情况下,一直指向首元素
tail = -1; //tail初始值为-1,表示此时队列为空,无任何数据元素
count = 0;
}
~Queue(){
delete [] data; //析构函数,删除动态开辟的内存
}
void push(int element){ //入队操作,只能从队列的尾部插入数据元素
if(count < length){ //队列未满的时候才能插入,否则则插入失败
tail = (tail + 1) % length; //分两种情况,如果队尾指针此时并未指向队列的最后一位,那么队尾指针直接前移,而当队尾指针此时指向最后一位时
data[tail] = element; //那么当队列未满时,则队尾指针将跳转至数组起始位置,再将数据元素插入队尾指针指向的位置
++count; //入队成功,队列中元素数量加一
}
}
void pop(){
if(count < 0){ //队列为空,出队失败
return;
}
head = (head + 1) % length; //同样,根据循环队列的性质得出
--count; //出队成功,队列中元素数量减一
}
int top(){
if(count > 0){ //队列不为空的情况下才能获取队首元素
return data[head];
}
}
void output(){
for(int i = head;i != tail + 1;i = (i + 1)%length){ //从队首一直遍历到队尾,当遍历到最后一位时,跳转至数组起始位置
//特别注意此时循环截止的条件应该是i != tail + 1,因此可能tail的值小于head
cout << data[i] << " ";
}
cout << endl;
}
};
int main() {
Queue queue(100); //声明一个队列对象,并初始化
for(int i = 1;i <= 10;++i){
queue.push(i); //将1-10这10个数据元素依次插入队列中
}
queue.output(); //调用输出的方法
cout << "当前的队首元素为:" << queue.top() << endl;
queue.pop(); //出队
queue.output(); //调用输出的方法
cout << "出队操作后的队首元素为:" << queue.top() << endl;
return 0;
}