排序算法的内容会随着博主的学习进度更新,内容介绍了各个算法的原理,并且都有代码示例。
目录
1.Comparable接口介绍
介绍:在一个需要可以进行比较的类实现Comparable接口,并重写Comparable接口的compareTO方法,以此来提供一个比较规则,从而实现类的比较。代码示例如下:
//Student类
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写Comparable类中的compareTo方法
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
//测试类
public class Test {
public static void main(String[] args) {
Student student1 = new Student("张三", 18);
Student student2 = new Student("李四", 16);
System.out.println(getMaxAge(student1, student2));
}
//实现比较方法
public static Student getMaxAge(Student o1, Student o2) {
int n = o1.compareTo(o2);
if(n >= 0) return o1;
else return o2;
}
}
2.冒泡排序
原理:比较相邻元素,如果前一个元素比后一个元素大,就交换这两个元素的位置;每一次遍历都对每一对相同元素做同样的,直到最后排序完成。代码示例如下:
package SortDemo;
//冒泡排序实现
public class Bubble {
//排序
public static void sort(Comparable[] a) {
for(int i = a.length - 1; i > 0; i--) {
for(int j = 0; j < i; j++) {
if(greater(a[i], a[j]))
exchange(a, i, j);
}
}
}
//比较两个值v和w的大小
public static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
//交换数组a中下标为i和j的值
public static void exchange(Comparable[] a, int i, int j) {
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
package SortDemo;
import java.util.Arrays;
//冒泡排序测试
public class Test {
public static void main(String[] args) {
Integer[] a = {8,4,2,3,6,7,5,1,0};
Bubble.sort(a);
System.out.println(Arrays.toString(a));
}
}
冒泡排序的时间复杂度是O(n^2),所以它适用于较小量的比较场景。
3.选择排序
原理:在每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处的值大于其他某个索引处的值,则进行交换,并假定其他某个索引处的值为最小值,但索引未变。示例代码如下:
package SelectionDemo;
public class Selection {
//排序
public static void sort(Comparable[] a) {
for(int i = 0; i < a.length; i++) {
int minIndex = i;
for(int j = i + 1; j < a.length; j++) {
if(greater(a[minIndex], a[j]))
minIndex = j;
}
exchange(a, i, minIndex);
}
}
//比较两个值v和w的大小
public static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
//交换数组a中下标为i和j的值
public static void exchange(Comparable[] a, int i, int j) {
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
package SelectionDemo;
import java.util.Arrays;
//选择排序测试
public class SelectionTest {
public static void main(String[] args) {
Integer[] a = {8,4,2,3,6,7,5,1,0};
Selection.sort(a);
System.out.println(Arrays.toString(a));
}
}
选择排序的时间复杂度是O(n^2),所以它适用于较小量的比较场景。
4.插入排序
原理:
- 形象地把所有的元素分为两组,已排序组和未排序组;
- 找到未排序组中的第一个元素,向已排序组中进行插入;
- 倒叙遍历已排序组,依次与未排序组的第一个元素进行比较,符合条件进行交换并进行下一次比较,若不符合条件,即已排序没有比未排序组的第一个元素小的,则跳出当前循环并进行未排序组下一个元素的排序。
代码示例如下:
package InsertionDemo;
public class Insertion {
//排序
public static void sort(Comparable[] a) {
for(int i = 1; i < a.length; i++) {
for(int j = i; j > 0 ; j--) {
if(greater(a[j - 1], a[j]))
exchange(a, j - 1, j);
else
break;
}
}
}
//比较两个值v和w的大小
public static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
//交换数组a中下标为i和j的值
public static void exchange(Comparable[] a, int i, int j) {
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
package InsertionDemo;
import java.util.Arrays;
//插入排序测试
public class InsertionTest {
public static void main(String[] args) {
Integer[] a = {8,4,2,3,6,7,5,1,0};
Insertion.sort(a);
System.out.println(Arrays.toString(a));
}
}
插入排序的时间复杂度是O(n^2),所以它适用于较小量的比较场景。
※5.希尔排序
原理:
- 选定一个增长量h,按照增长量h作为数组分组的依据,对数据进行分组;
- 对分好组的每一组数据完成插入排序;
- 减小增长量,最小减为1,重复第二步。
增长量确定依据:
int h = 1;
//h的增长规律
while(h < 数组长度/2) {
h =2 * h + 1;
}
//h的减小规律
h = h / 2;
代码示例如下:
package ShellDemo;
//希尔排序实现
public class Shell {
public static void sort(Comparable[] a) {
int h = 1;
while(h < a.length) {
h = 2 * h + 1;
}
//当增长量h=1时,排序结束
while(h >= 1) {
//找到待排序的元素
for(int i = h; i < a.length; i++) {
//将待排序元素插入已排序组中
for(int j = i; j >= h; j -= h) {
if(greater(a[j], a[j - h]))
exchange(a, j, j - h);
else
break;
}
}
h = h / 2;
}
}
//比较两个值v和w的大小
public static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
//交换数组a中下标为i和j的值
public static void exchange(Comparable[] a, int i, int j) {
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
package ShellDemo;
import java.util.Arrays;
//希尔排序测试
public class ShellTest {
public static void main(String[] args) {
Integer[] a = {8,4,2,3,6,7,5,1,0};
Shell.sort(a);
System.out.println(Arrays.toString(a));
}
}
在进行大量数据排序时,希尔排序所用时间是冒泡、选择和插入排序的千分之一,所以希尔排序适合进行大量数据排序的场景。
※6.归并排序
6.1递归
定义:在定义方法时,在方法的内部调用方法的本身,称之为递归。
public void show() {
System.out.println("aaa");
show();
}
//这样写实际上有些错误,没有结束条件,会进入死循环
实际应用代码示例如下:
//求n的阶乘
public class FactorialTest {
public static void main(String[] args) {
System.out.println(factorial(5)); //120
}
public static long factorial(int n) {
if(n == 1)
return 1;
else
return n * factorial(n - 1);
}
}
6.2归并排序
原理:通过递归,将原数组从中间分为两组,直至分到不能分为止,然后对分组后的数组进行排序,再将排序后的数组归并到原数组,完成排序。代码示例如下:
package MergeDemo;
public class Merge {
//辅助数组
static Comparable[] assist;
//对数组a进行排序
public static void sort(Comparable[] a) {
//初始化辅助数组
assist = new Comparable[a.length];
//定义lo记录数组最小索引,定义hi记录数组最大索引
int lo = 0;
int hi = a.length - 1;
//对数组a中从索引lo到索引hi的元素排序
sort(a, lo, hi);
}
//对数组a中从索引lo到索引hi的元素排序
public static void sort(Comparable[] a, int lo, int hi) {
if(hi <= lo)
return;
//对数组进行分组
int mid = lo + (hi - lo) / 2;
//对分组后的数组元素进行排序
sort(a, lo, mid); //对索引lo到索引mid的元素排序
sort(a, mid + 1, hi); //对索引mid+1到索引hi的元素排序
//将排完序的两个数组归并
merge(a, lo, mid, hi);
}
private static void merge(Comparable[] a, int lo, int mid, int hi) {
//定义三个指针
int i = lo ;
int p1 = lo;
int p2 = mid + 1;
//对两组数据的元素进行比较,并存入辅助数组
while(lo <= mid && p2 <= hi) {
if(greater(a[p1], a[p2]))
assist[i++] = a[p1++];
else
assist[i++] = a[p2++];
}
//如果指针p1没有走完,那么顺序移动p1指针,把对应元素放到辅助数组的对应索引处
while(p1 <= mid)
assist[i++] = a[p1++];
//如果指针p2没有走完,那么顺序移动p2指针,把对应元素放到辅助数组的对应索引处
while(p2 <= hi)
assist[i++] = a[p2++];
//将辅助数组中的数据拷贝到原数组中
for(int index = lo; index <= hi; index++)
a[index] = assist[index];
}
//比较两个值v和w的大小
public static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
//交换数组a中下标为i和j的值
public static void exchange(Comparable[] a, int i, int j) {
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
package MergeDemo;
import java.util.Arrays;
//归并排序测试
public class MergeTest {
public static void main(String[] args) {
Integer[] a = {8,4,2,3,6,7,5,1,0};
Merge.sort(a);
System.out.println(Arrays.toString(a));
}
}
归并排序的时间复杂度减小到了O(logn),适合于对大量数据进行排列的场合。
视频教程:黑马程序员Java数据结构与java算法,全网资料最全数据结构+算法教程,154张java数据结构图_哔哩哔哩_bilibili
※7.快速排序
原理:
- 设置一个分界值,通过该分界值将数组分成左右两部分;
- 将大于或等于分界值的放在分界值右边,小于分界值的放在左边;
- 分别对分界值两边的数组重复上述过程;(可以看出这是一个递归)
- 再通过递归分别对左右两个数组进行排序,当递归结束,整个数组就排好了。
代码示例如下:
视频教程:黑马程序员Java数据结构与java算法,全网资料最全数据结构+算法教程,154张java数据结构图_哔哩哔哩_bilibili
※8.堆排序
待补充