1、何为队列?
队列是一个有序列表,可以用数组or链表来实现。跟排队一样,先入先出,即:先存入队列的数据先取出,后存入的数据后取出
2、一次性的队列代码示例
public class suanfa {
//一次性队列问题
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
duilie dl = new duilie(3);
System.out.println("请输入您想进行的操作:\n" +
"1、显示队列所有元素\n" +
"2、取出队列的数据\n" +
"3、向队列中添加数据\n" +
"4、显示头数据\n" +
"5、退出系统");
boolean flag = true;
while(flag){
int i = in.nextInt();
//一定要注意这句话放在循环内部!!不然就输入一个数后一直操作此数据对应的功能了!
switch(i){
case 1:
dl.getall();
break;
case 2:
dl.get();
break;
case 3:
System.out.println("请输入你想添加的数据:");
int l = in.nextInt();
dl.add(l);
break;
case 4:
dl.showhead();
break;
case 5:
in.close();
flag = false;
System.out.println("程序已退出!");
break;
default:
break;
}
}
}
}
class duilie{
//队列的生成
private int maxsize;//队列数组最长长度
private int front;//头结点
private int rear;//尾结点
int []arry;//定义队列数组
public duilie(int max){
maxsize = max;
front = -1;
rear = -1;
arry = new int[maxsize];
}
//判断队列是否为空
public boolean isempty(){
if(front == rear){
return true;
}
else {
return false;
}
}
//判断队列是否已满
public boolean isfull(){
if(rear == (maxsize - 1)){
return true;
}else{
return false;
}
}
//添加数据
public void add(int n){
if(isfull()){
System.out.println("数据已满!");
}else{
rear++;
arry[rear] = n;
System.out.println("添加成功!");
}
}
//取出队列的数据值(下段代码并没有将数据取出来,只是把front指针后移了)
public void get(){
if(isempty()){
System.out.println("队列中没有数据!");
}else{
front++;
System.out.println("取出的数据为:" + arry[front]);
}
}
//获取队列的所有数据值
public void getall(){
if(isempty()){
System.out.println("队列中没有数据!");
}else{
for(int i = 0;i < arry.length;i++){
System.out.print("第" + (i + 1) + "个数值为:" + arry[i] + "\n");
}
}
}
//显示队列的头数据
public void showhead(){
if(isempty()){
System.out.println("队列中没有数据!");
}else{
front++;
System.out.println("队列的头数据为:" + arry[front]);
}
}
}
3、一次性队列的问题分析及优化
1>目前数组使用一次就不能用,没有达到复用的效果。详情参见代码中:取出队列的数据值,即get()方法,只是指针后移,但是数据并没有删除,空间依旧被占用着。
2>将这个数组使用算法,改进成一个环形的%
碎碎念:看到弹幕上的这些话要笑喷了🤣你以为老师错了,实际上老师站在大气层在教你🤣
4、循环队列
1>front变量的含义调整为:front指向队列的第一个元素,即front的初始值为0,arry[front]就是队列的第一个元素
2>rear变量的含义调整为:rear指向队列最后一个元素的后一个位置,且rear指向的位置元素为空,便于判断队列满or空
3>元素进队后rear所在位置:rear = (rear + 1)% maxsize
4>队满的条件为:(rear + 1)% maxsize == front
5>队空的条件为:rear == front
6>队列中有效的数据个数为:有效个数为:(rear + maxsize - front)% maxsize
对<6>进行解析:
当rear > front时,可以理解为:
则有效数据的个数即为数轴上front和rear之间的长度,又由于rear指向的是一个空数据的空间,故长度为:(rear - 1)- front + 1,化简得:rear - front
当rear < front时,可以理解为:
此时rear - front 为负数,也就是没有存数据的空间量,则与maxsize相加后得到的就是队列中真正的数据量了,即:(rear - front + maxsize)% maxsize
5、循环队列的分析
假设H还未入队,则rear指向H所在处。
当H入队,则rear的位置应该为:(7 + 1)% maxsize,其中maxsize为8,则结果为0,故rear指向0号位置。
同理,I入队。
此时若不留出一个空位置,则再进入一个数据时,rear == front代表队满,而当队空时也满足此条件,所以采取这种方式的话,需要另设一个标识符或者count统计,太麻烦了,于是我们采取少用一个元素空间的方法。
▲以上视频对我帮助较大
6、循环队列代码
public class suanfa_02 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
CirleDuilie dl = new CirleDuilie(4);//设置数组长度为4,有效数据长度最大为3
System.out.println("请输入您想进行的操作:\n" +
"1、显示队列所有元素\n" +
"2、取出队列的数据\n" +
"3、向队列中添加数据\n" +
"4、显示头数据\n" +
"5、退出系统");
boolean flag = true;
while(flag){
int i = in.nextInt();
switch(i){
case 1:
dl.getall();
break;
case 2:
dl.get();
break;
case 3:
System.out.println("请输入你想添加的数据:");
int l = in.nextInt();
dl.add(l);
break;
case 4:
dl.showhead();
break;
case 5:
in.close();
flag = false;
System.out.println("程序已退出!");
break;
default:
break;
}
}
}
}
class CirleDuilie{
//循环队列的生成
private int maxsize;//循环队列的长度
private int front;//头结点,若不赋值,则int类型的变量默认为0
private int rear;//尾结点,若不赋值,则int类型的变量默认为0
private int []arry;//定义队列数组
public CirleDuilie(int max){
maxsize = max;
arry = new int[maxsize];
}
//判断循环队列是否为空
public boolean isempty(){
return front == rear;
}
//判断队列是否已满
public boolean isfull(){
return front == (rear + 1) % maxsize;
}
//添加数据
public void add(int n){
if(isfull()){
System.out.println("数据已满!");
}else{
arry[rear] = n;
rear = (rear + 1) % maxsize;
System.out.println("添加成功!");
}
}
//取出循环队列的数据值
public void get(){
if(isempty()){
System.out.println("队列中没有数据!");
}else{
System.out.println("取出的数据为:" + arry[front]);
front = (front + 1) % maxsize;
}
}
//获取循环队列的有效数据长度
public int getlength(){
return (rear - front + maxsize) % maxsize;
}
//显示队列的所有数据值
public void getall(){
if(isempty()){
System.out.println("队列中没有数据!");
}else{
//让循环队列进行有效循环,循环长度可以采取:从起始开始,延伸了有效数据个数的长度
for(int i = front;i < front + getlength();i++){
//这里一定要注意,输出的数据在数组中的位置要%maxsize!!
System.out.print("第" + (i % maxsize) + "个数值为:" + arry[i % maxsize] + "\n");
}
}
}
//显示循环队列的头数据
public void showhead(){
if(isempty()){
System.out.println("队列中没有数据!");
}else{
System.out.println("队列的头数据为:" + arry[front % maxsize]);
}
}
}
7、总结
1>提示“Duplicated code fragment”时,代表:在同一个项目里,于不同的文件中存在有相同的代码块
2>使用Scanner in = new Scanner(System.in)后,可以调用in.close()方法,调用后,在接下来的代码中无法再使用Scanner,即使再声明一次也无法使用Scanner
在上述示例中,运行结果为:程序已退出!
所以为什么要去调用in.close()方法?
如果创建了Scanner对象,却不关闭,那么在方法结束后,Scanner对象并不会立刻进入被回收的队列中,这就使得计算机有一定的负担。如果确定之后不会再使用Scanner,那么也可以提前终止。
3>直接输出Java中的类,得到的结果:自动调用getClass().getName() + '@' + Integer.toHexString(hashCode()),也就是每个Java类自带的toString()方法。@后面的表示十六进制的哈希值。
4>快速生成对象快捷键:Ctrl+Alt+v
5>自得人生哲理之一:不去主动伤害别人,但是当被伤害时,不要给自己担上气氛调节的责任,该发脾气就发,考虑别人时,别人不一定去考虑你。