数据结构-队列
2011-09-06 19:58 Clingingboy 阅读(1267) 评论(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个数的变量
添加这个变量后的好处有三点
- 能够快速求出队尾元素
- 方便队满和空的计算
- 可以移除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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现