您的位置:首页 > 其它

插入排序、冒泡排序、选择排序与希尔排序、快速排序、归并排序

2016-04-30 22:19 746 查看
从算法时间代价考虑,分为两类

第一类:插入排序、冒泡排序、选择排序

它们比较相邻的元素,平均算法时间代价都为O(n2);

插入排序:

public class insertion_sort {

public static void insertsort(int[] unsorted){
for(int i=1;i<unsorted.length;i++){
if(unsorted[i-1]>unsorted[i]){
int temp=unsorted[i];
int j = i;
while(j>0&&unsorted[j-1]>temp){
unsorted[j]=unsorted[j-1];
j--;
}
unsorted[j]=temp;
}
}
for(int i=0;i<unsorted.length;i++){
System.out.println(unsorted[i]);
}
}

public static void main(String[] args) {
int[] x={6,2,4,1,5,9};
insertsort(x);
}
}
冒泡排序:

原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,
这样一趟过去后,最大或最小的数字被交换到了最后一位,
然后再从头开始进行两两比较交换,直到倒数第二位时结束,其余类似看例子
例子为从小到大排序,
原始待排序数组| 6 | 2 | 4 | 1 | 5 | 9 |

第一趟排序(外循环)
第一次两两比较6 > 2交换(内循环)
交换前状态| 6 | 2 | 4 | 1 | 5 | 9 |
交换后状态| 2 | 6 | 4 | 1 | 5 | 9 |

第二次两两比较,6 > 4交换
交换前状态| 2 | 6 | 4 | 1 | 5 | 9 |
交换后状态| 2 | 4 | 6 | 1 | 5 | 9 |

第三次两两比较,6 > 1交换
交换前状态| 2 | 4 | 6 | 1 | 5 | 9 |
交换后状态| 2 | 4 | 1 | 6 | 5 | 9 |

第四次两两比较,6 > 5交换
交换前状态| 2 | 4 | 1 | 6 | 5 | 9 |
交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

第五次两两比较,6 < 9不交换
交换前状态| 2 | 4 | 1 | 5 | 6 | 9 |
交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

第二趟排序(外循环)
第一次两两比较2 < 4不交换
交换前状态| 2 | 4 | 1 | 5 | 6 | 9 |
交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

第二次两两比较,4 > 1交换
交换前状态| 2 | 4 | 1 | 5 | 6 | 9 |
交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

第三次两两比较,4 < 5不交换
交换前状态| 2 | 1 | 4 | 5 | 6 | 9 |
交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

第四次两两比较,5 < 6不交换
交换前状态| 2 | 1 | 4 | 5 | 6 | 9 |
交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

第三趟排序(外循环)
第一次两两比较2 > 1交换
交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

第二次两两比较,2 < 4不交换
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

第三次两两比较,4 < 5不交换
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

第四趟排序(外循环)无交换
第五趟排序(外循环)无交换

排序完毕,输出最终结果1 2 4 5 6 9

public class bubble_sort {
public static void bubblesort(int[] unsorted){
for(int i=0;i<unsorted.length;i++){
for(int j=i;j<unsorted.length;j++){
if(unsorted[i]>unsorted[j]){
int temp=unsorted[i];
unsorted[i]=unsorted[j];
unsorted[j]=temp;
}
}
}
for(int i=0;i<unsorted.length;i++){
System.out.println(unsorted[i]);
}
}
public static void main(String[] args){
int[]x={6,2,4,1,5,9};
bubblesort(x);
}
}


选择排序:

就是直接从待排序数组里选择一个最小(或最大)的数字,每次都拿一个最小数字出来,
顺序放入新数组,直到全部拿完
再简单点,对着一群数组说,你们谁最小出列,站到最后边
然后继续对剩余的无序数组说,你们谁最小出列,站到最后边
再继续刚才的操作,一直到最后一个,继续站到最后边,现在数组有序了,从小到大
举例
先说看每步的状态变化,后边介绍细节,现有无序数组[6 2 4 1 5 9]
第一趟找到最小数1,放到最前边(与首位数字交换)
交换前:| 6 | 2 | 4 | 1 | 5 | 9 |
交换后:| 1 | 2 | 4 | 6 | 5 | 9 |
第二趟找到余下数字[2 4 6 5 9]里的最小数2,与当前数组的首位数字进行交换,实际没有交换,本来就在首位
交换前:| 1 | 2 | 4 | 6 | 5 | 9 |
交换后:| 1 | 2 | 4 | 6 | 5 | 9 |

第三趟继续找到剩余[4 6 5 9]数字里的最小数4,实际没有交换,4待首位置无须交换
第四趟从剩余的[6 5 9]里找到最小数5,与首位数字6交换位置
交换前:| 1 | 2 | 4 | 6 | 5 | 9 |
交换后:| 1 | 2 | 4 | 5 | 6 | 9 |
第五趟从剩余的[6 9]里找到最小数6,发现它待在正确的位置,没有交换
排序完毕输出正确结果[1 2 4 5 6 9]
第一趟找到最小数1的细节
当前数组是| 6 | 2 | 4 | 1 | 5 | 9 |
先把6取出来,让它扮演最小数
当前最小数6与其它数一一进行比较,发现更小数就交换角色
当前最小数6与2比较,发现更小数,交换角色,此时最小数是2,接下来2与剩余数字比较
当前最小数2与4比较,不动
当前最小数2与1比较,发现更小数,交换角色,此时最小数是1,接下来1与剩余数字比较
当前最小数1与5比较,不动
当前最小数1与9比较,不动,到达末尾
当前最小数1与当前首位数字进行位置交换,如下所示
交换前:| 6 | 2 | 4 | 1 | 5 | 9 |
交换后:| 1 | 2 | 4 | 6 | 5 | 9 |
完成一趟排序,其余步骤类似
public class selection_sort {
public static void selectionsort(int[]unsorted){
for(int i=0;i<unsorted.length;i++){
int min=unsorted[i],min_index=i;
for(int j=i;j<unsorted.length;j++){
if(unsorted[j]<min){
min=unsorted[j];
min_index=j;
}
}
if(min_index!=i){
int temp=unsorted[i];
unsorted[i]=unsorted[min_index];
unsorted[min_index]=temp;
}
}
for(int i=0;i<unsorted.length;i++){
System.out.println(unsorted[i]);
}
}
public static void main(String[] args) {
int[] x={6,2,4,1,5,9};
selectionsort(x);
}
}


希尔排序要快于前三个排序算法,而快速排序和归并排序的整个算法的时间代价为θ(nlogn)。
希尔排序:

希尔排序Shell Sort是基于插入排序的一种改进,同样分成两部分,
第一部分,希尔排序介绍
第二部分,如何选取关键字,选取关键字是希尔排序的关键
第一块希尔排序介绍
准备待排数组[6 2 4 1 5 9]
首先需要选取关键字,例如关键是3和1(第一步分成三组,第二步分成一组),那么待排数组分成了以下三个虚拟组:
[6 1]一组
[2 5]二组
[4 9]三组
看仔细啊,不是临近的两个数字分组,而是3(分成了三组)的倍数的数字分成了一组,
就是每隔3个数取一个,每隔三个再取一个,这样取出来的数字放到一组,
把它们当成一组,但不实际分组,只是当成一组来看,所以上边的"组"实际上并不存在,只是为了说明分组关系
对以上三组分别进行插入排序变成下边这样
[1 6] [2 5] [4 9]
具体过程:
[6 1]6和1交换变成[1 6]
[2 5]2与5不动还是[2 5]
[4 9]4与9不动还是[4 9]
第一趟排序状态演示:
待排数组:[6 2 4
1 5 9]
排后数组:[1 2 4
6 5 9]
第二趟关键字取的是1,即每隔一个取一个组成新数组,实际上就是只有一组啦,隔一取一就全部取出来了嘛
此时待排数组为:[1 2 4 6 5 9]
直接对它进行插入排序
[1 2 4]都不用动,过程省略,到5的时候,将5取出,在前边的有序数组里找到适合它的位置插入,就是4后边,6前边
后边的也不用改,所以排序完毕
顺序输出结果:[1 2 4 5 6 9]
第二块希尔排序的关键是如何取关键字,因为其它内容与插入排序一样
那么如何选取关键字呢?就是分成三组,一组,这个分组的依据是什么呢?为什么不是二组,六组或者其它组嘞?
好的增量序列的共同特征:
① 最后一个增量必须为1
② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况
参见 http://baike.baidu.com/view/2217047.htm

增量的取值规则为第一次取总长度的一半,第二次取一半的一半,依次累推直到1为止 http://www.cnblogs.com/huangxincheng/archive/2011/11/20/2255695.html
public class shell_sort {
public static void shellsort(int[] unsorted,int len){
int group,i,j,temp;
for(group=len/2;group>0;group/=2){
for(i=group;i<len;i++){
for(j=i-group;j>=0;j-=group){
if(unsorted[j]>unsorted[j+group]){
temp=unsorted[j];
unsorted[j]=unsorted[j+group];
unsorted[j+group]=temp;
}
}
}
}
for(i=0;i<unsorted.length;i++){
System.out.println(unsorted[i]);
}
}
public static void main(String[] args){
int[]x={6,2,4,1,5,9};
shellsort(x,x.length);
}
}


快速排序:

原理,通过一趟扫描将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
举个例子
如无序数组[6 2 4 1 5 9]
a),先把第一项[6]取出来,
用[6]依次与其余项进行比较,
如果比[6]小就放[6]前边,2 4 1 5都比[6]小,所以全部放到[6]前边
如果比[6]大就放[6]后边,9比[6]大,放到[6]后边,//6出列后大喝一声,比我小的站前边,比我大的站后边,行动吧!霸气十足~
一趟排完后变成下边这样:
排序前 6
2 4 1 5 9
排序后 2 4 1 5
6 9

b),对前半部分[2 4 1 5]继续进行快速排序
重复步骤a)后变成下边这样:
排序前 2 4 1 5
排序后 1 2 4 5
前半部分排序完成,总的排序也完成:
排序前:[6 2 4 1 5 9]
排序后:[1 2 4 5 6 9]
排序结束

public class quick_sort {
public static int partition(int[] unsorted,int low,int high){
int pivot = unsorted[low];
while(low<high){
while(low<high&&unsorted[high]>pivot)
high--;
unsorted[low]=unsorted[high];
while(low<high&&unsorted[low]<=pivot)
low++;
unsorted[high]=unsorted[low];
}
unsorted[low]=pivot;
return low;
}
public static void quicksort(int[] unsorted,int low,int high){
int loc=0;
if(low<high){
loc=partition(unsorted,low,high);
quicksort(unsorted,low,loc-1);
quicksort(unsorted,loc+1,high);
}

}
public static void main(String[] args) {
int[] x={6,2,4,1,5,9};
quicksort(x,0,x.length-1);
for(int i=0;i<x.length;i++){
System.out.println(x[i]);
}
}
}
归并排序:

原理,把原始数组分成若干子数组,对每一个子数组进行排序,
继续把子数组与子数组合并,合并后仍然有序,直到全部合并完,形成有序的数组
举例
无序数组[6 2 4 1 5 9]
先看一下每个步骤下的状态,完了再看合并细节
第一步 [6 2 4 1 5 9]原始状态
第二步 [2 6] [1 4] [5 9]两两合并排序,排序细节后边介绍
第三步 [1 2 4 6] [5 9]继续两组两组合并
第四步 [1 2 4 5 6 9]合并完毕,排序完毕
输出结果[1 2 4 5 6 9]
合并细节
详细介绍第二步到第三步的过程,其余类似
第二步:[2 6] [1 4] [5 9]
两两合并,其实仅合并[2 6] [1 4],所以[5 9]不管它,
原始状态
第一个数组[2 6]
第二个数组[1 4]
--------------------
第三个数组[...]

第1步,顺序从第一,第二个数组里取出一个数字:2和1
比较大小后将小的放入第三个数组,此时变成下边这样
第一个数组[2 6]
第二个数组[4]
--------------------
第三个数组[1]

第2步,继续刚才的步骤,顺序从第一,第二个数组里取数据,2和4,
同样的比较大小后将小的放入第三个数组,此时状态如下
第一个数组[6]
第二个数组[4]
--------------------
第三个数组[1 2]

第3步,再重复前边的步骤变成,将较小的4放入第三个数组后变成如下状态
第一个数组[6]
第二个数组[...]
--------------------
第三个数组[1 2 4]

第4步,最后将6放入,排序完毕
第一个数组[...]
第二个数组[...]
--------------------
第三个数组[1 2 4 6]

[ 1 2 4 6 ]与[ 5 9 ]的合并过程与上边一样

public class merge_sort {
public static void merge(int[] unsorted,int first,int mid,int last,int[] sorted){
int i=first,j=mid;
int k=0;
while(i<mid&&j<last){
if(unsorted[i]<unsorted[j]){
sorted[k++]=unsorted[i++];
}else{
sorted[k++]=unsorted[j++];
}
}
while(i<mid)
sorted[k++]=unsorted[i++];
while(j<last)
sorted[k++]=unsorted[j++];
for(int v=0;v<k;v++)
unsorted[first+v]=sorted[v];
}
public static void mergesort(int[] unsorted,int first,int last,int[] sorted){
if(first+1<last){
int mid=(first+last)/2;
System.out.println("{0}-{1}-{2}"+first+mid+last);
mergesort(unsorted,first,mid,sorted);
mergesort(unsorted,mid,last,sorted);
merge(unsorted,first,mid,last,sorted);

}
}
public static void main(String[] args) {
int[] x={6,2,4,1,5,9};
int[] sorted=new int[x.length];
mergesort(x,0,x.length,sorted);
for(int i=0;i<sorted.length;i++){
if(x[i]>0)
System.out.println(x[i]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: