recursion&file&Buffered&I/O流

本文深入解析递归算法的应用及其在程序设计中的优势与局限,同时详细介绍了IO流的概念,包括字节流与字符流的区别,以及如何在Java中进行文件的读写操作。

递归

描述:

递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

递归算法解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。

Java中使用递归注意:构造方法不能递归使用。

  • 代码实例:
    • 斐波那契
      /*for example-Fibonacci*/
      /*思考如何用递归实现斐波那契数列的存储和显示。*/
      public static int fib(int n) {
      		if (n == 1 || n == 2) {
      			return 1;
      		} else {
      			return fib(n - 1) + fib(n - 2);
      		}
      	}
      
      /*明显的优势是将有用的数据存储在数组里面。*/
      arr[0] = 1;
      arr[1] = 1;
      for (int x = 2; x < arr.length; x++) {
      	arr[x] = arr[x - 2] + arr[x - 1];			
      }
      
      /*不断替换a,b对应的数据,数据不保留。*/
      int a = 1;
      int b = 1;
      for (int x = 0; x < 18; x++) {
      	// 每运行一次将a,b对应的数据刷新一遍。
      	int temp = a;
      	a = b;
      	b = temp + b;
      	System.out.println(a);
      }
      

IO流

描述:

按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列。从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流…

  • 分类:

    • 流向
      可以这样理解,流的输入还是输出性是相对于内存来描述的。相对于内存是进入内存,则为输入流–读取数据;相对于内存是流出内存,则是输出流–写出数据–写入到外部存储设备。
    • 数据类型
      字节流:字节输入流,字节输出流。
      字符流:字符输入流,字符输出流。

    建议使用字节流进行文件的输入和输出。

  • FileOutputStream写出数据

    使用中,主函数必须public static void main(String[] args) throws IOException/try…catch…

    /*for example*/
    		FileOutputStream fos = new FileOutputStream("fos.txt");			
    		fos.write("hello,world.".getBytes());			
    		fos.close();
    
  • FileInputStream读取数据

    使用中,主函数必须public static void main(String[] args) throws IOException/try…catch…

    /*for example*/
    		FileInputStream fis = new FileInputStream("fos.txt");
    		//way_01:	
    		int by = 0;
    		while((by=fis.read())!=-1) {
    			System.out.print((char)by);
    		}
    
    		//way_02
    		char by = 0;		
    		while ((by = (char) fis.read()) != -1) {
    			System.out.print(by);
    		}
    	
    		//way_03
    			byte[] bys = new byte[1024];
    			int len = 0;
    			while((len=fis.read(bys))!=-1) {
    				System.out.print(new String(bys,0,len));
    			}		
    		fos.close();
    
  • 字节缓冲区流

    • BufferedOutputStream.
    • BufferedInputStream.

    	//字符缓冲区的使用方法.
    	public static void Way_One(String srcString, String destString)
    			throws IOException {
    		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    				srcString));
    		BufferedOutputStream bos = new BufferedOutputStream(
    				new FileOutputStream(destString));
    
    		byte[] bys = new byte[1024];
    		int len = 0;
    		while ((len = bis.read(bys)) != -1) {
    			bos.write(bys, 0, len);
    		}
    
    		bos.close();
    		bis.close();
    	}
    
    	
    	public static void Way_Two(String srcString, String destString)
    			throws IOException {
    		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    				srcString));
    		BufferedOutputStream bos = new BufferedOutputStream(
    				new FileOutputStream(destString));
    
    		int by = 0;
    		while ((by = bis.read()) != -1) {
    			bos.write(by);
    
    		}
    
    	fos.close();
    	fis.close();
    
    
  • 字符流

    描述:字节流对于数据的复制存储操作上并没有什么区别,但是有操作中文数据的可视化上不是特别的方便,所以就出现了转换流,转换流的作用就是把字节流转换字符流来使用。

    • 转换流就是字符
      字符流 = 字节流 + 编码表(注明编码格式.)
    • 编码表
      • 就是由字符和对应的数值组成的表。

    编码表

  • 字符串中的编码

    • IO流中的编码

      /*for example*/
      /*字符流与字节流的桥梁*/
      OutputStreamWriter
      
      	是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节charset 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
      
      	OutputStreamWriter(OutputStream os):默认编码,GBK
      	OutputStreamWriter(OutputStream os,String charsetName):指定编码。
      
      InputStreamReader
      
      	是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
       
      	InputStreamReader(InputStream is):默认编码,GBK.
      	InputStreamReader(InputStream is,String charsetName):指定编码.
      
      编码问题
      	存储的本质问题都是字节流,解决办法直接指定编码格式与之对应即可,或者使用写入文件的编码格式即可。
      
      public static void main(String[] args) throws IOException {
      		
      		// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
      		// "osw.txt")); // 默认GBK
      		// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
      		// "osw.txt"), "GBK"); // 指定GBK
      		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
      				"osw.txt"), "UTF-8"); // 指定UTF-8
      		
      	
      		osw.write("中国");		
      		osw.close();
      }
      
      public static void main(String[] args) throws IOException {
      		
      		// InputStreamReader isr = new InputStreamReader(new FileInputStream(
      		// "osw.txt"));
      		// InputStreamReader isr = new InputStreamReader(new FileInputStream(
      		// "osw.txt"), "GBK");
      		InputStreamReader isr = new InputStreamReader(new FileInputStream(
      				"osw.txt"), "UTF-8");
      		
      		int ch = 0;
      		while ((ch = isr.read()) != -1) {
      			System.out.print((char) ch);
      		}
      
      		/*
      		char[] chs = new char[1024];
      		int len = 0;
      		while ((len = isr.read(chs)) != -1) {
      			System.out.print(new String(chs, 0, len));
      		}
      		*/
      		
      		isr.close();
      }
      
      public static void main(String[] args) throws IOException {
      
      	InputStreamReader isr = new InputStreamReader(new FileInputStream(
      			"a.txt"));	
      	OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
      			"b.txt"));
      	
      	/*方式1
      	int ch = 0;
      	while ((ch = isr.read()) != -1) {
      	osw.write(ch);
      	}
      	*/
      
      	/* 方式2*/
      	char[] chs = new char[1024];
      	int len = 0;
      	while ((len = isr.read(chs)) != -1) {
      		osw.write(chs, 0, len);
      		// osw.flush();
      	}
      
      	// 释放资源
      	osw.close();
      	isr.close();
      }
      
    • 字符流

      Reader
      	|--InputStreamReader
      		|--FileReader
      	|--BufferedReader
      Writer
      	|--OutputStreamWriter
      		|--FileWriter
      	|--BufferedWriter
      

IO流操作结构图解

  • IO图解

  • I/O代码实例

/*for example*/
/*字符缓冲流
 BufferedWriter:
 		public void newLine():根据系统来决定换行符
 BufferedReader:
 		public String readLine():一次读取一行数据
 		包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null.
 */
在 C++ 中,使用 lambda 表达式实现递归时,需要特别注意捕获列表(capture list)的设置以及如何正确地将 lambda 自身作为参数传递。以下是对 `C++ lambda recursion with auto and this capture` 的详细解析。 ### 使用 `auto` 与 `this` 捕获实现递归 在 C++ 中,lambda 表达式可以通过 `std::function` 或 `auto` 来存储,并通过引用捕获自身来实现递归调用。由于 lambda 是匿名函数对象,无法直接在内部调用自己,因此需要借助外部变量来完成递归。 #### 示例代码:使用 `auto` 和 `this` 捕获实现递归 ```cpp #include <iostream> #include <functional> class Fibonacci { public: void compute() { // 使用 auto 声明一个 lambda 函数,并通过 this 捕获当前对象 std::function<int(int)> fib = [this](int n) -> int { if (n <= 1) return n; return fib(n - 1) + fib(n - 2); // 递归调用 }; std::cout << "Fibonacci(5): " << fib(5) << std::endl; // 输出 5 } }; int main() { Fibonacci f; f.compute(); return 0; } ``` 在这个例子中,`[this]` 捕获了当前类对象的上下文,使得 lambda 可以访问类中的成员变量和方法。同时,`std::function<int(int)>` 被用来保存 lambda 表达式,以便在函数体内递归调用它自己。 #### 使用 `auto` 直接声明 lambda 并递归 如果直接使用 `auto` 来声明 lambda,则必须先声明 lambda 变量,再赋值,因为 lambda 在定义时尚未完全构造,不能立即在初始化表达式中引用自身: ```cpp #include <iostream> #include <functional> int main() { std::function<int(int)> factorial; factorial = [&factorial](int n) -> int { if (n == 0) return 1; return n * factorial(n - 1); }; std::cout << "Factorial(5): " << factorial(5) << std::endl; // 输出 120 return 0; } ``` 在这个例子中,`factorial` 是一个 `std::function` 类型的对象,其内部捕获了自身的引用 `[&factorial]`,从而允许递归调用。 #### 使用 `auto` 和 `this` 捕获的注意事项 - **避免循环依赖**:确保递归有终止条件,否则会导致无限递归。 - **性能问题**:频繁递归可能影响性能;考虑使用迭代或记忆化技术优化。 - **捕获方式选择**:使用 `[=]` 按值捕获所有外部变量,或者 `[&]` 按引用捕获。对于递归,通常推荐使用 `[&]` 或显式捕获特定变量以避免不必要的拷贝[^3]。 --- ### 总结 在 C++ 中实现 lambda 表达式的递归调用时,必须借助 `std::function` 或类似机制来保存 lambda 对象,并通过引用捕获自身(如 `[&f]` 或 `[this]`)。这种方式可以有效地封装递归逻辑并保持代码简洁性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值