目录
Comparable 接口
- 要比较的类实现Comparable接口
- class Student implements Comparable<Student>
- 重写compareTo方法
@Override public int compareTo(Student o) { return this.getAge()-o.getAge(); }
package test.comparable;
public class Student implements Comparable<Student>{
private int age;
private String name;
public Student() {
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Student o) {
return this.getAge()-o.getAge();
}
}
package test.comparable;
public class Test {
public static void main(String[] args) {
Student st1 = new Student(3,"lisan");
Student st2 = new Student(4,"王四");
Comparable cc = getMax(st1,st2);
System.out.println(cc);
}
public static Comparable getMax(Comparable c1,Comparable c2){
int i = c1.compareTo(c2);
if(i>=0){
return c1;
}else{
return c2;
}
}
}
输出:
Student{age=4, name='王四'}
1、简单排序
1.1、冒泡排序
package test.comparable;
public class Bubble {
/*
对数组a进行排序
*/
private static void sort(Comparable<?> [] a){
for (int i = a.length-1; i>0 ; i--) {
for (int j = 0; j <i ; j++) {
if(greater(a[j],a[j+1])){
exch(a,j,j+1);
}
}
}
}
private static boolean greater(Comparable v,Comparable w){
return v.compareTo(w)>0;
}
/**
* 数组元素i和j交换位置
* @param a
* @param i
* @param j
*/
private static void exch(Comparable<?>[]a,int i,int j){
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
测试代码
package test.comparable;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Integer [] a = {4,5,3,7,8,2,1};
Bubble.sort(a);
System.out.println(Arrays.toString(a));
}
}
冒泡排序时间复杂度分析
1.2、选择排序
选择排序的api设计
类名 | sefection |
构造方法 | Selection();创建Selection对象 |
成员方法 | 1、public static void sort(Comparable<?> [] a)对数组内的元素进行排序 2、private static boolean greater(Comparable v,Comparable w)判断V是否大于W 3、private static void exch(Comparable<?>[]a,int i,int j);交换a数组中索引i和索引j处的值 |
package test.comparable;
public class Selection {
/*
对数组a进行排序
*/
public static void sort(Comparable<?> [] a){
for (int i = 0; i <a.length-1 ; i++) {
int minIndex = i;
for (int j = i+1; j <a.length ; j++) {
if(greater(a[minIndex],a[j])){
minIndex = j;
}
}
exch(a,minIndex,i);
}
}
private static boolean greater(Comparable v,Comparable w){
return v.compareTo(w)>0;
}
/**
* 数组元素i和j交换位置
* @param a
* @param i
* @param j
*/
private static void exch(Comparable<?>[]a,int i,int j){
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
/**测试代码
*/
public class Test {
public static void main(String[] args) {
Integer [] a = {4,5,3,7,8,2,1};
Selection.sort(a);
System.out.println(Arrays.toString(a));
}
}
1.3、插入排序
package test.comparable;
public class Insertion {
/*
对数组a进行排序
*/
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])){
exch(a,j-1,j);
}else{
break;
}
}
}
}
private static boolean greater(Comparable v,Comparable w){
return v.compareTo(w)>0;
}
/**
* 数组元素i和j交换位置
* @param a
* @param i
* @param j
*/
private static void exch(Comparable<?>[]a,int i,int j){
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
2、高级排序
2.1 希尔排序
增长量h的确定:增长量h的值每一固定的规则,我们这里采用以下规则:
int h =1
while(h<数组的长度/2){
h = 2h+1
}
//循环后我们可以获取h的最大值
h的减小规则为
h=h/2;
希尔排序的api设计
类名 | Shell |
构造方法 | Shell();创建Selection对象 |
成员方法 | 1、public static void sort(Comparable<?> [] a)对数组内的元素进行排序 2、private static boolean greater(Comparable v,Comparable w)判断V是否大于W 3、private static void exch(Comparable<?>[]a,int i,int j);交换a数组中索引i和索引j处的值 |
package test.comparable;
public class Shell {
/*
对数组a进行排序
*/
public static void sort(Comparable [] a){
//1、根据数组的长度,确定正常量h的初始值
int h =1;
while(h<(a.length/2)){
h=2*h+1;
}
//2、希尔排序
while(h>=1){
//排序
for(int i=h;i<a.length;i++){
for(int j=i;j>=h;j-=h){
if(greater(a[j-h],a[j])){
exch(a,j-h,j);
}else{
//待插入的数据以及找到合适的
break;
}
}
}
//
//减小h的值
h=h/2;
}
}
private static boolean greater(Comparable v,Comparable w){
return v.compareTo(w)>0;
}
/**
* 数组元素i和j交换位置
* @param a
* @param i
* @param j
*/
private static void exch(Comparable<?>[]a,int i,int j){
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
希尔排序的时间复杂度不好计算,但是比插入排序快很多
2.2归并排序
排序原理
1、尽可能地把一组数据分成俩个元素相等的子组,并对每个子组继续拆分,直到拆分后的每个子组个数是1为止。
2、将相邻的俩个子组进行合并成一个有序的大组。
3、不断地重复操作,直到最终只有一个组为止。
归并排序api设计:
类名 | Merge |
构造方法 | Merge();创建Merge对象 |
成员方法 | 1、public static void sort(Comparable<?> [] a);对数组内的元素进行排序 2、private static void sort(Comparable [] a,int lo,int hi); 对数组a中从lo到hi的元素进行排序 3、 private static void merge(Comparable[] a , int lo,int mid , int hi) 对数组中,从lo到min为一组,从min+1到hi为一组,对着俩组数据进行归并 4、 private static boolean less(Comparable v,Comparable w) 比较v大小是否小于w大小 5、 private static void exch(Comparable<?>[]a,int i,int j) 数组元素i和j交换位置 |
成员变量 | 1、private static Comparable[] assist;完成并归操作需要的辅助数组 |
package test.comparable;
/**
* 归并排序
*/
public class Merge {
//归并所需要的辅助数组
private static Comparable[] assist;
/**
* 比较v大小是否小于w大小
* @param v
* @param w
* @return
*/
private static boolean less(Comparable v,Comparable w){
return v.compareTo(w)<0;
}
/**
* 数组元素i和j交换位置
* @param a
* @param i
* @param j
*/
private static void exch(Comparable<?>[]a,int i,int j){
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
/**
* 对数组a中的元素进行排序
* @param a
*/
public static void sort(Comparable [] a){
//1、初始化辅助数组
assist = new Comparable[a.length];
//2、定义一个lo变量,和hi变量,分别记录数组中最小索引和最大索引;
int lo = 0;
int hi = a.length-1;
//3、调用sort重载方法完成数组a中,从索引lo到索引hi的排序
sort(a,lo,hi);
}
/**
* 对数组a中从lo到hi的元素进行排序
* @param a
* @param lo
* @param 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);
sort(a,mid+1,hi);
merge(a,lo,mid,hi);
}
/**
* 对数组中,从lo到min为一组,从min+1到hi为一组,对着俩组数据进行归并
* @param a
* @param lo
* @param mid
* @param hi
*/
private static void merge(Comparable[] a , int lo,int mid , int hi){
//1、定义三个指针
int i=lo;
int p1=lo;
int p2=mid+1;
//2、遍历、移动p1指针和p2指针,比较对应索引处的值,找到小的那个,放到辅助数组的对于索引处
while(p1 <= mid && p2 <=hi){
if(less(a[p1],a[p2])){
assist[i++]=a[p1++];
}else{
assist[i++]=a[p2++];
}
}
//3、如果p1没有走完,那么顺序移动p1指针,把对应的元素放到辅助数组的对应索引处
while(p1<=mid){
assist[i++]=a[p1++];
}
//4、如果p2没有走完,那么顺序移动p2指针,把对应的元素放到辅助数组的对应索引处
while(p2<=hi){
assist[i++]=a[p2++];
}
//把辅助数组的数据考呗到原数组中
for (int index = lo; index <=hi ; index++) {
a[index]=assist[index];
}
}
}
2.3快速排序
需求
排序前:{6,1,2,7,9,3,4,5,8}
排序后:{1,2,3,4,5,6,7,8,9}
排序原理:
1、首先设定一个分界值,通过读分界值件数组分成左右俩个部分
2、将大于或等于分界值的数据放到数组右边,小于分界值的数据放到数组左边,此时左边部分各元素小于或等于分界值,而右边部放置较大值,有车的数组数据也可以做类似处理。
3、重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序,当左侧和右侧俩个部分的数组排好序后,整个数组的排序也就完成了。
快速排序api设计
类名 | Quick |
构成方法 | Quick();创建Quick对象 |
成员方法 |
切分原理:
把一个数组切分成俩个子数组的基本思想
1、找一个基准值,用俩个指针分别指向数组的头部和尾部;
2、先把尾部向头部开始收索一个比基准值小的元素,收索到即停止,并记录指针的位置。
3、再从头部向尾部开始收索一个比基准值大的元素,收索到即停止,并记录指针的位置。
4、交换当前左边指针位置和右边指针位置的元素
5、重复2,3,4步骤,直到左边指针的值大于右边指针的值停止。
package test.comparable;
public class Quick {
public static void sort(Comparable[] a){
sort(a,0,a.length-1);
}
private static void sort(Comparable[] a,int lo ,int hi){
//安全性校验
if(hi<=lo){
return;
}
//需要对数组中lo索引到hi索引之间的元素进行排序
int partition = partition(a,lo,hi);
//让左子组有序,
sort(a,lo,partition-1);
// 让右子组有序
sort(a,partition+1,hi);
}
//对数组a中,从索引lo到索引hi之间的元素进行分组,并返回分组界限对应的索引
private static int partition(Comparable[] a , int lo , int hi ){
//确定分界值
Comparable key = a[lo];
//定义俩个指针,分别指向待切分元素的最小索引处和最大索引处的下一个位置
int left=lo;
int right=hi+1;
//切分
while(true){
//先从右往左扫描,移动right指针,找到一个比分界值小的元素,停止
while(less(key,a[--right])){
if(right==lo){
break;
}
}
//再先从左往右扫描,移动left指针,找到一个比分界值大的元素,停止
while(less(a[++left],key)){
if(left==hi){
break;
}
}
//判断left>=right,如果是,则证明元素扫描完毕,如果不是,则交换元素
if(left>=right){
break;
}else{
exch(a,left,right);
}
}
exch(a,lo,right);
return right;
}
private static boolean less(Comparable v,Comparable w){
return v.compareTo(w)<0;
}
/**
* 数组元素i和j交换位置
* @param a
* @param i
* @param j
*/
private static void exch(Comparable<?>[]a,int i,int j){
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}