学习了好长 一段时间的数据结构,由于时间关系一直没有写博客。这次打算将这段时间的学习内容写下来做个整理。
队列作为线性结构的一种, 其实用性不用多说。这里总结下两种结构的队列实现。
##循环队列 ##
先列下以顺序表结构形成的普通顺序队列存在的问题:
队头不断删除元素,将使队列的头部空出单元;
随着删除、插入的进行,将很快队满—假溢出;
这一点不象人类排队,人类排队时,队头的人走掉后,后面的人自然会往前移动,不会让队头部分空出位置。
所以如果向用顺序结构实现队列,一个解决办法就是—循环顺序队列
1. 循环队列定义
//循环队列
template<class T>
class seQueue
{
public :
seQueue();
bool empty(); //判断队空
bool full(); //判断队满
T Front(); //取队头元素
void pop(); //出队
void push(T x); //入队
int size(); //统计队列元素个数
~seQueue();
private:
T data[MAXLEN];//定义元素集合
int front; //队头指针
int rear; //队尾指针
};
循环队列的不同之处在于其将data[0]和data[MaxLen-1]视为相邻单元,首尾相接,形成一个逻辑意义的环(非物理上的)。
当rear=Maxlen-1时,再插入一个元素,让rear=0;同样,front=MaxLen-1时,再删除一个元素,也让front=0;形成逻辑上的循环。
- 入队(插入)操作位置计算
正常操作:rear++; data[rear]=x; 循环队列中,当rear=Maxlen-1时,再进行插入,此时要回到rear=0, 而不能是rear+1=MaxLen,如何实现呢?
用取模运算rear=(rear+1) % MaxLe//判断队满
template<class T>
bool seQueue<T>::full()
{
if((rear+1)%MAXLEN == front) //队满条件(Q.rear+1)%MAXLEN == Q.front
return true; //队满,返回true,即尾指针的x下一个位置是头指针
else
return false; //不满,返回false
}
//入队
template<class T>
inline void seQueue<T>::push(T x)
{
if(full())
cout<<"队列已满, 不能完成入队操作";
else
{
rear = ((rear)+1) % MAXLEN; //取新队尾位置
data[rear] = x;
}
}
- 如何判定队空和队满呢?
由于循环,队空和队满时都有:rear==front,如何区分出队空和队满呢?–【方法一】约定保留一个元素单元:
解决方法:约定数组最多存放MaxLen-1个元素,front指队头元素的前一个单元;
因此,在有数据元素时,front和rear至少相差一个单元,使得头指针front永远“赶不上”尾指针rear判定条件:
队列空:front==rear
队列满:front==(rear+1) % MaxLen
- 注:
因为反复的入队、出队操作,队空、队满时,front和Rear指针可能指向data[]数组的任何位置,而不是固定在某个位置。
front指向的前一个数据节点才是实际的数据存放区域
完整代码如下:
//循环队列
template<class T>
class seQueue
{
public :
seQueue();
bool empty(); //判断队空
bool full(); //判断队满
T Front(); //取队头元素
void pop(); //出队
void push(T x); //入队
int size(); //统计队列元素个数
~seQueue();
private:
T data[MAXLEN];//定义元素集合
int front; //队头指针
int rear; //队尾指针
};
template<class T>
seQueue<T>::seQueue()
{
front = 0; //空队列
rear = 0;
}
template<class T>
seQueue<T>::~seQueue()
{
front = 0; //空队列
rear = 0;
cout<<"free"<<endl;
}
//判断队空
template<class T>
bool seQueue<T>::empty()
{
if(front == rear) //当rear等于front时队空
return true;
else return false;
}
//判断队满
template<class T>
bool seQueue<T>::full()
{
if((rear+1)%MAXLEN == front) //队满条件(Q.rear+1)%MAXLEN == Q.front
return true; //队满,返回true,即尾指针的x下一个位置是头指针
else
return false; //不满,返回false
}
//取队头元素
template<class T>
T seQueue<T>::Front()
{
if(empty())
{
cout<<"队空,不能取头元素";
return NULL;
}
else
return data[(front+1) % MAXLEN]; //front指向的下一个单元才是队头元素
}
//入队
template<class T>
inline void seQueue<T>::push(T x)
{
if(full())
cout<<"队列已满, 不能完成入队操作";
else
{
rear = ((rear)+1) % MAXLEN; //取新队尾位置
data[rear] = x;
}
}
//出队
template<class T>
void seQueue<T>::pop()
{
if(empty())
cout<<"队列为空无法出队";
else
{
front = ((front)+1) % MAXLEN;
}
}
//统计队列元素个数
template<class T>
int seQueue<T>::size()
{ //元素个数为; (Q.rear-Q.front + MAXLEN) % MAXLEN
return (rear-front + MAXLEN) % MAXLEN;
}
链队列
链队列的实现较为简单,这里不做过多描述
这里总结下用不带头结点的链表实现的链队列
不带头结点的链队列实现
//定义结点
template<class T>
class node
{
public:
T data;
node *next;
};
//定义链队列
template<class T>
class linkedQueue
{
private:
node<T> *front; //队头指针
node<T> *rear; //队尾指针
public:
//构建函数
linkedQueue();
//析构函数
~linkedQueue();
//判断队空
bool empty();
//取队头元素
T Front();
//入队
void push(T x);
//出队
bool pop();
//统计队列元素个数
int size();
//判断队满
bool full();
void init();//c1.初始化
};
//构建函数
template<class T>
linkedQueue<T>::linkedQueue()
{
rear = front =NULL; //将rear与front指向NULL
}
//析构函数
template<class T>
linkedQueue<T>::~linkedQueue()
{
while(!empty())
pop();
}
//判断队空
template<class T>
bool linkedQueue<T>::empty()
{
return (front==rear && front==NULL); //当front等于rear且front等于NULL时
}
//取队头元素
template<class T>
T linkedQueue<T>::Front()
{
return front->data; //队头是front指向的结点
}
//入队
template<class T>
void linkedQueue<T>::push(T x)
{
node<T> *p = new node<T>; //申请内存,产生新节点
p->data = x;
p->next = NULL;
if(front) //当前队头结点非空时
{
rear->next = p; //新结点接到原表尾
rear = p; //后移指针,指向新节点
}
else front = rear = p; //当队头元素为空时,p成为第一个队列结点
}
//出队
template<class T>
bool linkedQueue<T>::pop()
{
if(empty())
return false;
node<T>*u = NULL;
u = front;
front = u->next;
delete u;
if(front == NULL) //删除结点后队空,改rear 指针
rear=front;
return true; //删除指针
}
//统计队列元素个数
template<class T>
int linkedQueue<T>::size()
{
node<T> *temp = front;
int tot = 0; //元素个数,初始化为0
while(temp != rear)
{
tot++;
temp = temp->next;
}
return tot;
}
template<class T>
void linkedQueue<T>::init()//初始化
{
node<T> *p;
while(front!=rear)
{
p=front;
front=front->next;
delete p;
}
if(front!=NULL)
{
p=front;
front=rear=NULL;
delete p;
}
return;
}