java学习day28(算法)
Classs2基尼系数实验终于来到了算法的学习在这里我们先跟着左神一步步把基础部分的算法过完也就是入门必备必须学完java创建数组的两种方式下面是之前记录的一些笔记我不会把源码全部贴出来只会贴出来以后需要反复观看的内容源码直接去code文件夹里面找就行了1 直接 int []a new int[5];2.赋值的方式 int []anew int []{1,2,3,4,5}注意不能int []anew int [5]{1,2,3,4,5}Arrays.fill(wealth, 100);这个是把数组里所有元素填满值都是100int j (int) (Math.random() * 5);这个(随机数的类型)Math.random()*n是从0到n-1随机抽取一个随机数返回之后对数器里面也会讲到这个这个地方之前笔记得有点令人疑惑我们在这里补充一下我们把这行代码int j (int) (Math.random() * 5);拆开来一步一步看你就明白了1.Math.random()这是系统自带的一个生成随机数的方法。它的规则是生成一个大于等于 0.0 且严格小于 1.0 的小数。它可以是0.0可以是0.534也可以是0.9999但永远到不了 1.0。2.* 5接着把刚才生成的这个随机小数乘以 5。如果刚才生成的是最小的0.0乘 5 还是0.0。如果刚才生成的是最大的极限值比如0.9999乘 5 就会无限接近5.0比如4.9995。所以这一步做完结果就变成了一个0.0 到 4.999... 之间的小数。3.(int)这在编程里叫做强制类型转换。它的作用极其简单粗暴把小数部分直接砍掉只保留整数。如果是0.8砍掉小数变成0。如果是2.6砍掉小数变成2。如果是4.9995砍掉小数变成4。这个地方就很关键了如果没有砍掉0-n-1 就不对了就变成了n-1.小数点了所以因为有了这个的存在才变成了0-n-1了Math.abs(wealth[i] - wealth[j]);这个是算绝对值总结图片里的红字第一句“这个...是从 0 到 n-1 随机抽取一个随机数返回”这里的n就是代码里的5。因为最大只能生成 4.999...被(int)砍掉小数后最大只能是 4。 所以这行代码的最终结果就是在 0、1、2、3、4 这五个整数里面随机挑一个赋值给变量j。这就是红字里说的“0 到 n-1”。第二句“之后对数器里面也会讲到这个”“对数器”是学习算法时常用的一个测试技巧。为了验证你写的算法对不对经常需要让电脑自动生成成千上万个随机的数据比如随机长度的数组、随机的数字来测试你的代码。而要生成这些随机数据就会疯狂用到上面这行代码这就是为什么教程里说以后还会碰到它。int[] a new int[]{2, 3, 1, 4, 5};Arrays.sort(a);for(inti 0;i 5;i) {System.out.println(a[i]);输出是12345这个是java里面的排序调用之后会自动把数组里面的数从小到大排好今天题目是算法学习方法左神讲了几个点1.复习不要做几个题就回去复习一次一定要有了不断做新题通过新题来复习然后有了一定题量比如刷了700题之后再整体的大段大段的复习因为做几个题就频繁往前复习会影响学习的节奏什么叫节奏就是得保证每天都在学新东西而不是复习旧东西但是切记也不是不复习一定得复习一定要理解什么叫有了大量练习之后再进行整体复习这句话2.算法不是突击几下就能学会一定要每天花时间练像磨刀一样磨。持之以恒力量。不求一天练的多但很久都不练了直接断了。但求一年之内每天都在练习一道。然后付出大量时间就跟手艺人一样无它唯手熟尔。3.要学会和喜欢折腾只看课一模一样写出课上代码没有用不要仿照它的代码写我知道他写的很漂亮但是看了之后你会临时背下来然后照着它的写了完全就不知道自己会出现的哪些问题了就和高中一样不要照着答案写不然真的以为自己啥都会自己不看它的代码只靠自己思路和课上听到的思路努力写出来实在写不动再看一下要课上学到内容自己去拿对数器去验证或者有什么新思路就自己去做实验class3二进制和位运算二进制的复习对于有符号数来说平均分成了负数和非负数 分别有2的31次方个负数 和2的31次方个非负数 然后就是转换了 负数和非负数转换 记住就一个 加1或者减一 再全部取反包括符号位int c 0b1001110; int d 0x4e;在java里面我们可以直接定义二进制数比如这里的0b 0x 都没实际的意义只是定义而已然后我们还记得int 是32位 long 是48位讲一下这个相反数: 1.10进制的相反数是直接填负号2.而2进制的相反数是取反再加1 但是最小的那个负数取反加1得到还是本身就传不过去了比如四位最小负数是-8对应二进制是1000取反加一还是1000然后我们还发现求一个数的二进制相反数和解读一个有符号负数的具体值在本质上完全是同一个数学操作场景 A你想把正数变成负数你有一个数 $X$你需要求它的相反数 $-X$。根据公式你的操作是 -X 1也就是取反再加一。场景 B你想看懂负数到底是多少计算机给你一个负数的补码 -X比如1111 1011你想知道它的绝对值具体是多少。其实你的大脑在做的事情是**“求这个负数的相反数”。既然又是求相反数再次套用上面的公式操作依然是(-X) 1也就是对这串负数二进制码取反再加一其实就是-13 你看不出来 转成相反数 13你就看出来了| 是或 $是与 ^是异或不同是1相同是0然后区分一下|和||区别一个符号是位运算上的或与两个符号逻辑上或与一般来说判断逻辑通常用做位运算掩码、取某一位用这里有一个小细节也就是左神讲的穿透性如果A是T的话接下来B都不会执行了只有ABC全是F才会一路穿透下去直到遇到某个变量是T才会停止但是位运算一定两边都会执行为什么两者都能判断 True / False答案很简单在计算机底层根本没有所谓的true和false只有数字1和0。当你把布尔值丢给这两种运算符时它们的计算结果恰好殊途同归位运算|,的角度单纯的数学计算位运算把true当作二进制的1把false当作二进制的0。 计算true | false在它眼里就是计算1 | 01与0按位或。根据二进制运算法则1和0按位或的结果是1。再转换回布尔值就是true。逻辑运算||,的角度条件逻辑判断逻辑运算就是专门为了处理布尔值设计的。计算true || false它的逻辑是“只要有一个为真结果就是真”所以结果也是true。二进制设置最精妙的地方就在于 不管是-5加7 还是5-7 都只要用通一套加法逻辑而不是最后减法去给定制一套逻辑 其实总结来说加减乘除没有自己的逻辑单元只有位运算的单元而减乘除都是加法高效的拼接而成的其实本质上 在CPU的算术逻辑单元ALU中真实的层级是这样的位运算构建了加法加法又构建了其他运算。左移就是整个状态往左移动比如11010往左移动右边就拿0补但是负数就得分情况了如果是正数就是往右移动最高位用0补位但如果是负数就是往右移动最高位用符号位补位printBinary(a); printBinary(~a); int e ~a 1; System.out.println(e); printBinary(e);~想必都没见过~这个就是按位取反再加1才是真正的相反数 所以~a 1-aclass4冒泡插入选择排序这三个排序被称为三傻排序在今天基本上只有教学意义但是插入排序是三傻排序里面最有用的选择排序有点像我们手里抓了一堆有序的牌然后新摸了一张牌再把这张牌排有序选择排序就是数组坐标0到n-1上选择一个最小值放0坐标这里是0坐标位置和最小值坐标位置直接交换和冒泡的两两比较是不一样的1到n-1上选择一个最小值放1依次类推一直结束冒泡是一直两两比较传递把最大数冒到最右边插入是我先认为0-0是有序的当然有序因为只有一个数新来一个数看看插到哪个位置停下来下面给出模板package class004; public class SelectBubbleInsert { // 数组中交换i和j位置的数 public static void swap(int[] arr, int i, int j) { int tmp arr[i]; arr[i] arr[j]; arr[j] tmp; } // 选择排序 public static void selectionSort(int[] arr) { if (arr null || arr.length 2) { return; } for (int minIndex, i 0; i arr.length - 1; i) { minIndex i; for (int j i 1; j arr.length; j) { if (arr[j] arr[minIndex]) { minIndex j; } } swap(arr, i, minIndex); } } // 冒泡排序 public static void bubbleSort(int[] arr) { if (arr null || arr.length 2) { return; } for (int end arr.length - 1; end 0; end--) { for (int i 0; i end; i) { if (arr[i] arr[i 1]) { swap(arr, i, i 1); } } } } // 插入排序 public static void insertionSort(int[] arr) { if (arr null || arr.length 2) { return; } for (int i 1; i arr.length; i) { for (int j i - 1; j 0 arr[j] arr[j 1]; j--) { swap(arr, j, j 1); } } } }Class5(对数器)不能完全依赖别人给提供oj 平台和测试用例 得要有一个自己测试的技巧 所以对数器因此应运而生。如果学会了对数器我们以后可以验证任何方法这里的方法指的就是我们解答的答案再也不需要oj 也可以认证我们的代码对不对了尤其是贪心和观察规律的题里面有用首先就跟我们前面所说的一样Math.random()他会得到再[01) 之间的一个小数 这个小数的类型是double类型而且这个小鼠是等概率的然后Math.random()*n 就会得到 [0,n)范围内的小数如果我们(int)Math.random() 就会把小数的小数部分舍去最后得到一个[0,n-1)范围内的整数等概率package class005; public class Validator { // 为了验证 public static void main(String[] args) { // 随机数组最大长度 int N 200; // 随机数组每个值在1~V之间等概率随机 int V 1000; // testTimes : 测试次数 int testTimes 50000; System.out.println(测试开始); for (int i 0; i testTimes; i) { // 随机得到一个长度长度在[0~N-1] int n (int) (Math.random() * N); // 得到随机数组 int[] arr randomArray(n, V); int[] arr1 copyArray(arr); int[] arr2 copyArray(arr); int[] arr3 copyArray(arr); selectionSort(arr1); bubbleSort(arr2); insertionSort(arr3); if (!sameArray(arr1, arr2) || !sameArray(arr1, arr3)) { System.out.println(出错了!); // 当有错了 // 打印是什么例子出错的 // 打印三个功能各自排序成了什么样 // 可能要把例子带入每个方法去debug } } System.out.println(测试结束); } // 为了验证 // 得到一个随机数组长度是n // 数组中每个数都在1~v之间随机得到 public static int[] randomArray(int n, int v) { int[] arr new int[n]; for (int i 0; i n; i) { // Math.random() - double - [0,1)范围山的一个小数0.37463473126、0.001231231等概率 // Math.random() * v - double - [0,v)一个小数依然等概率 // (int)(Math.random() * v) - int - 0 1 2 3 ... v-1等概率的 // (int) (Math.random() * v) 1 - int - 1 2 3 .... v等概率的 arr[i] (int) (Math.random() * v) 1; } return arr; } // 为了验证 public static int[] copyArray(int[] arr) { int n arr.length; int[] ans new int[n]; for (int i 0; i n; i) { ans[i] arr[i]; } return ans; } // 为了验证 public static boolean sameArray(int[] arr1, int[] arr2) { int n arr1.length; for (int i 0; i n; i) { if (arr1[i] ! arr2[i]) { return false; } } return true; } // 数组中交换i和j位置的数 public static void swap(int[] arr, int i, int j) { int tmp arr[i]; arr[i] arr[j]; arr[j] tmp; } // 选择排序 public static void selectionSort(int[] arr) { if (arr null || arr.length 2) { return; } for (int minIndex, i 0; i arr.length - 1; i) { minIndex i; for (int j i 1; j arr.length; j) { if (arr[j] arr[minIndex]) { minIndex j; } } swap(arr, i, minIndex); } } // 冒泡排序 public static void bubbleSort(int[] arr) { if (arr null || arr.length 2) { return; } for (int end arr.length - 1; end 0; end--) { for (int i 0; i end; i) { if (arr[i] arr[i 1]) { swap(arr, i, i 1); } } } } // 插入排序 public static void insertionSort(int[] arr) { if (arr null || arr.length 2) { return; } for (int i 1; i arr.length; i) { for (int j i - 1; j 0 arr[j] arr[j 1]; j--) { swap(arr, j, j 1); } } } }