HOW2J的JAVASE刷题一

容器

1.(比较器)自定义顺序的TreeSet

题目:默认情况下,TreeSet中的数据是从小到大排序的,不过TreeSet的构造方法支持传入一个Comparator,使其倒序输出:

Comparator<? super Integer> c;	
	private ArrayList<Integer> list=new ArrayList<>();	
	public TreeSet(Comparator<? super Integer> c) {
   		
		this.c=c;
	}	
	//正序输出
	public TreeSet() {
   
		this.c=new Comparator<Integer>() {
   
			@Override
			public int compare(Integer o1, Integer o2) {
   
				return o1-o2;//正就正序输出,负就反序输出
			}		
		};
	}
	
	public void add(int n) {
   
		list.add(n);
	}
	
	@Override
	public String toString() {
   
		// TODO Auto-generated method stub
		Collections.sort(list,c);
		return list.toString();
	}

	public static void main(String[] args) {
   		
		TreeSet t=new TreeSet(new Comparator<Integer>() {
   
			@Override
			public int compare(Integer o1, Integer o2) {
   
				// TODO Auto-generated method stub
				return o2-o1;
			}	
		});		
		//TreeSet t=new TreeSet();		
		t.add(1);
		t.add(5);
		t.add(3);
		System.out.println(t);	
	}

java库里面是有TreeSet函数的。我这里重新写了一个。
总结: 重载构造器里面传递是对象参数,Collections.sort()需要的是一个对象,这个对象能够提供比较哪一个参数的信息。与之前遇到的相似,重载函数是把内容传递给成员变量(类属性),通过这种方式去改变成员变量的值。此外,也可以不传递给成员变量,可以仅仅无用的工作。

2.(几种Set)用LinkedHashSet实现PI的函数

题解:1.第一种思路是利用LinkedHashSet的元素不重复,且按照插入顺序排序,那么其size()最多为10,那么就可以采取取余计算,代码如下:

LinkedHashSet<Integer> numberSet2 =new LinkedHashSet<Integer>();
boolean pi=true;
double p=Math.PI;
while(pi){
   
	if(numberSet2.size()==10) break;
	numberSet2.add((int) (p%10));
	p*=10;
}		
System.out.println(numberSet2);

输出结果为:

[3, 1, 4, 5, 9, 2, 6, 8, 7, 0]

上面的题解虽然可以,但是有一个问题就是其准确度有待考察,因为double类型只能够保证小数点后15位为精确的,超过的部分就是不准确的,所以*10不太准确,从这个算法来看0可能是系统带来的误差。

java中double只考虑小数点15位,所以在运算的时候也是优先15位的运算,在转为字符数组的时候就是小数点15位。

观察如下代码:

double dou=(double)(10)/3.;
System.out.println(dou);
for(int i=0;i<1000;i++) {
   
	System.out.print((int)(dou%10));
	dou*=10;
}

运算结果:

3333333333333334408602464042028080024004086208044040

题解:2.可以先将Math.PI转换为字符数组,然后将字符数组元素添加到LinkedHashSet中去。在这里面首先得知道转换为字符数字的时候,PI的位数就是double提供的位数,而题解1中的位数随着*10运算,不断显示小数点最后的数字。

LinkedHashSet<Character> numberSet3 =new LinkedHashSet<Character>();
String str = String.valueOf(Math.PI);
System.out.println(str);
String k=str.replace(".", "");
char[] cha=k.toCharArray();
	for(char c:cha) {
   
		numberSet3.add(c);
	}
System.out.println(numberSet3);

题解:3.与2相似,容器中加入的不是字符而是字符串

LinkedHashSet<String> numberSet4=new LinkedHashSet<>();
String str = String.valueOf(Math.PI);
String k=str.replace(".", "");
for(int i=0;i<k.length();i++) {
   
		numberSet4.add(String.valueOf(k.charAt(i)));
}
System.out.println(numberSet4);

IO

1.遍历文件夹

题目:(文件对象)一般说来操作系统都会安装在C盘,所以会有一个 C:\WINDOWS目录。遍历这个目录下所有的文件(不用遍历子目录)找出这些文件里,最大的和最小(非0)的那个文件,打印出他们的文件名
题解:1.我自己的想法就是对于定位问题,可以使用HashMap来做(快速),从而来解决由此来带的各种问题,最终从解决问题的角度看,还有一些不足,通过get(key)函数,获取到的File对象只有一个,万一要是有两个呢?put函数在放key相同时会覆盖掉之前的那个键对值。
代码如下:

//时间复杂度为O(n)
File file3=new File("C:/Windows");
File[] file33=file3.listFiles();
long s=0;
TreeSet<Long> filelength=new TreeSet<>();
for(int i=0;i<file33.length;i++) {
   
	filelength.add(file33[i].length());
}
		
if (filelength.first()==0) {
   
	s=filelength.higher((long) 0);
	System.out.println("最小字节单位"+filelength.higher((long) 0));
} else {
   
	System.out.println("最小字节单位0");
}

System.out.println("最大字节单位"+filelength.last());
HashMap<Long,File> hashmap=new HashMap<>();
for(int i=0;i<file33.length;i++) {
   
			hashmap.put(file33[i].length(), file33[i]);
}

System.out.println(hashmap.get(s));//最小文件
System.out.println(hashmap.get(filelength.last()));//最大文件

题解:2.采用递归的办法去找到字节最大和最小的文件,并输出字节长度

//时间复杂度为O(n)
	public static void searchfile(File[] file,long minl) {
   
		long minlength=minl;
		boolean s=true;
		int k=0;
		
		for(int i=0;i<file.length;i++) {
   
			if (s) {
   
				if (file[i].length() < minlength && file[i].length() != 0) {
   
					System.out.println("最小字节为:" + file[i].length() + " 位置在: " + file[i]);
					s = false;
				}
			}
			//代码块A
			if (!s) {
   
				if (i != 0&&k==0) {
   
					i = 0;
					k=1;
					continue;
				}
				if (file[i-1].length() > file[i].length()) {
   
					File temp = file[i-1];
					file[i-1] = file[i];
					file[i] = temp;				
				}
				if(i==file.length-1) 
					System.out.println("最大字节为:" + file[file.length-1].length() + "位置在:" + file[0]);
			}	
		}
//代码块B		
//		if (!s) {
   
//			for (int j = 0; j < file.length - 1; j++) {
   
//				if (file[j].length() > file[j+1].length()) {
   
//					File temp = file[j];
//					file[j] = file[j+1];
//					file[j+1] = temp;				
//				}
//			}
//			System.out.println("最大字节为:" + file[file.length-1].length() + "位置在:" + file[0]);
//		}
	
		if(s) searchfile(file,++minlength);	//这是一个非常容易出错的地方++a
	}
	
	public static void main(String[] args) {
   
		// TODO Auto-generated method stub
		File file=new File("C:/Windows");
		File[] files=file.listFiles();
		
		long time1=System.currentTimeMillis();
		searchfile(files,0);
		long time2=System.currentTimeMillis();
		System.out.println("运行时间为:"+(time2-time1)+"ms");		
	}

通过构造一个递归函数,输出是文件数组和最小字节,递归就是能够创造一个无限循环,直至满足条件循环终止!所以必须得找一个循环终止的条件。上面的办法计算量还有点不好的地方在于,如果文件最小字节比较大,从0开始将会导致计算时间很久,所以如果将文件本身的字节长度放进输入参数里面去,将会减少运算次数。

//时间复杂度为O(n) 
public class TestFileD {
   
	int i=0;
	File minf;
	File maxf;
	long minl=Integer.MAX_VALUE;
	long maxl=0;
		
	public static void main(String[] args) {
   
		File file=new File("C:/Windows");
		File[] files=file.listFiles();
		TestFileD f=new TestFileD();	
		long time1=System.currentTimeMillis();
		f.search(files);
		long time2=System.currentTimeMillis();
		System.out.println("最小文件: "+f.minf+" ,最小文件长度 "+f.minf.length());
		System.out.println("最大文件: "+f.maxf+" ,最大文件长度 "+f.maxf.length());	
		System.out.println(time2-time1);
	}
	
	private void search(File[] files) {
   
		if(i>=files.length) {
   
			return ;
		}else {
   
			if(files[i].length()<minl&&files[i].length()>0) {
   
				minf=files[i];	
				minl=files[i].length();
			}
			if(files[i].length()>maxl) {
   
				maxf=files[i];
				maxl=files[i].length();
			}
		}
		if(i++<files.length) search(files);		
	}
}

总结: 递归是一种看不见“for”的循环,因为递归需要满足一定的条件才能进行递归,递归最后就是总是得有一个结束的条件,否则就进入了死循环。在递归里面,1.每一次递归要干什么事情,这件事情必须是基础性的;2.每一次递归有无条件,这决定了递归的有限性;3.在下一次递归中,如何利用前面递归得到的结果。

2.写入数据到文件

题目:OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据。注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。但是如果是文件 d:/xyz/lol2.txt,而目录xyz又不存在,会抛出异常

File nfil=new File("F:/Dashuaige/cdk/fhg/ds/wwd/nfil.txt");
		if(nfil.getParentFile().mkdirs()) {
   
			System.out.println("创建了文件"+!nfil.getParentFile().mkdirs());
		} 
		
		System.out.println(nfil.getParent());
		
		byte[] k= {
   'a','b'};

		try {
   
			FileOutputStream fuck = new FileOutputStream(nfil);
			
			try {
   
				fuck.write(k);
			} catch (IOException e) {
   
				e.printStackTrace();
			}
			try {
   
				fuck.close();
			} catch (IOException e) {
   
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		} catch (FileNotFoundException e1) {
   
			// TODO Auto-generated catch block
			e1.printStackTrace();        
		}    

利用mkdirs()函数,创建F:/Dashuaige/cdk/fhg/ds/wwd这一系列的文件夹,包括wwd也是一个文件夹,如果wwd在父目录下已经被命名过了,那么创建失败。如果父文件夹不存在,那么将会创建父文件夹。如果父文件夹存在,那么只创建自身命名的文件夹(例:ds存在,wwd不存在,那么将创建wwd)。
比较:mkdis()函数,如果父文件夹存在,那么创建;父文件夹不存在,创建无效。

3.拆分文件

题目:找到一个大于100k的文件,按照100k为单位,拆分成多个子文件,并且以编号作为文件名结束。比如文件 eclipse.exe,大小是309k。拆分之后,成为eclipse.exe-0;eclipse.exe-1;eclipse.exe-2;eclipse.exe-3
题解:

public static void main(String[] args) throws IOException {
   	
		get("F:/Wangchuang/execise.docx");	
	}
	
	//主体程序输出
	public static void get(String filepath) throws IOException {
   
		File file=new File(filepath);
		FileInputStream filestream=new FileInputStream(file);
		if(file.length()*1024>Integer.MAX_VALUE) {
   
			System.out.println("文件内存太大");
		}else {
   
			byte[] filebyte = new byte[(int) file.length()];
			filestream.read(filebyte);
			filestream.close();
			int count=(int)(file.length()/1024/100)+1;
			for(int k=0;k<count;k++) {
   
				writefile(file,k).write(get(filebyte,k*1024*100,(k+1)*1024*100));
			}			
		}
	}
	
	//返回每一个文件要读入的字节数组
	public static byte[] get(byte[] filebyte,int start,int end) {
   	
		
		if(end>filebyte.length) {
   
			end=filebyte.length;
		}
		
		byte[] exebyte=new byte[end-start];
		for(int i=start;i<end;i++) {
   
			exebyte[i-start]=filebyte[i];
		}		
		return exebyte;
	}
	
	//创建文件
	public static FileOutputStream writefile(File file,int i) throws FileNotFoundException {
   
		File exe=new File(file.getParent()+"/eclipse.exe-"+i);
		return new FileOutputStream(exe);	
	}

4.合并文件

题目:将上一题分解的文件合并起来,并查看能否运行。
题解:1.分别将文件以字节流的形式read到一个字节数组当中;将字节数组write到一个新的文件当中。2.所以最关键的部分是第一步,怎么将文件以字节流的形式放到字节数组中。

public static void body(String filepath) throws IOException {
   
		File file=new File(filepath);
		File[] files=file.listFiles();
		long  size=0;
		for(File f:files) {
   
			size=size+f.length();
		}
		byte[] bossbyte=new byte[(int) size];
		System.out.println(size);
		File bossfile=new File(filepath+"/boss.docx");
		//得到bossbyte
		int k=0;
		for (int j = 0; j < files.length; j++) {
   
			if(j==0) {
   
				k=0;
			}else {
   
				k=k+(int) files[j-1].length();
			}	
			for(int i=0;i<files[j].length();i++) {
   			
				bossbyte[i+k]=insertbyte(files[j])[i];					
			}
		}
		FileOutputStream bossfilestream=new FileOutputStream(bossfile);
		bossfilestream.write(bossbyte);
		bossfilestream.close();
		
	}
	
	//用byte
	public static byte[] insertbyte(File file) throws IOException {
   
		byte[] bytes=new byte[(int) file.length()];
		FileInputStream fos=new FileInputStream(file);
		fos.read(bytes);
		fos.close();
		return bytes;
	}
	
	public static void main(String[] args) throws IOException {
   
		body("F:/Wangchuang/eclipse");	
	}	

这个程序运行时间很久,运行了38523ms。里面有大量的循环,执行循环要花费时间很久。

对这个算法做一点修改,运算速度提高十倍:

	byte[] byte11=insertbyte(files[j]);
	long time1=System.currentTimeMillis();	
	for(int i=0;i<files[j].length();i++) {
   			
		bossbyte[i+k]=byte11[i];					
	}			
	long time2=System.currentTimeMillis();

执行循环的时候,每一次循环都要调用函数,现在只调用一次,就把时间提高了十倍。

		public static void getbody(String filepath) throws IOException {
   
		StringBuffer sb=new StringBuffer();
		File file=new File(filepath);
		File files[]=file.listFiles();
		String s="";
		for(int i=0;i<files.length;i++) {
   
			sb.append(new String(filereadtobyte(files[i]),"ISO-8859-1"));
		}
				
		System.out.println("s的长度为:"+s.length());
				
		File bossfile =new File(filepath+"/boss.docx");
		byte[] bossbyte=new String(sb).getBytes("ISO-8859-1");
		System.out.println(bossbyte.length);
		
		FileOutputStream fos=new FileOutputStream(bossfile);
		fos.write(bossbyte);
		fos.close();	
	}
		
	//文件以字节流形式read到字节数组当中
	public static byte[] filereadtobyte(File file) throws IOException {
   
		FileInputStream filein=new FileInputStream(file);
		byte[] bytes=new byte[(int) (file.length())];
		filein.read(bytes);
		filein.close();
		return bytes;
	}
	
	public static void main(String[] args) throws IOException {
   
		// TODO Auto-generated method stub
		long time1=System.currentTimeMillis();
		
		getbody("F:/Wangchuang/eclipse");		
		long time2=System.currentTimeMillis();
		System.out.println(time2-time1+"ms");	
	}

这个程序运行时间只有23ms,因为里面避免了很多循环,基本都是用API函数完成的。但是这里面有一个问题,解决了一个困扰了我很久的bug,见文章:
字节数组转换为字符串的时候会发生数据损失
③ArrayList

5.文件加密

题目:加密算法:
数字:如果不是9的数字,在原来的基础上加1,比如5变成6, 3变成4;如果是9的数字,变成0
字母字符: 如果是非z字符,向右移动一个,比如d变成e, G变成H;如果是z,z->a, Z-A。字符需要保留大小写
非字母字符:比如’,&^ 保留不变,中文也保留不变

/*
 * @加密
 * @20200914
 */
public class Suibi {
   
	
	//采用系统默认编码方式GBK
	public static void encodeFile(File encodingFile, File encodedFile) {
   
		try(FileReader fr=new FileReader(encodingFile);
				FileWriter fw=new FileWriter(encodedFile);){
   
			String s=getString();
			char[] chars=new char[(int)encodingFile.length()];
			fr.read(chars);
			System.out.println("加密前文件内容:\n"+new String(chars));
			for(int i=0;i<chars.length;i++) {
   
					chars[i]=getencoding(chars[i],s
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用IDEA 2023.2.1创建一个普通JavaSE项目,您可以按照以下步骤进行操作: 1. 首先,确保您已经安装了Java开发工具包(JDK)。您可以在引用中提供的路径中找到JDK的安装目录。 2. 打开IDEA,并选择"Create New Project"(创建新项目)选项。 3. 在弹出的对话框中,选择"Java",然后选择"JavaSE"作为项目类型。 4. 在项目设置中,选择您想要的项目名称和存储位置。 5. 确保在"Project SDK"(项目SDK)下拉菜单中选择正确的JDK版本。如果没有找到您的JDK版本,请确保您已正确安装了JDK,并在IDEA的设置中配置了JDK的路径。 6. 单击"Next"(下一步)继续进行。 7. 在"Additional Libraries and Frameworks"(附加库和框架)部分,您可以选择添加其他库或框架,或者直接单击"Finish"(完成)创建项目。 至此,您已成功使用IDEA 2023.2.1创建了一个普通的JavaSE项目。请注意,这是一种常见的创建JavaSE项目的方法,具体步骤可能会因IDEA版本而有所不同。如果您需要更详细的指导,请参考IDEA的官方文档或在线教程。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Mac/Win最新IntelliJ IDEA2023.1详细安装与配置使用教程(亲测有效,持续更新)](https://blog.csdn.net/Sunshine_Mr_Sun/article/details/123891067)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [如何在IDEA中新建一个WEB项目(2020.3、2021.1)](https://blog.csdn.net/xcj2317496650/article/details/115936438)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值