# zb_java0723 **Repository Path**: qwe872022920/zb_java0723 ## Basic Information - **Project Name**: zb_java0723 - **Description**: 数组 - **Primary Language**: Java - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 5 - **Created**: 2018-07-23 - **Last Updated**: 2021-11-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # zb_java0723 # 课堂笔记 ## 0 方法[补充] ### 0.1 方法概念 * 1 变长参数 在一个方法定义的形参列表里面,有不确定个数的参数,叫做变长参数; 语法: 访问控制修饰符 其他修饰符 返回值类型 方法名(数据类型 形参名,数据类型 形参名n,数据类型... 形参名){ 方法体; } 等价于: 访问控制修饰符 其他修饰符 返回值类型 方法名(数据类型 形参名,数据类型 形参名n,数据类型[] 形参名){ 方法体; } 解析: (1)变长参数的定义形式,在数据类型后面有...表示参数个数不确定; (2)一个方法定义中至多只能有一个 变长参数; (3)变长参数只能写在形参的末尾; (4)变长参数等价于该数据类型的一维数组类型; (5)变长参数的个数可以是0个、1个、以及任意多个; (6)在被调用的子方法中,可以通过数据遍历的形式,获取变长参数中的所有的值; (7)在主方法调用时,实参可以是数组类型; (8)变长参数的方法也可以构成方法的重载; (9)当变长参数方法和非变长参数方法的形参都可以和实参列表匹配时,优先调用非变长参数的方法; 代码[]: ``` public static void main(String[] args) { // 调用变长参数 System.out.println("====================="); System.out.println("调用变长参数方法:"); shopping(99, "小明", "张三1", "王五1", "赵六1"); System.out.println("====================="); System.out.println("以数组的形式调用变长参数方法:"); String[] strOtherF = { "张三2", "王五2", "赵六2" }; shopping(88, "小明", strOtherF); System.out.println("====================="); System.out.println("变长参数可以为0个:"); shopping(77, "小明"); } /** * 购物 * * @param strFrieds * 形参 */ private static void shopping(double costMoney) { System.out.println("I am shopping with money of " + costMoney); } /** * 购物 * * @param strFrieds * @param costMoney */ private static void shopping(double costMoney, String strFrieds) { System.out.println("此处调用的是非变长参数方法"); System.out.println("I am shopping with boyfriend " + strFrieds + ",and costing Money of " + costMoney); } /** * 变长参数方法 购物 * * @param strFrieds * @param costMoney */ private static void shopping(double costMoney, String strFrieds, String... strOtherFrieds) { // 如何获取变长参数的内容 // 变长参数就是一个该数据类型的数组 System.out.println("变长参数就当成数组进行遍历即可:"); if (strOtherFrieds != null) { for (String str : strOtherFrieds) { System.out.print(" " + str); } // 换行 System.out.println(); } System.out.println("I am shopping with boyfriend " + strFrieds + ",and costing Money of " + costMoney); } ``` ### 0.2 方法传参形式 在方法调用过程中实参的值会传递给形参,这就是方法调用过程中参数值的传递; 实参的值传递给形参,反过来形参值的变化会不会影响实参可以将java传参方式分为两种: 按值传传参:形参变化不影响实参; 8种基本类型、String; 按引用传参:形参变化影响实参; 其他的所有类型。【包括数组】 在java语言中,参数的传值有两种形式: 按值传参; 实参的值传递给形参,如果形参的值发生了变化,则实参不受影响; 因为按值传参传递是值的拷贝,所有形参改变不会影响实参; 8种基本类型、String是按值传参;【除此以外都是按引用传参】 代码[com.yuw.fun.Test02]: ``` /** * 按值传参 */ private static void test01_main() { // 定义个实参 int age = 20; System.out.println("在调用子方法sub01之前实参的值为:" + age); // 调用子方法sub01 test01_sub01(age); // 实参age System.out.println("在调用子方法sub01之后实参的值为:" + age); } /** * 子方法 * * @param age * 形参 */ private static void test01_sub01(int age) { System.out.println("=======子方法开始========"); System.out.println("在子方法sub01中形参从实参中获取的值为:" + age); // 改变形参age的值 age += 1; System.out.println("在子方法sub01中形参的值改变之后为:" + age); System.out.println("=======子方法结束========"); } ``` 按引用传参; 实参的值传递给形参,如果形参的值发生了变化,则实参受影响; 因为按引用传参传递的是地址(引用),所有形参改变会影响实参; 对象类型(不包括String)、数组按引用传参; 代码[com.yuw.fun.Test02]: ``` /** * 按引用(地址)传参 */ private static void test02_main() { // 定义个实参 int[] scores = { 20, 80, 50, 90 }; System.out.println("在调用子方法sub01之前实参的值为:"); // 打印数组 printArr(scores); // 调用子方法sub01 test02_sub01(scores); // 实参scores System.out.println("在调用子方法sub01之后实参的值为:"); // 打印数组 printArr(scores); } /** * 子方法 * * @param age * 形参 */ private static void test02_sub01(int[] scores) { System.out.println("=======子方法开始========"); System.out.println("在子方法sub01中形参从实参中获取的值为:"); // 打印数组 printArr(scores); // 改变形参scores中某一个元素的值 scores[0] += 1; System.out.println("在子方法sub01中形参的值改变之后为:"); // 打印数组 printArr(scores); System.out.println("=======子方法结束========"); } /** * 打印数组的内容 * * @param arr * 数组 */ private static void printArr(int[] arr) { for (int i : arr) { System.out.print(" " + i); } // 换行 System.out.println(); } ``` 作用: (1)在方法声明定义时,在给定新参列表时,需要考虑传递的方式(按值传参还是按引用传参) (2)在进行方法调用时,需要注意形参的数据类型是按引用传参还是按值传参; ## 1 数组 ### 1.1 不规则二维数组 不规则二维数组是指二维数组中某些行的列数不相同; 产生的原因: 二维数组在声明初始化时可以直接给定初始化的值,在给定值的时候会产生不规则二维数组。 例如: 数据类型[][] 变量名 = new 数据类型[][]{{逗号分隔的值列表1},{逗号分隔的值列表2},{逗号分隔的值列表n}}; // 以下写法,声明和初始化不能分开 数据类型[] 变量名 = {{逗号分隔的值列表1},{逗号分隔的值列表2},{逗号分隔的值列表n}}; 数组的行和列可以分开进行声明定义: // 第一步:声明定义时,只指定了行数,列数进行单独声明初始化; 数据类型[][] 变量名 = new 数据类型[行数][]; // 第二部:单独对每行进行声明初始化 变量名[0] = new 数据类型[列数]; 变量名[1] = new 数据类型[]{逗号分隔的值列表}; ...... 变量名[n] = new 数据类型[列数]; 注意: 不规则的二维数组在内存中还是连续存储的; 代码[com.yuw.arr.Test01]: ``` /** * 不规则二维数组 */ private static void test01() { // 定义声明不规则二维数组 int[][] arr0 = new int[][] { { 1, 2, 3, 4 }, { 5, 6 }, { 7, 8, 9 } }; int[][] arr1 = { { 1, 2, 3, 4 }, { 5, 6 }, { 7, 8, 9 } }; int[][] arr2 = new int[3][]; arr2[0] = new int[2]; arr2[1] = new int[3]; arr2[2] = new int[4]; // 规则二维数组的定义 int[][] arr22 = new int[3][3]; // 二维数组的遍历 // 外层for循环遍历行数 for (int i = 0; i < arr1.length; i++) { // 内层for循环遍历列数 for (int j = 0; j < arr1[i].length; j++) { // 使用行标和列标取出对应元素的值 int temp = arr1[i][j]; System.out.print(" " + temp); } // 换行 System.out.println(); } } ``` ## 2 方法和数组的应用 ### 2.1 递归方法调用 递归调用就是方法自己调用自己的过程; 递归算法的分析: (1)递归结束条件【否则就是死循环】 (2)递归调用自身 递归算法的使用情景: 进行重复处理时可以优先考虑递归; 递归调用的性能分析及优缺点: (1)代码实现比较简单; (2)递归算法的性能不高; 示例: 求解斐波那契数列的第N项的值; 数学概念:斐波那契数列,给定前两项的值,从第三项开始该项的值是前两项之和;【兔子问题】 解析: 已知,f(1) = 1,f(2) = 1;f(n)=f(n-2)+f(n-1) (n>=2) 代码[]: ``` /** * 从控制台输入求解的项数,并求解第n项的值 */ private static void getF() { System.out.println("请输入所要求的的斐波那契数列的第几项:"); Scanner sc = new Scanner(System.in); // 获取所有的项数 int n = sc.nextInt(); // 计算性能——获取当前时间的毫秒数 long lBegin = System.currentTimeMillis(); // 调用斐波那数列求解的递归函数 long lResult = caculateF(n); // 执行结束之后,获取当时的毫秒数 long lEnd = System.currentTimeMillis(); // 计算程序所耗费的时间 System.out.println("程序运行所花费的时间为:" + (lEnd - lBegin) + "毫秒"); System.out.println("斐波那契数列的第" + n + "项的值为:" + lResult); } /** * 递归求解斐波那契数列的第N项的值 * * @param n * 第n项 * @return 第n项的值 */ private static long caculateF(int n) { // (1)递归结束条件 if (n == 1 || n == 2) { return 1; } // (2)递归调用 return caculateF(n - 2) + caculateF(n - 1); } ``` ### 2.2 冒泡排序算法 算法思想: 核心:通过两两比较将最值移到末尾;经过N轮这样的处理,序列就会编程有序的; 算法过程: 第一轮:进行两两比较,最值放在末尾; 第二轮:再次进行两两比较,最值放在末尾【第二个最值放在倒数第二的位置】; ... ... 算法实现: 这是一个两重维度的问题;需要使用双重for循环进行实现; 经过N-1轮;每轮经过N-1次比较; 代码[com.yuw.fun.Test04]: ``` public static void main(String[] args) { test01(); System.out.println("====================="); test02(); System.out.println("====================="); test03(); } /** * 冒泡排序测试类 */ private static void test01() { int[] arr = { 1, 2, 8, 3, 4, 6, 9, 7 }; System.out.println("排序之前的数组:"); printArr(arr); bubbleSort(arr); System.out.println("排序之后的数组"); printArr(arr); } /** * 优化每轮中比较次数的测试类 */ private static void test02() { int[] arr = { 1, 2, 8, 3, 4, 6, 9, 7 }; System.out.println("排序之前的数组:"); printArr(arr); bubbleSort2(arr); System.out.println("排序之后的数组"); printArr(arr); } /** * 优化比较轮数的测试类 */ private static void test03() { int[] arr = { 1, 2, 8, 3, 4, 6, 9, 7 }; System.out.println("排序之前的数组:"); printArr(arr); bubbleSort3(arr); System.out.println("排序之后的数组"); printArr(arr); } /** * 冒泡排序算法【从小到大】 * * @param arr * 被排序数组【方法定义为了void,因为数组是按引用传参】 */ private static void bubbleSort(int[] arr) { // 统计比较次数 int count = 0; // 外层for循环,控制冒泡排序算法的轮数 for (int i = 0; i < arr.length - 1; i++) { // 内存for循环,控制每一轮中的两两比较次数 for (int j = 0; j < arr.length - 1; j++) { // 按照排序要求进行比较,并交换相邻两个元素 if (arr[j] > arr[j + 1]) { // 比较交换 int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } // 经过一次比较,计数器+1 count++; } } System.out.println("本次排序比较次数:" + count); } /** * 冒泡排序算法【从小到大】 -- 优化每轮中的比较次数 * * @param arr * 被排序数组【方法定义为了void,因为数组是按引用传参】 */ private static void bubbleSort2(int[] arr) { // 统计比较次数 int count = 0; // 外层for循环,控制冒泡排序算法的轮数 for (int i = 0; i < arr.length - 1; i++) { // 内存for循环,控制每一轮中的两两比较次数 // arr.length - i - 1 优化每轮比较的次数 for (int j = 0; j < arr.length - i - 1; j++) { // 按照排序要求进行比较,并交换相邻两个元素 if (arr[j] > arr[j + 1]) { // 比较交换 int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } // 经过一次比较,计数器+1 count++; } } System.out.println("本次排序比较次数:" + count); } /** * 冒泡排序算法【从小到大】 -- 优化比较轮数 * * @param arr * 被排序数组【方法定义为了void,因为数组是按引用传参】 */ private static void bubbleSort3(int[] arr) { // 统计比较次数 int count = 0; // 外层for循环,控制冒泡排序算法的轮数 for (int i = 0; i < arr.length - 1; i++) { // 每轮是否发生交换变量:默认没有发生交换 boolean isChanged = false; // 内存for循环,控制每一轮中的两两比较次数 // arr.length - i - 1 优化每轮比较的次数 for (int j = 0; j < arr.length - i - 1; j++) { // 按照排序要求进行比较,并交换相邻两个元素 if (arr[j] > arr[j + 1]) { // 比较交换 int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; // 当前本轮比较中,发生了交换,修改标志变量 isChanged = true; } // 经过一次比较,计数器+1 count++; } // 如果当前轮没有发生交换,则无需在进行下一轮比较,可以终止比较轮数的循环【终止外层循环】 // if (!isChanged) { if (isChanged == false) { // 没有发生交互,终止外层循环 break; } } System.out.println("本次排序比较次数:" + count); } /** * 打印数组 * * @param arr * 被打印的数组 */ private static void printArr(int[] arr) { for (int i : arr) { System.out.print(" " + i); } System.out.println(); } ``` #### 参与贡献 1. Fork 本项目 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 码云特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 5. 码云官方提供的使用手册 [http://git.mydoc.io/](http://git.mydoc.io/) 6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)