Java 最基础的三种排序排序
关于算法最基础的就是各种排序算法和查找算法,今天我们讲一下最基础的三种排序算法:冒泡排序、选择排序、插入排序
1)冒泡排序
冒泡排序是一种最直接最直观的排序方法,方法就是比较相邻两个数字大小,将较大的数字向后移动,依次向后移动着比较,当与最后一个数字相比较的时候最后一个数字就是一组数字中的最大值,当到最后一个数字的时候再回到开头,然后继续此操作,如此重复循环n-1次即可完成排序,n表示的就是数组长度
/** * 冒泡排序 (默认升序排) * 相邻两个相比较,较大的向后放,从数组或者集合中的第一个与第二个比较到倒数第二个与最后一个比较为一轮比较 * 总共需要比较list.length-1轮循环比较 */ @Test public void bubblesort() { List<Integer> list = Arrays.asList(3, 3, 54, 213, 34, 876, 32, 456, 567, 43, 121, 312, 123, 45, 234, 234, 123, 546, 867, 89, 807, 8, 76); //确定需要重复的次数 for (int j = 0; j < list.size() - 1; j++) { //每次循环都把相邻想个相比较,较大的向后放 //这里减j 每循环一轮,比较的时候就会少比较一次 for (int m = 0; m < list.size() - j - 1; m++) { int b; if (list.get(m) > list.get(m + 1)) { b = list.get(m); list.set(m, list.get(m + 1)); list.set(m + 1, b); } } } for (Integer integer : list) { System.out.println(integer); } }
分析:外循环控制轮数,内循环进行比较和换位,总共需要length-1轮排序,两个数比较一轮,三个数需要两轮;内循环进行每轮的相邻两个数的比较和换位,而两两换位的次数是length-1-轮数,因为每轮都能保证最后一位是最大或者最小,所以当最后的数确定之后就不用再比较了。这里有两层for循环,每个for循环都与我们的length相关
时间复杂度: O(n^2)
空间复杂度:O(1)
2)选择排序
选择排序就是从中依次找到最大或者最小值,然后放到开头或者结尾,比如我们有一个n个元素的数组需要从小到大排序,那么先从n个元素中找到最小的数字,然后与最右边(第一个数)相比较,看是否比第一个小,如果比第一个小就换位置,否则不就不动;然后再从剩下的元素中再找出最小的与第二个数相比较。看是否比第二个小,如果比第二个小就换位置,否则不就不动;一次类推,直至最后两个比较完毕,这个数组就排好了
/** * 选择排序 (默认升序) * 假设一个最小值,循环比较出实际最小值 * 然后把假设最小值与实际最小值互换位置 */ @Test public void chooseSort() { List<Integer> list = Arrays.asList(3, 3, 54, 213, 34, 876, 32, 456, 567, 43, 121, 312, 123, 45, 234, 234, 123, 546, 867, 89, 807, 8, 76); //总共需要多少轮循环比较,i表示该轮循环假设最小值的角标 for (int i =0; i < list.size()-1; i++){ int temp=i; //假设i是本轮循环中最小元素的索引,temp记录最小元素的角标 for (int n = i+1; n < list.size();n ++){ //比较本轮循环中目前最小值和这个索引下的元素的比较 if (list.get(temp) > list.get(n)){ //如果最小值大于n索引下的元素值那就把n当成最小值索引 temp = n; } } //到这里temp就是实际最小元素的角标了 if (list.get(i) > list.get(temp)){ //如果所假设的的最小值 大于 实际最小值,则互换位置 int record; record = list.get(i); list.set(i,list.get(temp)); list.set(temp,record); } } for (Integer integer : list) { System.out.println(integer); } }
时间复杂度: O(n^2)
空间复杂度:O(1)
3)插入排序
插入排序是先构建一个有序列表,然后在原列表中取出一个个元素向有序列表中比较插入的过程。当我们有一个无序列表,我们首先拿到第一个元素作为一个有序列表,例如[5,3,8,5],我们先拿到5作为一个有序列表[5],剩下的[3,8,5]就是一个无序列表,然后取出3和5比较,3小于5所以放在5的左边,这个时候有序列表就是[3,5],无序列表就是[8,5],再拿到8和5比较大于5所以放在5的右边,有序列表[3,5,8],无序列表就剩了一个5,最后拿5和有序里面最右边的比较小于那就再往前比较,当再次遇到大于该值的地方插入位置。即每次我们从无序列表中拿出一个值在有序列表中从右到左扫描找到对应位置并插入,直至所有数字全部插入完毕则排序结束
时间复杂度: O(n^2)
空间复杂度:O(1)
/** * 插入排序 * 从每个数组的第二个元素开始向前比较,只要比前面的小就互换位置, * 直到前面一个小于等于这个值的时候跳出本循环,开始插入下一个元素 * */ @Test public void insertSort(){ List<Integer> list = Arrays.asList(3, 3, 54, 213, 34, 876, 32, 456, 567, 43, 121, 312, 123, 45, 234, 234, 123, 546, 867, 89, 807, 8, 76); //确定插入的元素是 list.get(i) for (int i = 1;i<list.size();i++) { int j=i; //向前循环比较,如果前面的比插入的值大就互换位置 while (j>0 && j < list.size()){ if (list.get(j) < list.get(j-1)){ int record=list.get(j); list.set(j,list.get(j-1)); list.set(j-1,record); }else { //else可以省略,但是考虑到如果已经确定了前面不会出现比该元素大的数那么再循环下去等于做的无用功,可以直接结束本次循环来节省时间 break; } j--; } } for (Integer integer : list) { System.out.println(integer); } }