看看七大排序算法吧
2018-09-06 12:26:18

排序

内部排序

插入排序
  • 直接插入排序
  • 希尔排序
选择排序
  • 简单选择排序
  • 堆排序
交换排序
  • 冒泡排序
  • 快速排序

直接插入排序

给定一组序列,假定第一个记录自成一个有序序列,其余记录为无序序列。接着从第二个记录开始,按照记录的大小依此将当前处理的记录插入到其之前的有序序列中,直到最后一个记录插入到有序序列中为止

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  static void insertSort(int arr[]){
// 1. 假设第一个序列的第一个元素是有序的
// 38,73,27,79,19,76
if(arr == null || arr.length ==0){
return ;
}
int j = 0;
// 2. 设置一个下标,从1开始(从第二个元素开始)
for(int i = 1;i<arr.length;i++){
// 当前元素和前一个比较
int temp = arr[i];
j = i;
if(temp < arr[j=1]){
// 前一个比当前的大,则将当前元素放到合适的位置
// 此处要找出当前元素合适的位置,同时把前面的元素向后移动
do{
arr[j] = arr[j-1];
j--;
}while(arr[j]>temp && j>=1);

arr[j] = temp;
}
}

}
1
2
3
4
排序前:
38 65 97 76 13 27 49
排序后:
13 27 38 49 65 76 97

希尔排序(最小增量排序)

算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void shellSort(int arr[]){
int length = arr.length;
// 初始化增量h = length/2,每循环一次增量h/2
for(int h = length/2;h>0;h=h/2){
// 对相差当前增量的元素排序
for(int i = 0;i<length-h;i++){
int temp ;
if(arr[i+h]<arr[i]){
temp = arr[i+h];
arr[i+h] = arr[i];
arr[i] = temp;
}
}
}
}
1
2
3
4
排序前:
38 65 97 76 13 27 49
shell排序后:
13 27 38 49 65 76 97

简单选择排序

在要排序的一组数中,选出最小的一个数与第一个位置的数交换;

然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void selectSort(int arr[]){
int minLocation = 0;
// 在序列中挑选出最小的一个数和第一个交换
for(int i = 0;i<arr.length;i++){
int temp = arr[i]; // 最小的数
// 遍历查找出最下的数
for(int j = i+1;j<arr.length;j++){
if(temp > arr[j]){
temp = arr[j]; // temp 为最小的数
minLocation = j;
}
}
// 到此,找出了本次循环最小的数和最小数的位置
// 交换
if(minLocation != i){
arr[minLocation] = arr[i];
arr[i] = temp;
}

}
}
1
2
3
4
排序前:
38 65 97 76 13 27 49
选择排序后:
13 27 38 49 65 76 97

堆排序

堆排序是一种树形选择排序,是对直接选择排序的有效改进。

冒泡排序

在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void bubbleSort(int[] arr){
int i;
int j;
int temp = 0;

for ( i = 0; i < arr.length; i++) {
// 内部循环从序列末尾开始
for(j = arr.length-1;j>i;j--){
if(arr[j-1] > arr[j]){
// 交换
temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
}


}
}
}
1
2
3
4
排序前:
38 65 97 76 13 27 49 21 5 8 6 4 8 3 9
冒泡排序后:
3 4 5 6 8 8 9 13 21 27 38 49 65 76 97

快速排序

快速排序是一种非常高效的排算法,它采用了分而治之的思想,把大的拆成小的,小的再拆分为更小的

基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

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
36
37
38
39
40
41
42
43
44
public static void quickSort(int []arr){
sort(arr, 0, arr.length-1);

}

private static void sort(int arr[],int low,int high){
// 选择基准元素,扫描一遍
if(low>=high) return;
int i = low;
int j = high;
int key = arr[low]; // 选择基准元素
while(j>i){
/*if(arr[i]>arr[j]){
//
}*/
// 可能会出现连续的比关键字大的,就需要继续找,所以使用循环
// 从后向前比较
while(j>i && key <= arr[j]){ // 如果没有比关键字小的,则比较下一个,直到有比关键字小的交换位置
j--;
}
// 找出比关键字小的位置,交换两个位置的元素
if(arr[j]<=key){
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}

// 从前向后比较
while(j>i && key >= arr[i]){ // 如果没有比关键字小的,则比较下一个,直到有比关键字小的交换位置
i++;
}
if(arr[i]>=key){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//此时第一次循环比较结束,
//关键值的位置已经确定了。左边的值都比关键值小,右边的值都比关键值大,
//但是两边的顺序还有可能是不一样的,进行下面的递归调用
// 递归
sort(arr, low, i-1);
sort(arr,j+1,high);
}
1
2
3
4
排序前:
38 65 97 76 13 27 49 21 5 8 6 4 8 3 9 58 66 75 22 93 91 10
冒泡排序后:
3 4 5 6 8 8 9 10 13 21 22 27 38 49 58 65 66 75 76 91 93 97

并归排序

并归排序的思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

使用技术: 递归分治

先拆分再组合

并归时排序,采用双指针分别指向左半边和右半边,左半边的和有半边的比较大小,小的一边存入新的数组并自增

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 static void mergeSort(int []arr,int low,int high){
if(low < high){
int mid = (low+high)/2;
mergeSort(arr, low, mid); // 左边
mergeSort(arr, mid+1, high); // 右边
merge(arr, low, mid, high);
}
}
private static void merge(int arr[],int low,int mid,int high){
int temp[] = new int [high-low+1];
int left = low;
int right = mid + 1;
int indexOfTemp = 0; // temp 数组中的索引

// 此时左边数组的数为有序的
while(left<=mid && right<=high){
// 比较左右两个,找出小的放到temp中
if(arr[left] < arr[right]){
temp[indexOfTemp++] = arr[left++];
}else{
temp[indexOfTemp++] = arr[right++];
}
}

while(left <= mid){
temp[indexOfTemp++] = arr[left++];
}
while(right <= high){
temp[indexOfTemp++] = arr[right++];
}
// temp -> arr
for(int i = 0;i<temp.length;i++){
arr[low + i] = temp[i];
}
}
1
2
3
4
排序前:
58 66 75 22 93 91 10 16 52 18 90 77 44 29
并归排序后:
10 16 18 22 29 44 52 58 66 75 77 90 91 93