一 简要介绍
算法思路,从后往前先找到要插入的位置,如果小于则就交换,将元素向后移动,将要插入数据插入该位置即可。时间复杂度为O(n2),空间复杂度为O(1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package sort.algorithm;
public class DirectInsertSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
int data[] = { 2 , 6 , 10 , 3 , 9 , 80 , 1 , 16 , 27 , 20 };
int temp, j;
for ( int i = 1 ; i < data.length; i++) {
temp = data[i];
j = i - 1 ;
// 每次比较都是对于已经有序的
while (j >= 0 && data[j] > temp) {
data[j + 1 ] = data[j];
j--;
}
data[j + 1 ] = temp;
}
// 输出排序好的数据
for ( int k = 0 ; k < data.length; k++) {
System.out.print(data[k] + " " );
}
}
} |
如果mid小于data,则就表示插入的数据在mid的右边,low=mid+1
最后整体进行右移操作。
时间复杂度O(n2),空间复杂度O(1)
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
|
package sort.algorithm;
//折半插入排序 public class HalfInsertSort {
public static void main(String[] args) {
int data[] = { 2 , 6 , 10 , 3 , 9 , 80 , 1 , 16 , 27 , 20 };
// 存放临时要插入的元素数据
int temp;
int low, mid, high;
for ( int i = 1 ; i < data.length; i++) {
temp = data[i];
// 在待插入排序的序号之前进行折半插入
low = 0 ;
high = i - 1 ;
while (low <= high) {
mid = (low + high) / 2 ;
if (temp < data[mid])
high = mid - 1 ;
else
// low=high的时候也就是找到了要插入的位置,
// 此时进入循环中,将low加1,则就是要插入的位置了
low = mid + 1 ;
}
// 找到了要插入的位置,从该位置一直到插入数据的位置之间数据向后移动
for ( int j = i; j >= low + 1 ; j--)
data[j] = data[j - 1 ];
// low已经代表了要插入的位置了
data[low] = temp;
}
for ( int k = 0 ; k < data.length; k++) {
System.out.print(data[k] + " " );
}
}
} |
算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。
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
|
package sort.algorithm;
public class ShellSort {
public static void main(String[] args) {
int a[] = { 1 , 54 , 6 , 3 , 78 , 34 , 12 , 45 , 56 , 100 };
double d1 = a.length;
int temp = 0 ;
while ( true )
{
//利用这个在将组内倍数减小
//这里依次为5,3,2,1
d1 = Math.ceil(d1 / 2 );
//d为增量每个分组之间索引的增量
int d = ( int ) d1;
//每个分组内部排序
for ( int x = 0 ; x < d; x++)
{
//组内利用直接插入排序
for ( int i = x + d; i < a.length; i += d) {
int j = i - d;
temp = a[i];
for (; j >= 0 && temp < a[j]; j -= d) {
a[j + d] = a[j];
}
a[j + d] = temp;
}
}
if (d == 1 )
break ;
}
for ( int i = 0 ; i < a.length; i++)
System.out.print(a[i]+ " " );
}
} |
五 交换类排序之冒泡排序
时间复杂度O(n2),空间复杂度O(1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package sort.algorithm;
//冒泡排序:是一种交换排序 public class BubbleSort {
// 按照递增顺序排序
public static void main(String[] args) {
// TODO Auto-generated method stub
int data[] = { 2 , 6 , 10 , 3 , 9 , 80 , 1 , 16 , 27 , 20 , 13 , 100 , 37 , 16 };
int temp = 0 ;
// 排序的比较趟数,每一趟都会将剩余最大数放在最后面
for ( int i = 0 ; i < data.length - 1 ; i++) {
// 每一趟从开始进行比较,将该元素与其余的元素进行比较
for ( int j = 0 ; j < data.length - 1 ; j++) {
if (data[j] > data[j + 1 ]) {
temp = data[j];
data[j] = data[j + 1 ];
data[j + 1 ] = temp;
}
}
}
for ( int i = 0 ; i < data.length; i++)
System.out.print(data[i] + " " );
}
} |
空间复杂度O(long2n),快速排序需要递归用到了栈
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
45
|
package sort.algorithm;
//快速排序算法:是一种交换排序 public class QuikSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
int data[] = { 2 , 6 , 10 , 3 , 9 , 80 , 1 , 16 , 27 , 20 , 105 , 34 , 44 , 19 };
QuikSort sort = new QuikSort();
sort.sortArray(data, 0 , data.length - 1 );
for ( int i = 0 ; i < data.length; i++)
System.out.print(data[i] + " " );
}
// 这里不用返回值,直接对传入的数组进行操作
public void sortArray( int data[], int first, int end) {
int temp;
int i = first, j = end;
if (first < end) {
temp = data[i];
// 当i=j的时候,则说明扫描完成了
while (i < j) {
// 从右边向左边扫描找到一个小于temp的元素
while (j > i && data[j] > temp)
j--;
if (i < j) {
// 将该元素赋值给temp
data[i] = data[j];
// 赋值后就应该将i+1指向下一个序号
i++;
}
// 然后从左边向右边开始扫描,找到一个大于temp的元素
while (i < j && temp > data[i])
i++;
if (i < j) {
// 将该元素赋值给temp
data[j] = data[i];
// 赋值后就应该将j-1指向前一个序号
j--;
}
}
// 将轴数据放在i位置中
data[i] = temp;
sortArray(data, first, i - 1 );
sortArray(data, i + 1 , end);
}
}
} |
简单选择排序,每一趟从数据中选择一个最小值放到最前面,但是不需要交换位置,只记录该交换的位置,只有找到后才做一次交换!
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
|
package sort.algorithm;
//简单选择排序:是一种选择排序 public class SelectSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
int data[] = { 2 , 6 , 10 , 3 , 9 , 80 , 1 , 16 , 27 , 20 , 11 , 3 , 1 , 100 , 89 };
int temp, k;
// 开始时间
long start = System.nanoTime();
// 选择的每一趟数,每一趟都会将一个最小的放在最前面。
for ( int i = 0 ; i < data.length - 1 ; i++) {
// 使用k来记录要交换的位置,且k在比较的过程不断变化
k = i;
// 由于每一趟都会将最小的放在最前面,所以索引+1
for ( int j = i; j < data.length; j++)
// 这里始终要与k比较
if (data[j] < data[k])
k = j;
// k已经存放了交换的位置了
temp = data[i];
data[i] = data[k];
data[k] = temp;
}
System.out.println(System.nanoTime() - start);
// 输出排序好的数据
for ( int m = 0 ; m < data.length; m++) {
System.out.print(data[m] + " " );
}
}
} |
八 选择类排序之堆排序
堆排序就是建立大顶堆或者小顶堆,若建立大顶堆,每次对于建好的大顶堆将根元素与最后一个元素交换,无序的数目减少,有序的数目增加。
对于求N个数据中的前n个最小的数据,首先就是建立一个n个的大顶堆,然后让其余的元素来进行与这堆顶元素比较,如果小于则与堆顶互换元素。
这里采用数组存储节点,并且下标统一从0,length-1,所以对于这样处理的左孩子节点下标为
2 * i+1,右孩子的节点下标为2 * i+2
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
package sort.algorithm;
public class HeapSort {
public static int heap_size;
// 左孩子编号
public static int leftChild( int i) {
return 2 * i+ 1 ;
}
// 右孩子编号
public static int rightChild( int i) {
return 2 * i + 2 ;
}
/**
* 保持最大堆的性质
* 堆中的数组元素
* 对以该元素为根元素的堆进行调整,假设前提:左右子树都是最大堆
* 由于左右孩子都是最大堆,首先比较根元素与左右孩子,找出最大值,假如大于根元素,则调整两个元素的值;
* 由于左孩子(右孩子)的值与根元素交换,有可能打破左子树(右子树)的最大堆性质,因此继续调用,直至叶子元素。
*/
public static void max_heapify( int [] a, int i) {
int left = leftChild(i);
int right = rightChild(i);
int largest = 0 ;
if (left < heap_size && a[i] < a[left]) {
largest = left;
} else {
largest = i;
}
if (right < heap_size && a[right] > a[largest]) {
largest = right;
}
if (largest == i) {
return ;
} else {
int temp = a[i];
a[i] = a[largest];
a[largest] = temp;
max_heapify(a, largest);
}
}
/**
* 建立最大堆。在数据中,下标a.length/2+1一直到最后的元素a.length-1都是叶子元素
* 因此从其前一个元素开始,一直到
* 第一个元素,重复调用max_heapify函数,使其保持最大堆的性质
*/
public static void build_max_heap( int [] a) {
//从0~a.length/2中建立最大堆
for ( int i = a.length / 2 ; i >= 0 ; i--)
{
max_heapify(a, i);
}
}
/**
* 堆排序:首先建立最大堆,然后将堆顶元素(最大值)与最后一个值交换,同时使得 堆的长度减小1
* 调用保持最大堆性质的算法调整,使得堆顶元素成为最大值,此时最后一个元素已被排除在外、
*/
public static void heapSort( int [] a) {
//构建最大堆
build_max_heap(a);
for ( int i = a.length - 1 ; i >= 0 ; i--)
{
//将第一个元素和最后一个元素进行互换
int temp = a[ 0 ];
a[ 0 ] = a[i];
a[i] = temp;
heap_size--;
//调整堆为最大堆
max_heapify(a, 0 );
}
}
public static void main(String[] args) {
int a[] = { 5 , 4 , 1 , 3 , 2 , 16 , 9 , 10 , 14 , 8 , 7 };
heap_size = a.length; //最大数
heapSort(a);
//输出结果
for ( int i = 0 ; i < a.length; i++) {
System.out.print(a[i] + " " );
}
}
} |
九 二路归并排序
归并排序主要分为分割和归并,每次分割后,对于每一个部分进行排序,然后进行归并,建立一个临时表存储归并后的结果,在将两路进行归并的时候,每一路都已经是有序的。
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
45
46
47
48
49
50
51
52
53
54
55
56
|
package sort.algorithm;
import java.util.Arrays;
//二路归并排序主要分为 //分割和合并 public class MergeSort {
public static void main(String[] args) {
int data[] = { 2 , 6 , 10 , 3 , 9 , 80 , 1 , 16 , 27 , 20 };
mergeSort(data, 0 ,data.length- 1 );
//直接打印
System.out.println(Arrays.toString(data));
}
//二路归并的分割处理
public static void mergeSort( int [] array, int start, int end)
{
if (start<end)
{
//划分为两部分,每次两部分进行归并
int mid=(start+end)/ 2 ;
//两路归并
//先递归处理每一个部分
mergeSort(array,start,mid);
mergeSort(array,mid+ 1 ,end);
//然后将已经排序好的,两两归并排序再进行合并处理
merge(array,start,mid,mid+ 1 ,end);
}
}
//二路归并两个部分的时候进行排序
public static void merge( int [] array, int start1, int end1, int start2, int end2)
{
int i=start1; //左路起始索引
int j=start2; //右路起始索引
int k= 0 ;
//归并的时候,会将两个数组数据按照大小输入到一个临时数组中
//建立临时长度为两个子列表长度的数组
int [] temp= new int [end2-start1+ 1 ];
//循环遍历,按顺序找出两个表中的最小数据依次放入临时表中
//注意此时左路和右路已经是有序的了。
//当一路有一个小的,则会索引加1,继续喝另外一路的上次索引进行比较
while (i<=end1&&j<=end2)
{
//这里确定归并的次序大小
if (array[i]>array[j])
temp[k++]=array[j++];
else
temp[k++]=array[i++];
}
//把剩下的元素放入临时数组中,只有一路的
while (i<=end1)
temp[k++]=array[i++];
while (j<=end2)
temp[k++]=array[j++];
k=start1;
for ( int item:temp)
array[k++]=item;
}
} |
十 各种排序总结:
本文出自 “在云端的追梦” 博客,请务必保留此出处http://computerdragon.blog.51cto.com/6235984/1161859