您的位置:首页 > 其它

常见排序算法整理

2017-05-01 21:23 197 查看

常见排序算法整理

我们常见的排序算法主要有以下几种:

名称平均最好最坏空间稳定性
插入排序nn2n21稳定
希尔排序nnlog2nnlog2n1不稳定
快速排序nlognnlognn2logn不稳定
冒泡排序nn2n21稳定
选择排序n2n2n21不稳定
堆排序nlognnlognnlogn1不稳定
归并排序nnlognnlognn稳定
下面排序算法会用到的几个函数

/*比较两个元素大小*/
private static boolean less(Comparable v, Comparable w){
return v.compareTo(w) < 0;
}


/*交换两个元素*/
private static void exch(Comparable[] a, int i, int j){
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}


插入排序
主要思想:每次从剩余的未排序的元素中选取一个元素插入到前面已排序的元素中,使整体有序。如下图所示:

原数据:[9] [8] [7] [1] [3] [5]

第一步:选择9,只有一个元素已经排序好

[9] [8] [7] [1] [3] [5]

第二步:选择8,插入到前面已排序的元素当中

[9] [8] [7] [1] [3] [5]

[8] [9] [7] [1] [3] [5]

第三步:选择7,插入到前面已排序的元素当中

[8] [9] [7] [1] [3] [5]

[7] [8] [9] [1] [3] [5]

同理:依次从剩余的元素选取一个插入到前面已排序的元素中

/*插入排序*/
public static void Insertion(Comparable[] c){
int N = c.length;
for(int i = 1; i < N; i++){
for(int j = i; j > 0 && less(c[j], c[j-1]); j--){
exch(c, j, j-1);
}
}
}


希尔排序
主要思想:数组中任意间隔为h的元素都是有序的。h是步长,这样的数组被称为h有序数组。一个h有序数组就是h个相互独立的有序数组编织在一起组成的一个数组。

原数据:[9] [8] [7] [1] [3] [5]

第一步:设定步长为3,设 h = 3 * h + 1; // 1, 4, 13,… 步长公式有自己设定,因此第一次步长为4,每组进行的都是插入排序

输入 [9] [8] [7] [1] [3] [5]

4-sort [3] [5] [7] [1] [9] [8]

第二步:步长为1,相当于进行一次插入排序

4-sort [3] [5] [7] [1] [9] [8]

1-sort [1] [3] [5] [7] [8] [9]

/*希尔排序*/
public static void Shell(Comparable[] c){
int N = c.length;
int h = 1;
while(h < N / 3){
h = 3 * h + 1;
}
while (h >= 1){
for(int i = h; i < N; i++){
for(int j = i; j >= h && less(c[j], c[j-h]); j -= h){
exch(c, j, j-h);
}
}
h = h / 3;
}
}


快速排序
主要思想:是一种分治的思想。它将一个数组分成两个子数组,两部分独立的排序。

原数据:[9] [8] [7] [1] [3] [5]

第一步:选择哨兵9存放到临时变量tmp中,定义两个索引start, end。 start指向数组的第二个元素,end指向数组的最后一个元素。分别从前往后扫描找比tmp大的,从后往前找比tmp小的,然后交换两个元素,循环这个步骤,直到两个索引相遇,则第一次扫描结束。

[9] [8] [7] [1] [3] [5]

[5] [8] [7] [1] [3] [9]

第二步:对上一步以哨兵为分界线的两个数组分别进行上面的操作。

[5] [8] [7] [1] [3] [9]

[1] [3] [5] [7] [8] [9]

同理:直到数组有序

/*希尔排序*/
public static void Quick(Comparable[] c){
sort(c, 0, c.length-1);
}
private static void sort(Comparable[] c, int start, int end) {
if (end <= start) {
return;
}
int j = partition(c, start, end);
sort(c, start, j - 1);
sort(c, j+1, end);
}


/*切分程序*/
private static int partition(Comparable[] c, int start, int end){
int i = start, j = end + 1;
Comparable v = c[start];
while (true){
while (less(c[++i], v)){
if(i == end){
break;
}
}
while (less(v, c[--j])){
if(j == start){
break;
}
}
if(i >= j){
break;
}
exch(c, i, j);
}
exch(c, start, j);
return j;
}


冒泡排序
主要思想:依次比较两个相邻的元素,如果它们顺序错误,则交换,最终大数会沉向后面尾部。重复上面的步骤直到数组有序。

原数据:[9] [8] [7] [1] [3] [5]

第一步:依次比较,交换

[9] [8] [7] [1] [3] [5]

[8] [7] [1] [3] [5] [9]

第二步:同上

[8] [7] [1] [3] [5] [9]

[7] [1] [3] [5] [8] [9]

同理,直到数组有序

/*冒泡排序*/
public static void Bubble(Comparable[] c){
int N = c.length;
for(int i = 0; i < N-1; i++){
for(int j = 0; j < N-i-1; j++){
if(less(c[j+1], c[j])){
exch(c, j, j+1);
}
}
}
}


选择排序
主要思想:每次选择最小的一个元素与前面的元素进行交换。如下图所示:

原数据:[9] [8] [7] [1] [3] [5]

第一步:找到最小值1与最前面的9进行交换

[9] [8] [7] [1] [3] [5]

[1] [8] [7] [9] [3] [5]

第二步:在剩下的元素里面找到最小的瞳前面的8进行交换

[1] [8] [7] [9] [3] [5]

[1] [3] [7] [9] [8] [5]

同理:在剩余的元素中依次找最小的与前面的元素进行交换

/*选择排序*/
public static void Selection(Comparable[] c){
int N = c.length;
for(int i = 0; i != N; i++){
int min = i;
for(int j = i+1; j != N; j++){
if(!less(c[min], c[j])){
min = j;
}
}
exch(c, i, min);
}
}


堆排序
主要思想:建立大根堆,或者小根堆,然后每次添加新的元素之后,再调整堆使之保持大根堆或小根堆

原数据:[9] [8] [7] [1] [3] [5]

第一步:建立初始堆:

[9] [8] [7] [1] [3] [5]

[1] [3] [5] [8] [9] [7]

第二步:交换第一个元素与堆的最后一个元素,从新调整使之为小根堆

[1] [3] [5] [8] [9] [7]

[7] [3] [5] [8] [9] [1]

[3] [7] [5] [8] [9] [1]

第三步:同上

[3] [7] [5] [8] [9] [1]

[9] [7] [5] [8] [3] [1]

[5] [7] [9] [8] [3] [1]

原理同上

/*堆排序*/
public static void HeapSort(Comparable[] c){
int i;
for(i = c.length / 2 - 1; i >= 0; i--){
HeadAdjust(c, i, c.length);
}
for(i = c.length-1; i > 0; i--){
exch(c, 0, i);
HeadAdjust(c, 0, i);
}
}


/*自下而上的调整堆*/
private static void HeadAdjust(Comparable[] c, int i, int N){
int nChild;
for( ;2 * i + 1 < N; i = nChild){
nChild = 2 * i + 1;
if(nChild < N-1 && less(c[nChild], c[nChild+1])){
nChild++;
}
if(less(c[i], c[nChild])){
exch(c, i, nChild);
}else {
break;
}
}
}


归并排序
主要思想:先把数组分成多组,依次合并多个有序的组,使之称为一个大的有序的组。

/*合并两个子数组*/
public static void merge(Comparable[] c, Comparable[] cc, int start, int mid, int end){
int i = start;
int j = mid + 1;
for(int k = start; k <= end; k++){
cc[k] = c[k];
}
for(int k =start; k <= end; k++){
if(i > mid){
c[k] = cc[j++];
}else if(j > end){
c[k] = cc[i++];
}else if(less(cc[j], cc[i])){
c[k] = cc[j++];
}else{
c[k] = cc[i++];
}
}
}


/*归并排序*/
public static void MergeSort(Comparable[] c){
Comparable[] cc = new Comparable[c.length];
sort(c, cc, 0, c.length-1);
}


/*递归归并*/
private static void sort(Comparable[] c, Comparable[] cc, int start, int end){
if(end <= start){
return;
}
int mid = start + (end - start) / 2;
sort(c, cc, start, mid);
sort(c, cc, mid+1, end);
merge(c, cc, start, mid, end);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息