数据结构:有序线性表类中,返回素数表
文章目录
一、题目描述
public SortedSeqList<Integer> creatPrime(int max)
//返回包含max在内的所有素数的顺序排序表
创建这么一种方法并通过实例实现其功能
二、设计思路
1.素数的定义
所有大于1的数字中,除了其本身和1之外没有别的因数的数叫做素数(Prime Number)
2.实现查找素数的方法
2.1 使用数组存储+排除法
假设小于等于max的数字全部存储在一个数组中,且数字与数组下标相同避免混乱。
逐一确认是否有除了1和本身之外的因数,如果有,则抹除该数字使其为0,没有则保留
- 伪代码如下
int[] arr= new int[max+1];
arr[0]=arr[1]=0;
for(int i=2;i<max+1;i++)
arr[i]=i;
如果能整除<i的任何一个整数,则不是素数;
{
使得该数组项arr[i]=0;
}
//得到一组素数和0;
if(arr[i]!=0)
insert这个数字进入SortedSeqList里面
2.2 直接循环实现插入
使用循环max-1次逐个判断是否为素数,并且判断一个插入一个
if(max<2)
{
提示输入错误并且返回空表
}
else
{
for(int i=2;i<=max;i++)
{
int judge =1;//使用judge来判断i有没有因数
for(int j=2;j < i;j++)
{
if(i%j == 0)
{
judge = -1;
break;
}
}
if(judge == 1)
insert这个数字进入SortedSeqList里面
}
}
3.实现返回素数表的方法
3.1使用静态方法
在SortedSeqList类中里面创建一个静态方法,就可以直接使用类名.createPrime调用而不用通过实例调用
3.2 直接在新的类中创建方法并应用
在新的类中写入成员方法createPrime,再在主函数中创建自己类的对象,调用该方法。
三、程序源码与结果
1. 静态方法
- 主程序源码
package code_02_2_3_insert;
import java.util.*;
public class PracticePrime {
public static void main(String[] args) {
int max=0;
System.out.println("请输入最大界限max");//交互提示,便于操作
Scanner reader = new Scanner(System.in);
max = reader.nextInt();
SortedSeqList<Integer> Prime = new SortedSeqList<Integer>();
Prime=SortedSeqList.createPrime(max);//调用静态方法,直接使用类名调用即可
for(int i=0;i<Prime.n;i++)
System.out.print(Prime.get(i)+" ");//打印输来检测结果
}
}
1.1 数组方法
- SortedSeqList类中源码
public static SortedSeqList<Integer> createPrime(int max)
{
SortedSeqList<Integer> pList = new SortedSeqList<Integer>();
if(max<2)
{
System.out.println("输入数字无效,返回空表");//交互提示
return pList;
}
else
{
int[] arr= new int[max+1];
arr[0]=arr[1]=0;
//设法得到含有插入数字的数组
for(int i=2;i< max+1;i++)
{
arr[i]=i;//赋予初值
for(int j=2;j<i;j++)//排除不是素数的数字
{
if(i%j == 0)
{
arr[i]=0;
break;
}
}
}
//将有顺序的数组选择性的插入排序顺序表
for(int i=2;i<max+1;i++)
{
if(arr[i] != 0)
{
pList.insert(arr[i]);
}
}
return pList;
}
}
-
运行结果:对比上述素数表可以知道答案是正确的
-
时间复杂度(max=n)
循环嵌套,最外层循环 n − 1 n-1 n−1 次,内层每次循环 ≤ i − 1 \leq i-1 ≤i−1, 所以最大循环次数为 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1)
插入循环是简单循环,共循环 n − 1 n-1 n−1 次
所以最后循环次数最大为 n ( n − 1 ) 2 + ( n − 1 ) \frac{n(n-1)}{2} + (n-1) 2n(n−1)+(n−1) , 时间复杂度为 O ( n 2 ) O(n^2) O(n2)
1.2 直接循环实现
- SortedSeqList类中源码
public static SortedSeqList<Integer> createPrime(int max)
{
SortedSeqList<Integer> pList = new SortedSeqList<Integer>();
if(max<2)
{
System.out.println("输入数字无效,返回空表");
return pList;
}
else
{
for(int i=2;i<=max;i++)
{
//逐个判断i有没有因数
int judge = 1;//judge为判断i有无因数的标识
for(int j=2; j<i; j++)
{
if(i%j == 0)
{
judge=-1;
break;
}
}
if(judge == 1)
{
pList.insert(i);//将判断出来的每个素数插入表格中
}
}
return pList;
}
- 运行结果:对比上述素数表可以知道答案是正确的
-
时间复杂度
循环嵌套,最外层循环 n − 1 n-1 n−1 次,内层每次循环 ≤ i − 1 \leq i-1 ≤i−1, 所以最大循环次数为 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1)
所以最后的时间复杂度为 O ( n 2 ) O(n^2) O(n2)
2.写入新类中直接调用
2.1 数组法
- 源码
package code_02_2_3_insert;
import java.util.*;
public class PracticePrime {
//************************************//与1.1数组法的方法体是一致的,可以不看
public SortedSeqList<Integer> createPrime(int max)
{
SortedSeqList<Integer> pList = new SortedSeqList<Integer>();
if(max<2)
{
System.out.println("输入数字无效,返回空表");//交互提示
return pList;
}
else
{
int[] arr= new int[max+1];
arr[0]=arr[1]=0;
//设法得到含有插入数字的数组
for(int i=2;i< max+1;i++)
{
arr[i]=i;//赋予初值
for(int j=2;j<i;j++)//排除不是素数的数字
{
if(i%j == 0)
{
arr[i]=0;
break;
}
}
}
//将有顺序的数组选择性的插入排序顺序表
for(int i=2;i<max+1;i++)
{
if(arr[i] != 0)
{
pList.insert(arr[i]);
}
}
return pList;
}
}
//*************************************主函数
public static void main(String[] args) {
int max=0;
System.out.println("请输入最大界限max");//交互提示
Scanner reader = new Scanner(System.in);
max = reader.nextInt();
PracticePrime Prime2 = new PracticePrime();//创建自己类的实例Prime2
SortedSeqList<Integer> pList = new SortedSeqList<Integer>();//创建一个整型排序顺序表
pList=Prime2.createPrime(max);//调用静态方法
System.out.println(pList.toString());//打印字符串
}
}
- 运行结果:对比上述素数表可以知道答案是正确的
-
时间复杂度
同本小节1.1(因为方法内容一样)为 O ( n 2 ) O(n^2) O(n2)
2.2直接循环
- 源码
public SortedSeqList<Integer> createPrime(int max)
{//*************************与2.1直接循环的方法体是一致的,可以不看
SortedSeqList<Integer> pList = new SortedSeqList<Integer>();
if(max<2)
{
System.out.println("输入数字无效,返回空表");
return pList;
}
else
{
for(int i=2;i<=max;i++)
{ //逐个判断i有没有因数
int judge = 1;//judge为判断i有无因数的标识
for(int j=2; j<i; j++)
{
if(i%j == 0)
{
judge=-1;
break;
}
}
if(judge == 1)
{
pList.insert(i);
}
}
return pList;
}
}
//********************************************主函数!!
public static void main(String[] args) {
int max=0;
System.out.println("请输入最大界限max");//交互提示
Scanner reader = new Scanner(System.in);
max = reader.nextInt();
PracticePrime Prime2 = new PracticePrime();//创建自己类的实例Prime2
SortedSeqList<Integer> pList = new SortedSeqList<Integer>();//创建一个整型排序顺序表
pList=Prime2.createPrime(max);//调用静态方法
System.out.println(pList.toString());//打印字符串
}
}
- 运行结果与时间复杂度同上,此处略
六、分析评价
1.容错性
此处因为传入的参数只有一个max,所以比较简单,只需要考虑max不符合素数最大界限的条件时候的容错即可,即max<=2的时候将没有对应的素数
if(max<2)
{ …… }
else
{ …… }
2.交互性
1)提示错误:当传入的参数max不符合获取素数的条件的时候,输出交互反馈
2)通过流获取max:对调试的便捷性有很大的帮助
3.高效性
此处使用了两种方法去编写输出素数排序顺序表的具体内容,通过分析得到二者的时间复杂度都是 O ( n 2 ) O(n^2) O(n2) ,所以采用而用二者在时间损耗上面并无太大区别。而且因为程序内容简单,执行起来也十分高效快速。
五、细节探究
1.静态方法vs新类一般方法
使用静态方法的时候可以用类直接调用,不需要通过实例;
但是在此处方法的返回类型是确认了表内数据类型的有序顺序表而不是泛型表,与类定义中的其它基本方法类型不是十分一致,放在一起不是十分恰当。
- 拓展:其实可以在新类里面将方法设置为静态的,可以不通过实例调用,更加方便。
public class PracticePrime {
public static SortedSeqList<Integer> createPrime(int max){……}
public static void main(String[] args) {
~
SortedSeqList<Integer> pList=PracticePrime.createPrime(max);
//调用静态方法
~
}
2.声明实例vs创建实例
因为方法createPrime返回的类型是一个有序顺序表,而且方法内部有创建(New)了一个表,所以在调用该方法的时候其实只需要声明即可,可是节省内存空间,避免浪费。
即:
//静态方法
SortedSeqList<Integer> pList;
pList = SortedSeqList<Integer>.creatPrime();
//新类一般方法
PracticePrime Prime2 = new PracticePrime();//创建PracticePrime类的实例Prime2
SortedSeqList<Integer> pList =Prime2.createPrime(max);//调用方法返回一个表给pList
//新类的静态方法:比一般方法空间利用率高
SortedSeqList<Integer> pList=PracticePrime.createPrime(max);
3.打印线性表
- 使用System.out.println和SortedSeqList里面的get()方法结合
- 使用get方法中的toString()先转化,在打印整个字符串