北邮22信通一枚~
跟随课程进度每周更新数据结构与算法的代码和文章
持续关注作者 解锁更多邮苑信通专属代码~
上一篇文章:
北邮22信通:(10)第三章 3.2栈的实现_青山如墨雨如画的博客-CSDN博客
下一篇文章:
***鲜花***
有问题评论区留言哦 一起讨论
***********
目录
3.3.0无注释源代码
循环队列:
链队列:
3.3.1循环队列的实现
几点解释
代码部分
运行结果
3.3.2链队列的实现
几点解释
代码部分
运行结果
//循环队列书上代码
#include
using namespace std;
const int queuesize = 1000;
class student
{
private:
int ID;
string name;
public:
student()
{
this->ID = 0;
this->name = "INVALID";
}
student(int ID, string name)
{
this->ID = ID;
this->name = name;
}
void print()
{
cout << "this->ID=" << this->ID << " ";
cout << "this->name=" << this->name << endl;
}
friend ostream& operator <<(ostream& output, student& stu)
{
output << "ID=" << stu.ID << " ";
output << "name=" << stu.name << endl;
return output;
}
};
template
class circlequeue
{
private:
temp data[queuesize];
int front;
int rear;
public:
circlequeue() { this->front = this->rear = 0; }
void enqueue(temp x);
temp dequeue();
temp getfront();
int getlength();
bool empty()
{
return this->front == this->rear ? true : false;
}
};
template
void circlequeue::enqueue(temp x)
{
if ((this->rear + 1) % queuesize == this->front) throw "overflow";
this->rear = (this->rear + 1) % queuesize;
this->data[this->rear] = x;
}
template
temp circlequeue::dequeue()
{
if (this->rear == this->front)throw"underflow";
this->front = (this->front + 1) % queuesize;
return this->data[this->front];
}
template
temp circlequeue::getfront()
{
if (this->rear == this->front)throw"underflow";
return this->data[(this->front + 1) % queuesize];
}
template
int circlequeue::getlength()
{
return (this->rear - this->front + queuesize);
}
int main()
{
try
{
system("color 0A");
student stu[5] = { {1,"zhang"},{2,"wang"},{3,"li"},{4,"zhao"},{5,"liu"} };
circlequeue cq;
for (int i = 0; i < 5; i++)
cq.enqueue(stu[i]);
student tempstu;
cout << "now let's check if the queue is empty……" << endl;
cout << cq.empty() << endl;
for (int i = 0; i < 5; i++)
{
tempstu = cq.getfront();
cout << "before dequeue, the front data of the circlequeue is " << tempstu;
cout << "before dequeue, the length of the circlequeue is " << cq.getlength() << endl;
cout << "now we start to run the function dequeue……" << endl;
cq.dequeue();
cout << "deleted……" << endl << endl;
}
cout << "now let's recheck if the queue is empty……" << endl;
cout << cq.empty();
}
catch (const char* ss)
{
cout << ss << endl;
}
return 0;
}
#include
using namespace std;
const int queuesize = 1000;
class student
{
private:
int ID;
string name;
public:
student()
{
this->ID = 0;
this->name = "INVALID";
}
student(int ID, string name)
{
this->ID = ID;
this->name = name;
}
void print()
{
cout << "this->ID=" << this->ID << " ";
cout << "this->name=" << this->name << endl;
}
friend ostream& operator <<(ostream& output, student& stu)
{
output << "ID=" << stu.ID << " ";
output << "name=" << stu.name << endl;
return output;
}
};
template
struct node
{
temp data;
node* next;
};
template
class linkqueue
{
private:
node* front;
node* rear;
public:
linkqueue();
~linkqueue();
void enqueue(temp x);
temp dequeue();
temp getfront();
int getlength();
bool empty()
{
return (this->front == this->rear) ? true : false;
}
};
template
linkqueue::linkqueue()
{
this->front = this->rear = new node ;
this->front->next = NULL;
}
template
void linkqueue::enqueue(temp x)
{
this->rear->next = new node;
this->rear = this->rear->next;
this->rear->data = x;
this->rear->next = NULL;
}
template
temp linkqueue::dequeue()
{
node* p = this->front->next;
if (!p)throw"underflow";/*如果为空队列,抛出异常*/
this->front->next = p->next;
temp x = p->data;
delete p;
if (!(this->front->next))
this->rear = this->front;
return x;
}
template
temp linkqueue::getfront()
{
if (!this->front->next)throw"overflow";
return this->front->next->data;
}
template
linkqueue::~linkqueue()
{
while (this->front != NULL)
{
this->rear = this->front->next;
delete this->front;
this->front = this->rear;
}
}
template
int linkqueue::getlength()
{
node* p = this->front;
int cnt = 0;
while (p != this->rear)
{
cnt++;
p = p->next;
}
return cnt;
}
int main()
{
try
{
system("color 0A");
student stu[5] = { {1,"zhang"},{2,"wang"},{3,"li"},{4,"zhao"},{5,"liu"} };
linkqueue lq;
for (int i = 0; i < 5; i++)
lq.enqueue(stu[i]);
student tempstu;
cout << "now let's check if the queue is empty……" << endl;
cout << lq.empty() << endl;
for (int i = 0; i < 5; i++)
{
tempstu = lq.getfront();
cout << "before dequeue, the front data of the linkqueue is " << tempstu;
cout << "before dequeue, the length of the linkqueue is " << lq.getlength() << endl;
cout << "now we start to run the function dequeue……" << endl;
lq.dequeue();
cout << "deleted……" << endl << endl;
}
cout << "now let's recheck if the queue is empty……" << endl;
cout << lq.empty();
}
catch (const char*ss)
{
cout << ss << endl;
}
return 0;
}
1.为了实现循环队列更加方便,在此规定front位置永不存储队列元素,所以当队列满时,其长度实际为数组长度减1;
2.根据队列的性质,入队操作是对rear的移动,出队操作是对front的移动;
3.当front==next时,队列为空队列;
4.关于enqueue函数判断上溢的一点解释:
template
void circlequeue::enqueue(temp x)
{
if ((this->rear + 1) % queuesize == this->front) throw "overflow";
this->rear = (this->rear + 1) % queuesize;
this->data[this->rear] = x;
}
解释一下overflow的判断条件:
什么叫“上溢”:
顾名思义,就是向上溢出,本来队列已经满了,现在再从队尾插入一个元素,
队头那个元素就被挤死了。想出去,我没执行出队函数;不出去,队尾又补充进来一个元素。
这种情况就叫做上溢。
循环队列也会面对一模一样的问题。
下面解释if ((this->rear + 1) % queuesize == this->front) throw "overflow";
假设循环队列长度为5,第一个位置储存front,最后一个位置储存rear。这个长度为5的队列里,有效数据(即除去front)有4个。现在我执行入队操作,rear往后移一位,(rear+1)%queuesize=1=front,那不就被挤住了嘛。
所以称作上溢。
5.解释一下dequeue下溢的判断条件:
template
temp circlequeue::dequeue()
{
if (this->rear == this->front)throw"underflow";
this->front = (this->front + 1) % queuesize;
return this->data[this->front];
}
同理我们来理解一下this->rear==this->front这个判断条件:
那就是队头和队尾相等,那就是空队列。空队列不能执行dequeue函数,
所以称之为下溢。
//循环队列书上代码
#include
using namespace std;
const int queuesize = 1000;
class student
{
private:
int ID;
string name;
public:
student()
{
this->ID = 0;
this->name = "INVALID";
}
student(int ID, string name)
{
this->ID = ID;
this->name = name;
}
void print()
{
cout << "this->ID=" << this->ID << " ";
cout << "this->name=" << this->name << endl;
}
friend ostream& operator <<(ostream& output, student& stu)
{
output << "ID=" << stu.ID << " ";
output << "name=" << stu.name << endl;
return output;
}
};
template
class circlequeue
{
private:
temp data[queuesize];
int front;
int rear;
public:
circlequeue() { this->front = this->rear = 0; }
void enqueue(temp x);
temp dequeue();
temp getfront();
int getlength();
bool empty()
{
return this->front == this->rear ? true : false;
}
};
template
void circlequeue::enqueue(temp x)
{
if ((this->rear + 1) % queuesize == this->front) throw "overflow";
this->rear = (this->rear + 1) % queuesize;
this->data[this->rear] = x;
}
/*表扬这个取模运算,非常精彩*/
/*
解释一下overflow的判断条件:
什么叫“上溢”:
顾名思义,就是向上溢出,本来队列已经满了,现在再从队尾插入一个元素,
队头那个元素就被挤死了。想出去,我没执行出队函数;不出去,队尾又补充进来一个元素。
这种情况就叫做上溢。
循环队列也会面对一模一样的问题。
下面解释if ((this->rear + 1) % queuesize == this->front) throw "overflow";
假设循环队列长度为5,第一个位置储存front,最后一个位置储存rear。这个长度为5的队列里,有效数据(即除去front)有4个
现在我执行入队操作,rear往后移一位,(rear+1)%queuesize=1=front,那不就被挤住了嘛。
所以称作上溢。
*/
template
temp circlequeue::dequeue()
{
if (this->rear == this->front)throw"underflow";
this->front = (this->front + 1) % queuesize;
return this->data[this->front];
}
/*
同理我们来理解一下this->rear==this->front这个判断条件:
那就是队头和队尾相等,那就是空队列。空队列不能执行dequeue函数,
所以称之为下溢。
*/
template
temp circlequeue::getfront()
{
if (this->rear == this->front)throw"underflow";
return this->data[(this->front + 1) % queuesize];
}
template
int circlequeue::getlength()
{
return (this->rear - this->front + queuesize);
}
int main()
{
try
{
system("color 0A");
student stu[5] = { {1,"zhang"},{2,"wang"},{3,"li"},{4,"zhao"},{5,"liu"} };
circlequeue cq;
for (int i = 0; i < 5; i++)
cq.enqueue(stu[i]);
student tempstu;
cout << "now let's check if the queue is empty……" << endl;
cout << cq.empty() << endl;
for (int i = 0; i < 5; i++)
{
tempstu = cq.getfront();
cout << "before dequeue, the front data of the circlequeue is " << tempstu;
cout << "before dequeue, the length of the circlequeue is " << cq.getlength() << endl;
cout << "now we start to run the function dequeue……" << endl;
cq.dequeue();
cout << "deleted……" << endl << endl;
}
cout << "now let's recheck if the queue is empty……" << endl;
cout << cq.empty();
}
catch (const char* ss)
{
cout << ss << endl;
}
return 0;
}
1.为了实现链队列更加方便,在此规定对头指针所指位置永不存储队列元素,所以当队列满时,其长度实际为数组长度减1;
2.根据队列的性质,入队操作是对尾指针的操作,出队操作是对头指针的操作;
3.当对头指针和队尾指针指向头一个位置时,队列为空队列;
4.说说默认构造函数的一点心得:
template
linkqueue::linkqueue()
{
this->front = this->rear = new node ;
this->front->next = NULL;
}
说明:从默认无参构造函数我们可以看出:
当队列为空队列时,头指针和尾指针指向同一个位置;
从而我们可以反推出来:
当头指针和尾指针指向同一个位置时,
循环队列为空队列。
两者互为充要条件。
5.浅谈入队函数enqueue
template
void linkqueue::enqueue(temp x)
{
this->rear->next = new node;
this->rear = this->rear->next;
this->rear->data = x;
this->rear->next = NULL;
}
说明:根据队列的结构特点,
插入元素应该从队尾插入。
所以书写enqueue函数时,
我们是在对尾指针进行操作的。
6.说说dequeue函数中判断队列是否为空这条语句是啥意思:
template
temp linkqueue::dequeue()
{
node* p = this->front->next;
if (!p)throw"underflow";/*如果为空队列,抛出异常*/
this->front->next = p->next;
temp x = p->data;
delete p;
if (!(this->front->next))
this->rear = this->front;
return x;
}
解释一下if (!p)throw "underflow" ;这个语句为什么表示的是“如果队列为空队列,抛出异常”:
首先,如果一个队列为空队列,那么这个队列的头指针和尾指针指向同一个位置,头指针的下一个指针指向NULL;其次,运算符!表示“非”运算,返回值类型为布尔型;综上,如果指针p,也就是this->front->next==NULL,那么 !p 就等价于!this->front->next,就等价于!NULL,我们知道NULL是假值,那么!NULL就是真值,表示执行语句。翻译过来就是如果这件事情(也就是this->front->next==NULL)是真的,那我们执行throw "underflow"语句;
*********
//循环队列书上代码
//在此规定对头指针所指位置永不存储队列元素
//当队列满时,其长度实际为数组长度减1
//当队头指针和队尾指针指向同一个位置时,队列为空队列
#include
using namespace std;
const int queuesize = 1000;
class student
{
private:
int ID;
string name;
public:
student()
{
this->ID = 0;
this->name = "INVALID";
}
student(int ID, string name)
{
this->ID = ID;
this->name = name;
}
void print()
{
cout << "this->ID=" << this->ID << " ";
cout << "this->name=" << this->name << endl;
}
friend ostream& operator <<(ostream& output, student& stu)
{
output << "ID=" << stu.ID << " ";
output << "name=" << stu.name << endl;
return output;
}
};
template
struct node
{
temp data;
node* next;
};
template
class linkqueue
{
private:
node* front;
node* rear;
public:
linkqueue();
~linkqueue();
void enqueue(temp x);
temp dequeue();
temp getfront();
int getlength();
bool empty()
{
return (this->front == this->rear) ? true : false;
}
};
template
linkqueue::linkqueue()
{
this->front = this->rear = new node ;
this->front->next = NULL;
}
/*
说明:从默认无参构造函数我们可以看出:
当队列为空队列时,头指针和尾指针指向同一个位置;
从而我们可以反推出来:
当头指针和尾指针指向同一个位置时,
循环队列为空队列。
两者互为充要条件。
*/
template
void linkqueue::enqueue(temp x)
{
this->rear->next = new node;
this->rear = this->rear->next;
this->rear->data = x;
this->rear->next = NULL;
}
/*
说明:根据队列的结构特点,
插入元素应该从队尾插入。
所以书写enqueue函数时,
我们是在对尾指针进行操作的。
*/
template
temp linkqueue::dequeue()
{
node* p = this->front->next;
if (!p)throw"underflow";/*如果为空队列,抛出异常*/
this->front->next = p->next;
temp x = p->data;
delete p;
if (!(this->front->next))
this->rear = this->front;
return x;
}
/*
解释一下if (!p)throw"underflow";
这个语句为什么表示的是“如果队列为空队列,抛出异常”:
首先,如果一个队列为空队列,那么这个队列的头指针和尾指针指向同一个位置,
头指针的下一个指针指向NULL;
其次,运算符!表示“非”运算,返回值类型为布尔型;
综上,如果指针p,也就是this->front->next==NULL,
那么!p就等价于!this->front->next,就等价于!NULL,
我们知道NULL是假值,那么!NULL就是真值,表示执行语句
翻译过来就是如果这件事情(也就是this->front->next==NULL)是真的,
那我们执行throw "underflow"语句;
*/
template
temp linkqueue::getfront()
{
if (!this->front->next)throw"overflow";
return this->front->next->data;
}
template
linkqueue::~linkqueue()
{
while (this->front != NULL)
{
this->rear = this->front->next;
delete this->front;
this->front = this->rear;
}
}
template
int linkqueue::getlength()
{
node* p = this->front;
int cnt = 0;
while (p != this->rear)
{
cnt++;
p = p->next;
}
return cnt;
}
int main()
{
try
{
system("color 0A");
student stu[5] = { {1,"zhang"},{2,"wang"},{3,"li"},{4,"zhao"},{5,"liu"} };
linkqueue lq;
for (int i = 0; i < 5; i++)
lq.enqueue(stu[i]);
student tempstu;
cout << "now let's check if the queue is empty……" << endl;
cout << lq.empty() << endl;
for (int i = 0; i < 5; i++)
{
tempstu = lq.getfront();
cout << "before dequeue, the front data of the linkqueue is " << tempstu;
cout << "before dequeue, the length of the linkqueue is " << lq.getlength() << endl;
cout << "now we start to run the function dequeue……" << endl;
lq.dequeue();
cout << "deleted……" << endl << endl;
}
cout << "now let's recheck if the queue is empty……" << endl;
cout << lq.empty();
}
catch (const char*ss)
{
cout << ss << endl;
}
return 0;
}