【Java数组算法17】
一、冒泡排序:找到最大数,然后摘出来,在找出第二大数摘出来,依次进行
举例了解原理:
int[] data = {3,1,6,2,5}
比较之前的数据:3,1,6,2,5 (比较的时候都是按照第一个数和第二个数进行比较,如果第一个数大于第二个数调换顺序、否则保持不变,第二个数和第三个数进行比较,依次类推)
第一轮:
1,3,6,2,5(第1个数和第2个数比较的结果)
1,3,6,2,5(第2个数和第3个数比较的结果)
1,3,2,6,5(第3个数和第4个数比较的结果)
1,3,2,5,6(第4个数和第5个数比较的结果)
比较完第1轮以后把最大的一个数(6)摘出来,进行第2轮的比较
第二轮原数据:1,3,2,5
第二轮:
1,3,2,5
1,2,3,5
1,2,3,5
比较完第2轮以后把最大的一个数(5)摘出来,进行第3轮的比较
第三轮原数据:1,3,2
第三轮:
1,3,2
1,2,3
比较完第3轮以后把最大的一个数(3)摘出来,进行第4轮的比较
第四轮原数据:1,2
第4轮:
1,2
通过上面的比较可以清楚的知道:data数组内有5个数,对比了4轮,10次
由此可以得出一个公式:轮数:5-1;次数:5*(5-1)/2=10。如果数组内有n个数,那么比较的轮数为:n-1,每一轮进行的次数:n-1-1,总共次数:n*(n-1)/2
所以冒泡排序有两个动作:进行了几轮,进行了几次
在程序上解决方法:
1、双层for循环,外层for循环控制轮数,内层for循环控制次数。
2、内层for语句通过if判断来进行具体的转换:
A和B进行转换,先把A赋值给C,然后把B赋值给A,最后把C赋值给B
3、遍历数组,输出转换后的结果
package com.JavaStudy.studyArray0604; /** * @Author wufq * @Date 2020/6/4 15:00 * 冒泡排序 */ public class BubbleShort01 { public static void main(String[] args){ int[] data = {3,1,6,5,2}; //双层for循环来进行排序 for(int i=data.length-1;i>0;i--){ for(int j =0;j<i;j++){ if(data[j]>data[j+1]){ int temp = data[j]; data[j]= data[j+1]; data[j+1]=temp; } } } //遍历数组,输出结果 for(int i=0;i<data.length;i++){ System.out.print(data[i]+" "); } } }
package com.JavaStudy.studyArray0604; /** * @Author wufq * @Date 2020/6/4 16:29 */ public class Data { public static void main(String[] args){ int[] data = {3,1,6,5,2,7}; //双层for循环来进行排序 for(int i=1;i<=data.length-1;i++){ for(int j =0;j<data.length-1;j++){ if(data[j]>data[j+1]){ int temp = data[j]; data[j]= data[j+1]; data[j+1]=temp; } } } //遍历数组,输出结果 for(int i=0;i<data.length;i++){ System.out.print(data[i]+" "); } } }
以上两段代码的结果是一样的,区别在于两层for循环,第一种的外层for循环是按照先第4轮-->第1轮,而内层for循环是在小于外层for循环数的基础上进行的次数的计算;第二种的外层for循环是按照先第1轮-->第4轮,而内层for循环是在小于数组长度-1(即:数组下标)的基础上进行次数的计算。所以不管按照那种方式原理都是一样的,即:外层循环控制轮数,内层循环控制次数。但是第二种计算的次数明显多于第一种,所以还是建议采用第一种方式进行排序
二、选择排序
原理:找出最小数然后与数组的第一个元素进行对比然后互换。所以内层for循环分两步:1、找到最小数的下标,2、最小数的下标与第一个元素的下标进行对比然后互换
举例了解原理:
int[] arr={3,1,5,7,4}
比较之前的数据:3,1,5,7,4 (第一轮把第一个数赋值给最小数,然后最小数依次进行比较,找到最小数取出来,第二轮把第二个数当做最小数,然后进行比较,找出第二个最小数,依次寻找。。。)
第一轮:
原数:3,1,5,7,4
对比后:1,3,5,7,4
第二轮:
原数:3,5,7,4
对比后:3,5,7,4
第三轮:
原数:5,7,4
对比后:4,7,5
第四轮:
原数:7,5
对比后:5,7
通过上面的比较可以清楚的知道:选择排序也是先确定几轮,然后每一轮找到最小数,并摘出来。
package com.JavaStudy.studyArray0604; /** * @Author wufq * @Date 2020/6/4 17:02 * 选择排序:找到最小数然后和数组的第一个元素进行对比 */ public class SelectShort01 { public static void main(String[] args){ int[] arr={2,1,7,5,3,8}; for(int i=0;i<arr.length-1;i++){ //第一次循环都是和arr[i]元素交换位置,将剩余数据中的第一个元素看做最小元素 int min = i; //这个循环负责找出最小元素的下标 for(int j = i+1;j<arr.length;j++){ if(arr[min]>arr[j]){ min = j; } } //一定要找出最小元素的下标 //arr[min]和arr[i]交换位置 if(min!=i){ int temp = arr[min]; arr[min] = arr[i]; arr[i]=temp; } } for(int i=0;i<arr.length;i++){ System.out.print(arr[i]+"\t"); } } }
不管是冒泡排序还是选择排序,次数都是在轮的基础上进行的调换,所以内层循环时j都要在i控制的轮次里面进行次数的调换
如:冒泡排序:
for(int i=data.length-1;i>0;i--){
for(int j =0;j<i;j++){
选择排序:
for(int i=0;i<arr.length-1;i++){
for(int j = i+1;j<arr.length;j++){
三、二分法根据下标查找数据元素
使用二分法查找算法在数组中查找某个元素,前提该数组已经排序
例如:int[] arr = {1,5,8,12,56,89,99}
算法:begin=0
end = 7
mid = (begin+end) /2
mid = 被查找元素 --->return mid
mid > 被查找元素 ---> end = mid-1
mid < 被查找元素 --->begin= mid +1
package com.JavaStudy.studyArray0608; /** * @Author wufq * @Date 2020/6/8 11:22 */ public class IndexArray0608 { public static void main(String[] args){ int[] arr = {1,6,9,22,55,56,99}; int index =myIndex(arr,100); System.out.println(index!=-1?"被查找的元素在arr数组中的下标是"+index:"被查找的元素不存在"); } //myIndex方法两个元素,一个是arr数组,另外一个是需要查找的数 public static int myIndex(int[] arr,int dest){ //定义开始和结尾下标 int begin = 0; int end = arr.length-1; while (begin <= end){ int mid = (begin+end)/2; //判断中间数是否等于需要查找的数 if(arr[mid]==dest){ return mid; }else if(arr[mid]<dest){ begin= mid+1; }else if(arr[mid]>dest){ end= mid -1; } } return -1; } } ======执行结果===== 被查找的元素在arr数组中的下标是4
四、数组的工具类:Arrays类 --->java.until.Arrays
常用方法:
sort方法:可以进行排序
binarySearch方法:可以进行二分法排序查找
package com.JavaStudy.studyArray0608; import java.util.Arrays; /** * @Author wufq * @Date 2020/6/8 16:20 Arrays工具类,可以进行数组的查询和排序 */ public class ArraysTest01 { public static void main(String[] args){ int[] arr = {1,7,9,2,6,3}; //Arrays类里面sort方法进行排序 Arrays.sort(arr); //逆向遍历数组 for(int j=arr.length-1;j>=0;j--){ System.out.print(arr[j]+" "); } System.out.println("\n"); //正向遍历数组 for(int i=0;i<arr.length;i++){ System.out.print(arr[i]+" "); } System.out.println("\n"); //Arrays类中的binarySearch方法可以进行二分法查找数组下标 int index = Arrays.binarySearch(arr,3); System.out.println("arr数组的下标:"+index); } } =====执行结果===== 9 7 6 3 2 1 1 2 3 6 7 9 arr数组的下标:2
五、对一个字符串中的数值进行从小到大的排序
"20 78 9 -7 88 36 29"
思路:
1、排序我很熟,但是只熟int
2、如何获取到这些字符串中这些需要排序的数值
发现这些字符串都是用空格来对数值进行分隔的,
所以我们就想到用字符串对象的切割方法将大串切割成小串
3、数值最终变成小字符串,但是怎么变成int类型呢
字符串-->基本类型可以使用包装类
package com.JavaStudy01; import java.util.Arrays; /** * @Author wufq * @Date 2020/7/29 10:57 * 字符串"20 6 -1 50 9 7" 排序 * 思路: * 之前排序的都是int类型,但是没有把string类型的数值排序过 * 1、发现字符串是由空格进行分隔的,所以需要把大的字符串切割成小字符串 * 2、小字符串转换成int类型进行排序 * 3、排序后在转换成字符串 */ public class WrapperTest { private static final String SPACE_SEPARATOR = " "; //大小写切换快捷方式:⌘⇧U public static void main(String[] args){ String numstr = "20 6 -1 50 9 7"; System.out.println(numstr);//转换前 numstr = toStringNum(numstr); //自定义了一个方法名,但是想自动转换成方法,快捷方式为:option+enter/alt+enter System.out.print(numstr);//转换后 } private static String toStringNum(String numstr) { /* String [] str_num = numstr.split(" "); --> 想把此段代码变成一个方法,需要在idea内进行重构:全部选中右键->Refactor->Extract->Method 或者用快捷方式option+command+M */ //1、将字符串变成字符串数组 String[] str_num = stringToArray(numstr); //2、将字符串数组变成int数组 int [] int_num = toIntArray(str_num); //3、对int数组进行排序 mySortArray(int_num); //4、将排序后的int数组,转换成字符串 String temp = arrayToString(int_num); return temp; } private static String arrayToString(int[] int_num) { StringBuilder sb = new StringBuilder(); for(int j=0;j<int_num.length;j++){ if(j!=int_num.length-1){ sb.append(int_num[j]+SPACE_SEPARATOR); }else { sb.append(int_num[j]); } } return sb.toString(); } private static void mySortArray(int[] int_num) { Arrays.sort(int_num); } public static int[] toIntArray(String[] str_num) { int[] arr = new int[str_num.length]; for(int i=0;i<arr.length;i++){ arr[i]= Integer.parseInt(str_num[i]); } return arr; } public static String[] stringToArray(String numstr) { String [] str_num = numstr.split(SPACE_SEPARATOR); return str_num; } }
======执行结果======
转换前:20 6 -1 50 9 7
转换后:-1 6 7 9 20 5
如果字符串是这样类型的:String str = "312347890",排序的思路是不变的,区别在于先把String类型转换成char类型的数组,然后把char类型的数组转换成String类型,然后在转换成int类型的数组
package com.wufq.demo.demo8; import java.util.Arrays; /** * @Description 排序 * @Author wufq * @Version * @Date 2021/5/18 14:06 */ public class Sort_test { public static void main(String[] args){ String str= "312347890"; String s=Str_sort(str); System.out.println(s); } private static String Str_sort(String str) { char[] chars=strToChar(str); int[] i = charToInt(chars); arraySort(i); String ss = intToStr(i); return ss; } private static String intToStr(int[] tt) { StringBuilder sb = new StringBuilder(); for(int i=0;i<tt.length;i++){ sb.append(tt[i]+" "); } return sb.toString(); } private static void arraySort(int[] i) { Arrays.sort(i); } private static int[] charToInt(char[] chars) { int[] tt = new int[chars.length]; for(int i=0;i<tt.length;i++){ tt[i]=Integer.parseInt(String.valueOf(chars[i])); } return tt; } private static char[] strToChar(String str) { char[] chars = str.toCharArray(); return chars; } }
知识补充:
String、StringBuffer和StringBuilder的区别:
String类时不可变类,定义以后所占的内容空间不能修改
StringBuffer和StringBuilder功能差不多,都是代表了字符序列可变的字符串,
当StringBuffer和StringBuilder创建以后,提供append(),insert(),reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列,一旦生成想要的字符串,就可以通过toString()方法将其转换成一个String对象
两者之间的曲边:StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高。