简单排序

简单排序


Comparable接口

Java提供了Comparable就是用来定义排序规则的。

例:

  • 定义一个学生类Student,具体年龄age和姓名username两个属性,并通过Comparable接口提供比较规则;
  • 定义测试类Test,在测试类Test中定义测试方法Comparable getMax(Comparable c1, Comparable c2)完成测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Student implements Comparable<Student>{
private int age;
private String username;

public Student(int age, String name){
this.age = age;
this.username = name;
}

public int getAge(){
return this.age;
}

public String getUsername{
return this.username;
}

public void setAge(int age){
this.age = age;
}

public void setUsername(String name){
this.username = name;
}

@Override
public String toString(){
return "Student{" + "username=" + this.username + ", age=" + this.age + "}";
}

@Override
public int compareTo(Student o){
return this.getAge() - o.getAge();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test{
public static void main(String[] args){
Student s1 = new Student("zhangsan",18);
Student s2 = new Student("lisi",20);
Comparable max = getMax(s1,s2);
System.out.println(max);
}

public static Comparable getMax(Comparable c1, Comparable c2){
int result = c1.compareTo(c2);
if(result >= 0){
return c1;
}else{
return c2;
}
}
}

冒泡排序

需求:

  • 排序前:{4,5,6,3,2,1}
  • 排序后:{1,2,3,4,5,6}

排序原理:

  • 比较相邻的元素,如果前一个元素比后一个元素大,就交换这两个元素的位置;
  • 对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大值。
冒泡次数 冒泡后的结果
初始状态 4,5,6,3,2,1
第一次冒泡 4,5,3,2,1,6
第二次冒泡 4,3,2,1,5,6
第三次冒泡 3,2,1,4,5,6
第四次冒泡 2,1,3,4,5,6
第五次冒泡 1,2,3,4,5,6
第六次冒泡 1,2,3,4,5,6

冒泡排序API设计:

类名 Bubble
构造方法 Bubble()
成员方法 public static void sort(Comparable[] a):对数组内的元素进行排序
private static boolean greater(Comparable v, Comparable w):判断v是否大于w
private static void exch(Comparable[] a, int i, int j):交换a数组中,索引i和索引j处的值

冒泡排序的代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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[j],a[j+1])){
exch(a,j,j+1);
}
}
}
}

private static boolean greater(Comparable v, Comparable w){
return v.compareTo(w) > 0;
}

private static void exch(Comparable[] a, int i, int j){
Comparable temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
1
2
3
4
5
6
7
8
public class BubbleTest{
public static void main(String[] args){
Integer[] arr = {4,5,6,3,2,1};
Bubble.sort(arr);

System.out.println(Arrays.toString(arr));
}
}

冒泡排序的时间复杂度分析

在最坏情况下,也就是假如要排序的元素为{6,5,4,3,2,1},那么元素的比较次数为:$(N-1)+(N-2)…+2+1=(1+N-1)*(N-1)/2=\frac{N^2-N}{2}$元素交换次数为:$\frac{N^2-N}{2}$,总执行次数为$N^2-N$,按照大O推导法则,冒泡排序的时间复杂度为$O(N^2)$。


选择排序

需求:

  • 排序前:{4,6,8,7,9,2,10,1}
  • 排序后:{1,2,4,5,7,8,9,10}

排序原理:

  • 每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处的值大于其他某个索引处的值,则假定其他某个索引处的值为最小值,最后可以找到最小值所在的索引
  • 交换第一个索引处和最小值所在的索引处的值
{4,6,8,7,9,2,10,1} 原始数据
{1,6,8,7,9,2,10,4} 第一趟排序Min=1
{1,2,8,7,9,6,10,4} 第二趟排序Min=2
{1,2,4,7,9,6,10,8} 第三趟排序Min=4
{1,2,4,6,9,7,10,8} 第四趟排序Min=6
{1,2,4,6,7,9,10,8} 第五趟排序Min=7
{1,2,4,6,7,8,10,9} 第六趟排序Min=8
{1,2,4,6,7,8,9,10} 第七趟排序Min=9

选择排序API设计:

类名 Selection
构造方法 Selection()
成员方法 public static void sort(Comparable[] a)
private static boolean greater(Comparable v, Comparable w)
private static void exch(Comparable[] a, int i, int j)

选择排序的代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Selection{
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,i,minIndex);
}
}

private static boolean greater(Comparable v, Comparable m){
return v.compareTo(w) > 0;
}

private static void exch(Comparable[] a, int i, int j){
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
1
2
3
4
5
6
public class SelectionTest{
Integer[] arr = {4,6,8,7,9,2,10,1};
Selection.sort(arr);

System.out.println(Arrays.toString(arr));
}

选择排序的时间复杂度分析:

数据比较的次数:$(N-1)+(N-2)..+2+1=\frac{N^2-N}{2}$,数据交换次数:N-1,时间复杂度为$O(N^2)$。


插入排序

需求:

  • 排序前:{4,3,2,10,12,1,5,6}
  • 排序后:{1,2,3,4,5,6,10,12}

排序原理:

  • 把所有的元素分为两组,已经排序的未排序的;
  • 找到未排序的组中第一个元素,向已排序的组中进行插入;
  • 倒叙遍历已经排序的元素,依次和待插入的元素进行比较,直到找到一个元素小于等于待插入元素,那么就把待插入元素放到这个位置,其他的元素向后移动一位。
{4,3,2,10,12,1,5,6} 原始数据
{4,3,2,10,12,1,5,6} 第一趟排序(待插入数字为3)
{3,4,2,10,12,1,5,6} 第二趟排序(待插入数字为2)
{2,3,4,10,12,1,5,6} 第三趟排序(待插入数字为10)
{2,3,4,10,12,1,5,6} 第四趟排序(待插入数字为12)
{2,3,4,10,12,1,5,6} 第五趟排序(待插入数字为1)
{1,2,3,4,10,12,5,6} 第六趟排序(待插入数字为5)
{1,2,3,4,5,10,12,6} 第七趟排序(待插入数字为6)
{1,2,3,4,5,6,10,12} 最终结果

插入排序API设计:

类名 Insertion
构造方法 Insertion()
成员方法 public static void sort(Comparable[] a)
private static boolean greater(Comparable v, Comparable w)
private static void exch(Comparable[] a, int i, int j)

插入排序代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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])){
exch(a,j-1,j);
}else{
break;
}
}
}
}

private static boolean greater(Comparable v, Comparable w){
return v.compareTo(w) > 0;
}

private static void exch(Comparable[] a, int i, int j){
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
1
2
3
4
5
6
public class InsertionTest{
Integer[] arr = {4,6,8,7,9,2,10,1};
Inserction.sort(arr);

System.out.println(Arrays.toString(arr));
}

插入排序的时间复杂度分析:

在最坏情况下,比较次数为:$(N-1)+(N-2)…+2+1=\frac{N^2-N}{2}$,交换次数为:$\frac{N^2-N}{2}$,执行总次数为:$N^2-N$,因此插入排序的时间复杂度为:$O(N^2)$。

Donate comment here