今日学习总结:
排序算法
Java中的常见排序算法有:冒泡、插入、选择、快速、希尔、归并、堆7种 。
- 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。
- 线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。
构建一个乱序的数组用于进行排序
int[] arr=new int[6];//数据必须是可比较的,否则不能进行排序
Random r=new Random();
for(int i=0;i<arr.length;i++)
arr[i]=r.nextInt(100);
冒泡排序
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为每趟比较将当前数列未排序部分的最大的元素“沉”到数列末端,而小的元素会经由交换慢慢“浮”到数列
for(int i=1;i<arr.length;i++){//用于控制比较次数
for(int k=0;k<arr.length-i;k++){
if(arr[k]>arr[k+1]){
int temp=arr[k];
arr[k]=arr[k+1];
arr[k+1]=temp;
}
}
}
循环执行次数:(n-1)+(n-2)+(…)+(1)=(n*n-n)/2
平均时间复杂度为O(n平方) 空间复杂度O(1) 稳定的排序算法
练习:
键盘录入多个整数,点e表示输入完成,将所有录入数据放入数组,然后进行从大到小排序显示自定义方法,用于实现向数组中追加数据,并且将原始数组长度加1
public static int[] add(int[] source, int num) {
int[] res = new int[source.length + 1];新建数组,这个就是边长之后的数组,用于
新增数据
for (int i = 0; i < source.length; i++)拷贝原始数组中的数据到新数组中
res[i] = source[i];
res[source.length] = num;新数组最后一个位置存放需要追加的数据
return res;返回新创建的数组到方法调用的地方
}
自定义方法,用于实现指定数组的排序
public static void sort(int[] source){用于实现数组排序
for(int i=1;i<source.length;i++){控制比对的圈数
for(int k=0;k<source.length-i;k++){控制一圈比对中的具体比对操作
if(source[k]<source[k+1]){
int temp=source[k];
source[k]=source[k+1];
source[k+1]=temp;
}
}
}
}
主方法:调用上面定义的方法完成对应的处理功能
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);指代键盘的的对象,可以获取用户输入的数据
int counter = 1;统计输入数据个数
System.out.print("请输入第" + counter++ + "个整数:");
String str = sc.nextLine();
int[] arr = new int[0];不知道需要多长的数组所以先定义0个长的数组,每添加一个数
据,数组长度加1
while (!str.startsWith("e")) {如果用户输入e开头的内容则执行结束
int kk = Integer.parseInt(str.trim());进行数据类型转换,将输入的String
类型数据转换为int类型
arr = add(arr, kk);调用上面的方法对数据进行变长,并添加新增数据到数组末尾
System.out.print("请输入第" + counter++ + "个整数:");
str = sc.nextLine();
}
sort(arr);调用上面的方法进行排序
for (int temp : arr)
System.out.print(temp + "\t");
}
从键盘录入一行字符串,使用逗号作为分隔符,将字串分割成多端,然后按照字母序进行排序后显示
补充:字符串的比对是通过字符串中每个字符的Unicode编码值进行比较,如果返回值为正数,则表示前面的大于后面的,如果为0则表示相等;如果为负数则表示前面的小于后面的
Scanner sc = new Scanner(System.in);// 用于创建对象后获取用户的键盘录入
String str = sc.nextLine();
// 使用逗号作为分隔符将字串分割成多段子子字符串,并存放在数组
String[] arr = str.split(",");
for(int i=1;i<arr.length;i++){
for(int k=0;k<arr.length-i;k++){
if(arr[k].compareTo(arr[k+1])>0){
String temp=arr[k];
arr[k]=arr[k+1];
arr[k+1]=temp;
}
}
}
for(String temp:arr)
System.out.println(temp);
快速排序
快速排序是通常被认为在同数量级(O(nlog2n))的排序方法中平均性能最好的
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
平均时间复杂度O(nlog₂n) 空间复杂度O(1) 不稳定
查找算法
顺序查找、二分查找、插值查找、树表查找、分块查找、哈希查找等。
单纯论查找复杂度:对于无冲突的Hash表而言,查找复杂度为O(1)
遍历法
顺序查找又称为线性查找,是一种最简单的查找方法。适用于线性表的顺序存储结构和链式存储结构。
该算法的时间复杂度为O(n)
int[] arr = { 11, 2, 5, 34, 4, 5, 6, 7 };
int index = -1;// 序号,如果为-1表示没有找到
int target = 34;// 查找的目标
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
index=i;
break;
}
}
System.out.println(target+"位于第"+index+"的位置上");
缺点:是当n 很大时,平均查找长度较大,效率低;
优点:是对表中数据元素的存储没有要求。另外,对于线性链表,只能进行顺序查找。
折半查找法
二分查找Binary Search是一种在有序数组中查找某一特定元素的查找算法。查找过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则查找过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。 这种查找算法每一次比较都使查找范围缩小一半。
int[] arr = { 11, 2, 5, 34, 40, 51, 6, 7 };
int target = 5;
// 折半查找法要求数据必须有序,否则不能使用折半查找法
for (int i = 1; i < arr.length; i++) {
for (int k = 0; k < arr.length - i; k++) {
if (arr[k] > arr[k + 1]) {
int temp = arr[k];arr[k] = arr[k + 1];
arr[k + 1] = temp; }
} }
for (int temp : arr)System.out.print(temp + "\t");
System.out.println();
// 排序成功后才能进行折半查找法
int low = 0; int high = arr.length - 1; int index = -1;
if(arr[low]==target)index=low;
if(arr[high]==target)index=high;
while (index<0 && (high - low > 1)) {
int mid = (low + high) / 2;
if (arr[mid] > target) high = mid;
else if (arr[mid] < target) low = mid;
else {
index = mid; break; }
}
if (index > -1) System.out.println("查找的数据位于" + index);
else System.out.println("查找的数据不存在");
时间复杂度:折半搜索每次把搜索区域减少一半,时间复杂度为 O(logn) 空间复杂度:O(1)