java的运行效率问题(求解!!!)

简介: java的运行效率问题(求解!!!)

在我java做数据结构的题时,对于java运行效率一直都很费解!!!

看似改进了代码,但是运存和运行时间并没改变!


“改进”前的代码:


import java.util.*;
public class Main {
    //初始数组
    public static int[] array;
    //维护set集合的list
    public static List<Set<Integer>> setArray=new ArrayList<>();
    public static void main(String[] args) {
        //提前声明,避免在循环中声明占内存
        int z,a,b;
        //创建一个文本扫描器检测键盘输入
        Scanner scanner=new Scanner(System.in);
        //N个元素
        int N=scanner.nextInt();
        //M个操作
        int M=scanner.nextInt();
        //初始化array,确保下标即为对应的值
        array=new int[N+1];
        for (int i=0;i<N+1;i++){
            array[i]=i;
        }
        //循环操作
        for (int i=0;i<M;i++){
            z=scanner.nextInt();
            a=scanner.nextInt();
            b=scanner.nextInt();
            if (z==1){
                merge(a,b);
            }else if (z==2){
                findTwo(a,b);
            }
        }
    }
    /**
     * 1.首先在数组中查找,找到则说明不在一起
     * 2.若未找到则到list中遍历查找,返回所在集合(若在数组中则返回null)
     * 注意:不必遍历,因为每个数组的下标即为它的值
     * @param a
     * @return
     */
    private static Set<Integer> findOne(int a){
        if (array[a]!=0){
            return null;
        }
        //在维护set集合的数组中遍历
        for (Set<Integer> set:setArray){
            //调用contain方法,若存在则返回该集合
            if (set.contains(a)){
                return set;
            }
        }
        //这道题不可能执行到这步,除非系统想搞我们!当然我们也不怕
        return null;
    }
    /**
     * 1.调用findOne查找a所在集合
     * 2.在集合中查找是否存在b
     * 3.若有则输出打印Y,没有则N
     * @param a
     * @param b
     */
    public static void findTwo(int a,int b){
        Set<Integer>set=findOne(a);
        if (set==null){
            //集合为空时,即a在数组中时输出N
            System.out.println("N");
        }else if (set.contains(b)){
            System.out.println("Y");
        }else{
            //不包含时输出N
            System.out.println("N");
        }
    }
    /**
     * 1.用私有方法findOne查询a,b所在集合
     * 2.合并
     * @param a
     * @param b
     */
    public static void merge(int a,int b){
        Set<Integer> set1=findOne(a);
        Set<Integer> set2=findOne(b);
        //分别讨论几种情况
        if (set1==null&&set2!=null){
            set2.add(a);
            //原来数组的值清0
            array[a]=0;
        }else if (set1!=null&&set2==null){
            set1.add(b);
            array[b]=0;
        }else if (set1==null&&set2==null){
            //此时需要创建一个set集合,并清0
            Set<Integer> set=new HashSet<Integer>();
            set.add(a);
            set.add(b);
            //别忘了加入list集合,粗心的我就忘了!汗。。。
            setArray.add(set);
            array[a]=0;
            array[b]=0;
        }else {
            //判断两个集合是否相等
            if (set1!=set2){
                //确保小的集合加入大的集合
                if (set1.size()<set2.size()){
                    set2.addAll(set1);
                    //把多余的set集合清出list,粗心的我又忘了......
                    setArray.remove(set1);
                }else {
                    set1.addAll(set2);
                    setArray.remove(set2);
                }
            }
        }
    }
}



时间效率如下图:

q2.png


我做出了改进,缩短了很多代码,而且避开使用封装好的类,尽量写底层代码,以争取尽可能好的效果


可是。。。。。。。


以下是我“改进后”代码:


import org.w3c.dom.Node;
import java.util.*;
public class Main {
    //此数组下标即为其data
    public static int[] array;
    public static void main(String[] args) {
        //提前声明,避免在循环中声明占内存
        int z,a,b;
        //创建一个文本扫描器检测键盘输入
        Scanner scanner=new Scanner(System.in);
        //N个元素
        int N=scanner.nextInt();
        //M个操作
        int M=scanner.nextInt();
        //初始化array,确保下标即为对应的值
        array=new int[N+1];
        for (int i=0;i<N+1;i++){
            //初始化数组,-1表示根节点,且该集合规模为1(根节点值得绝对值表示该树的大小,负号表示根节点),即初始化时每个数都是单个集合
            array[i]=-1;
        }
        //循环操作
        for (int i=0;i<M;i++){
            z=scanner.nextInt();
            a=scanner.nextInt();
            b=scanner.nextInt();
            if (z==1){
                merge(a,b);
            }else if (z==2){
                check(a,b);
            }
        }
    }
    /**
     *
     * @param a
     * @return
     */
    private static int findOne(int a){
        if (array[a]<0){
            return a;
        }else{
            //先把值存下来以便按秩递归
            int temp=array[a];
            //据说是伪递归,编译的时候会自动写成循环,不知道jvm会不会这么做
            //存疑
            return array[a]=findOne(temp);
        }
    }
    /**
     * 1.调用findOne查找a所在集合
     * 2.在集合中查找是否存在b
     * 3.若有则输出打印Y,没有则N
     * @param a
     * @param b
     */
    public static void check(int a,int b){
        int m=findOne(a);
        int n=findOne(b);
        if (m!=n){
            System.out.println("N");
        }else {
            System.out.println("Y");
        }
    }
    /**
     * 1.用私有方法findOne查询a,b所在集合
     * 2.合并
     * @param a
     * @param b
     */
    public static void merge(int a,int b){
        int m=findOne(a);
        int n=findOne(b);
        if (m!=n){
            if (array[m]<=array[n]){
                array[n]+=array[m];
                array[m]=n;
            }else{
                array[m]+=array[n];
                array[n]=m;
            }
        }
    }
}

结果如图:

q1.png

可以发现结果并没有什么改进,甚至比原来的运行效率还要低,这就是我不能理解的地方,希望有能力的大佬能解答一下。


相关文章
|
Java
使用IDEA创建项目运行我的第一个JAVA文件输出Helloword
本文介绍了如何使用IDEA(IntelliJ IDEA)创建一个新的Java项目,并运行一个简单的Java程序输出"Hello Word"。文章详细展示了创建项目的步骤,包括选择JDK版本、设置项目名称和路径、创建包和类,以及编写和运行代码。最后,还展示了如何通过IDEA的运行功能来执行程序并查看输出结果。
1321 4
使用IDEA创建项目运行我的第一个JAVA文件输出Helloword
|
10月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
642 7
|
Java
Java关键字 —— super 详细解释!一看就懂 有代码实例运行!
文章详细解释了Java关键字`super`的用途,包括访问父类的成员变量、调用父类的构造方法和方法,并提供了相应的代码实例。
1265 5
Java关键字 —— super 详细解释!一看就懂 有代码实例运行!
|
Java Apache Maven
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
文章提供了使用Apache POI库在Java中创建和读取Excel文件的详细代码示例,包括写入数据到Excel和从Excel读取数据的方法。
187 6
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
|
Java 编译器 C++
【Java基础面试一】、为什么Java代码可以实现一次编写、到处运行?
这篇文章解释了Java能够实现“一次编写,到处运行”的原因,主要归功于Java虚拟机(JVM),它能够在不同平台上将Java源代码编译成的字节码转换成对应平台的机器码,实现跨平台运行。
【Java基础面试一】、为什么Java代码可以实现一次编写、到处运行?
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
824 2
|
分布式计算 大数据 Java
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
305 1
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
|
IDE Java 编译器
Java:如何确定编译和运行时类路径是否一致
类路径(Classpath)是JVM用于查找类文件的路径列表,对编译和运行Java程序至关重要。编译时通过`javac -classpath`指定,运行时通过`java -classpath`指定。IDE如Eclipse和IntelliJ IDEA也提供界面管理类路径。确保编译和运行时类路径一致,特别是外部库和项目内部类的路径设置。
849 5
|
Java
Java关键字 —— super 与 this 详细解释!一看就懂 有代码实例运行!
本文介绍了Java中this和super关键字的用法,包括在构造方法中使用this来区分参数和成员变量、使用super调用父类构造方法和方法,以及它们在同一个方法中同时使用的场景。
683 0
Java关键字 —— super 与 this 详细解释!一看就懂 有代码实例运行!
|
Java
Java关键字 —— static 与 final 详细解释!一看就懂 有代码实例运行!
这篇文章详细解释了Java中static和final关键字的用法,包括它们修饰类、方法、变量和代码块时的行为,并通过代码示例展示了它们的具体应用。
986 0
Java关键字 —— static 与 final 详细解释!一看就懂 有代码实例运行!