排序法 | 平均时间 | 最差情形 | 稳定度 | 额外空间 | 备注 |
冒泡 | O(n2) | O(n2) | 稳定 | O(1) | n小时较好 |
选择 | O(n2) | O(n2) | 不稳定 | O(1) | n小时较好 |
插入 | O(n2) | O(n2) | 稳定 | O(1) | 大部分已排序时较好 |
基数 | O(logrd) | O(logrd) | 稳定 | O(n) | d是关键字项数(0-9), r是基数(个十百) |
快速 | O(nlogn) | O(n2) | 不稳定 | O(nlogn) | n大时较好 |
归并 | O(nlogn) | O(nlogn) | 稳定 | O(1) | n大时较好 |
堆 | O(nlogn) | O(nlogn) | 不稳定 | O(1) | n大时较好 |
希尔 |
|
|
|
|
|
1. 冒泡排序
冒泡排序是最慢的排序算法.在实际运用中它是效率最低的算法.
a) 原理:将序列划分无序和有序区,不断通过交换较大元素至无序区尾完成排序.
b) 要点:在要排序的一组数中,对当前还没有排好序的范围内的全部的数,自上而下对相邻两个数依次进行比较和调整,让较大的数据往下沉,较小的数网上冒.即: 每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换. 设计交换判断条件,提前结束以排好序的序列循环。
publicclass Sort {
publicstaticvoid main(String[]args) {
int[] arraySort ={77,55,22,88,11,99,66,44,33};
//排序前
System.out.print("排序前:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
/**
* 冒泡排序
* 思路:是将最小的数据项放在数组的最开始(数组下标为0),并将最大的数据项放在数组的最后(数组下标为nElems-1).
* 外层for循环的计数器out从数组的最后开始,即out等于nElems-1,没经过一次循环out减一.
* 下标大于out的数据项都已经是排好序的.变量out在没完成一次内部循环后就左移一位,因此算法就不在处理那些已经排好序的数据了.
* 内层for循环计数器in从数组的最开始算起,即in=0,没完成一次内部循环体加一,当它等于out时结束一次循环.在内层for循环中,
* 数组下标为in和in+1的两个数据项做比较,如果下标为in的数据项大于下标为in+1的数据项,则交换两个数据项.
*/
int out,in;
for(out = arraySort.length-1; out > 0;out--){
for(in = 0; in <out; in++){
if(arraySort[in] >arraySort[out]){
int temp;
temp= arraySort[in];
arraySort[in]= arraySort[out];
arraySort[out]= temp;
}
}
}
//排序后
System.out.print("排序后:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
}
}
2. 选择排序
原理: 将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序.
描述: 在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
publicclass Sort {
publicstaticvoid main(String[]args) {
int[] arraySort ={77,55,22,88,11,99,66,44,33};
//排序前
System.out.print("排序前:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
/**
* 选择排序
* 外层循环用循环变量out,从数组开头开始(数组下标为0)向高位增长
* 内层循环用循环变量in,从out所指位置开始,同样是向右移动.
* 在每一个in的新位置,数据项a[in]和a[min]进行比较.如果a[in]更小,则min被赋值为in的值.
* 在内层循环的最后,min指向最小的数据项,然后交换out和min指向的数组的数据项.
*/
int out;
int in;
int min;
for(out = 0; out <arraySort.length; out++){
min =out;
for(in = out +1; in< arraySort.length; in++){
if(arraySort[in] <arraySort[min]){
min= in;
}
int temp =arraySort[out];
arraySort[out]= arraySort[min];
arraySort[min]= temp;
}
}
//排序后
System.out.print("排序后:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
}
}
3. 插入排序
原理:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。
要点:设立哨兵,作为临时存储和判断数组边界之用。
publicclass Sort {
publicstaticvoid main(String[]args) {
int[] arraySort ={77,55,22,88,11,99,66,44,33};
//排序前
System.out.print("排序前:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
/**
* 插入排序
* 在外层的for循环中,out变量从1开始,向右移动.它标记了未排序部分的最左端的数据.
* 在内层的while循环中,in变量从out变量开始,向左移动,知道temp变量小于in所指的数组数据项,或者它已经不能再往左移动为止.
* while循环的每一趟都向移动了一个已排序的数据项.
*/
int out;
int in;
for(out = 1; out <arraySort.length; out++){
int temp =arraySort[out];
in = out;
while(in > 0&& arraySort[in - 1] >= temp){
arraySort[in]= arraySort[in-1];
--in;
}
arraySort[in]= temp;
}
//排序后
System.out.print("排序后:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
}
}
4. 归并排序
归并排序比堆排序稍微快一点,但是需要比堆排序多一倍的内存空间,因为它需要一个额外的数组
publicclass MergeApp {
publicstaticvoid main(String[] args) {
int[] arrayA = {23,47,85,98};
int[] arrayB = {7,14,35,26,56,74};
int[] arrayC =newint[10];
merge(arrayA,4,arrayB,6,arrayC);
display(arrayC, 10);
}
publicstaticvoid merge(int[] arrayA,int sizeA,int[] arrayB,int sizeB,int[] arrayC){
int aDex = 0;
int bDex = 0;
int cDex = 0;
/**
* 沿着数组arrayA和数组arrayB走,比较他们的数据项,并且复制他们中最小的数据项到数组arrayC中.
*/
while(aDex < sizeA && bDex < sizeB){
if(arrayA[aDex] < arrayB[bDex]){
arrayC[cDex++] = arrayA[aDex++];
}else{
arrayC[cDex++] = arrayB[bDex++];
}
}
/**
* 当数组arrayB中所有的数据项全部移除,而数组arrayA还有剩余的数据项的情况.
* 这个循环把剩余的数据项直接从数组arrayA中复制到数组arrayC中.
*/
while(aDex < sizeA){
arrayC[cDex++] = arrayA[aDex++];
}
/**
* 当数组arrayA中所有的数据项全部移除,而数组arrayB还有剩余的数据项的情况.
* 这个循环把剩余的数据项直接从数组arrayB中复制到数组arrayC中.
*/
while(bDex < sizeB){
arrayC[cDex++] =arrayB[bDex++];
}
}
publicstaticvoid display(int[] theArray,int size){
for(int i = 0; i <size; i++){
System.out.println(theArray[i]);
}
}
}
5. 快速排序
原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想.
快速排序是一个就地排序,分而治之,大规模递归的算法。从本质上来说,它是归并排序的就地版本。快速排序可以由下面四步组成。
(1) 如果不多于1个数据,直接返回。
(2) 一般选择序列最左边的值作为支点数据。即temp=a[0];
(3) 将序列分成2部分,一部分都大于支点数据,另外一部分都小于支点数据。
(4) 对两边利用递归排序数列。
快速排序比大部分排序算法都要快。尽管我们可以在某些特殊的情况下写出比快速排序快的算法,但是就通常情况而言,没有比它更快的了。快速排序是递归的,对于内存非常有限的机器来说,它不是一个好的选择。
publicclass Sort {
staticvoid quick_sort(int s[], int l,int r){
if (l < r){
int i = l, j = r, temp = s[l];
while (i < j){
//从右向左找第一个小于temp的数
while(i < j && s[j] >= temp){
j--;
}
if(i < j){
s[i++] = s[j];
}
//从左向右找第一个大于等于temp的数
while(i < j && s[i] < temp){
i++;
}
if(i < j){
s[j--] = s[i];
}
}
s[i] = temp;
if(i - l > 1){
//递归调用,把temp前面的数据项完成排序
quick_sort(s, l, i - 1);
}
if(r - j > 1){
//递归调用,把temp后面的数据项完成排序
quick_sort(s, i + 1, r);
}
}
}
publicstaticvoid main(String[]args) {
int[] arraySort ={77,55,22,88,11,99,66,44,33};
//排序前
System.out.print("排序前:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
quick_sort(arraySort,0,arraySort.length-1);
//排序后
System.out.print("排序后:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
}
}
6. 基数排序
原理:将数字按位数划分出n个关键字,每次针对一个关键字进行排序,然后针对排序后的序列进行下一个关键字的排序,循环至所有关键字都使用过则排序完成。
要点:对关键字的选取,元素分配收集。
基数排序和通常的排序算法并不走同样的路线。它是一种比较新颖的算法,但是它只能用于整数的排序,如果我们要把同样的办法运用到浮点数上,我们必须了解浮点数的存储格式,并通过特殊的方式将浮点数映射到整数上,然后再映射回去,这是非常麻烦的事情,因此,它的使用同样也不多。而且,最重要的是,这样算法也需要较多的存储空间。
publicclass Sort {
publicstaticvoid main(String[]args) {
int[] arraySort ={77,55,22,88,11,99,66,44,33};
//排序前
System.out.print("排序前:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+"");
}
arraySort = radixSort(arraySort);
System.out.println();
//排序后
System.out.print("排序后:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+"");
}
}
publicstaticint[] radixSort(int[] a)
{
int[] b =newint[a.length];
for(int i=0; i<a.length; i++)
b[i] =a[i];
for(int i=1; i<=a.length; i++)
b = countSort(b,i);
return b;
}
publicstaticint[] countSort(int[] a, int k)
{
int[] b =newint[a.length];
int[] c =newint[10];
for(int i=0; i<b.length; i++)
b[i] =0;
for(int i=0; i<c.length; i++)
c[i] =0;
int s = 1;
for(int i=0; i<k;i++)
s = s *10;
int temp1 = 0;
for(int i=0; i<a.length; i++)
{
temp1 =a[i]%s;
temp1 =temp1 * 10 / s;
c[temp1] = c[temp1] + 1;
}
for(int i=1; i<c.length; i++)
c[i] =c[i] + c[i-1];
int temp2 = 0;
for(int i=a.length-1; i>=0;i--)
{
temp1 =a[i];
temp2 =a[i]%s;
temp2 =temp2 * 10 / s;
b[c[temp2]-1] = temp1;
c[temp2] = c[temp2] - 1;
}
return b;
}
}
7. 希尔排序
原理:又称增量缩小排序。先将序列按增量划分为元素个数相同的若干组,使用直接插入排序法进行排序,然后不断缩小增量直至为1,最后使用直接插入排序完成排序。
要点:增量的选择以及排序最终以1为增量进行排序结束。
希尔排序基于插入排序,通过加大排序中元素之间的间隔,并在这些间隔的元素进行插入排序,从而使数据项能大跨度地移动.
publicclass Sort {
publicstaticvoid main(String[]args) {
int[] arraySort ={77,55,22,88,11,99,66,44,33};
//排序前
System.out.print("排序前:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
int inner;
int outer;
int temp;
inth = 1;
while(h <= arraySort.length/3){
h =h * 3 + 1;
}
while(h > 0){
for(outer =h; outer < arraySort.length; outer++){
temp =arraySort[outer];
inner= outer;
while(inner >h-1 &&arraySort[inner-h]>= temp){
arraySort[inner]= arraySort[inner-h];
inner-= h;
}
arraySort[inner]= temp;
}
h = (h-1)/3;
}
//排序后
System.out.print("排序后:");
for(int i = 0; i <arraySort.length; i++){
System.out.print(arraySort[i]+",");
}
}
}
8. 堆排序