常见排序算法--简单排序

本文包括:

1.选择排序

2.冒泡排序/双向冒泡排序

3.插入排序

 

1.选择排序

选择排序是一种最为直观的排序方法。每次循环从数组中选择出一个最小或者最大的元素,按顺序重新放入数组中,直到所有的戴排序元素都排序完成。

public void selectSort(int[] a){
        int temp=0;
        for(int i=0;i<a.length-1;i++){
            for(int j=i+1;j<a.length;j++){
                if(a[j]<a[i]){
                    temp = a[j];
                    a[j] = a[i];
                    a[i] = temp;
                }
            }
        }
    }

从代码不难看出,选择排序的过程是:第一次循环,遍历数组找出数组中最小的数字,放入a[0],第二次循环,找出剩下数组中最小的数字放入a[1]一次类推。

所以,选择排序的时间复杂度为O(n^2),如果n较大,则效率会非常低。

 

2.冒泡排序

冒泡排序也是较为简单的一种排序方法,之所以叫冒泡排序,是因为排序的手法会使数字浮到数组顶端而得名。

冒泡排序的手法是:比较相邻的两个元素,如果相邻的两个元素的顺序是错误的,则将他们交换;然后继续比较下一组相邻的元素。直到所有需要排列的元素都排序完成。

public void bubbSort(int[] a){
        int temp=0;
        for(int i=0;i<a.length-1;i++){
            for(int j=a.length-1;j>i;j--){
                if(a[j]<a[j-1]){
                    temp = a[j];
                    a[j] = a[j-1];
                    a[j-1] = temp;
                }
            }
        }
    }

从代码我们可以看出来:冒泡排序是用层循环,外侧循环的意义是在于,循环n次,每次冒泡都冒出最小的节点依次放在数组的最前面。第二层循环的意义是在于,进行冒泡操作,每次比较相邻的两个元素,将较小的元素,像数组头方向移动。

因此我们可以看出冒泡排序的时间复杂度为O(n^2),如果n较大,则效率会非常低,如果数组是有序的,即进行一次冒泡扫描发现移动的关键次数为最小时,说明数组已经有序,此时的时间复杂度为O(n)。

 

双向冒泡排序:

传统的冒泡排序要么是从左向右进行,要么从右向左进行,每次都只对数组一头的元素进行扫描排序。

而双向冒泡排序首先从前往后把最大数移到最后,然后反过来从后往前把最小的一个数移动到数组最前面,这一过程就是第一轮,然后重复这一过程,最终就会把整个数组从小到大排列好。

public void bubbSort2(int[] a){
        int left =1 ;
        int right = a.length -1;
        int t=0;
        while(left<=right){
            for(int i=right;i>=left;i--){
                if(a[i]<a[i-1]){
                    int temp;
                    temp = a[i];
                    a[i] = a[i-1];
                    a[i-1] = temp;
                    t = i;//记录上一次交换的下标
                }
            }
            left = t+1; //t+1中间乱序部分的最左端
            for(int i=left;i<right+1;i++){
                if(a[i]<a[i-1]){
                    int temp;
                    temp = a[i];
                    a[i] = a[i-1];
                    a[i-1] = temp;
                    t = i;//记录上一次交换的下标
                }
            }
            right = t-1;//t-1为中间乱序部分的最右端
        }
    }

从代码看来,双向冒泡排序会比普通冒泡排序减少很多次循环。因为双向排序时数组的两头都排序好了,我们只需要处理数组的中间部分即可,普通冒泡排序只有一头的元素是排好序的。

虽然双向冒泡排序有些改进,但是不能大幅度的提升效率,这是由于冒泡排序的基本过程所确定的。

 

3.插入排序

插入排序的基本方法是,每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。

public void insertSort(int[] a){
        for(int i=1;i<a.length;i++){
            int temp = a[i],j=i    ;
            if(a[j-1]>temp){
                while(j>=1&&a[j-1]>temp){//找到新元素合适的位置
                    a[j] = a[j-1];//前一个覆盖后一个
                    j--;
                }
            }
            a[j]=temp; //插入元素
        }
    }

直接插入排序最好的时间复杂度为O(n),平均时间复杂度为O(n^2)。同样的,如果n过于大的时候,直接插入排序的效率会很低。

 

插入排序改进思路和冒泡排序一样,我们也可以对于直接插入排序进行改进。在直接插入排序中我们每次插入元素的时候,都是挨个遍历前面所有元素,这样遍历的效率并不高。

因为插入的数组是已经排好序的有序数组,所以我们自然而然的想到了折半插入的方法,这样可以减少比较的次数。

不过虽然折半插入会减少元素比较的次数,但因为是插入数组,所以,只是减少元素的比较次数,元素移动的个数依然没有改变,时间复杂度依然是O(n^2)。

posted @ 2015-08-10 15:30  yfsmooth  阅读(7913)  评论(0编辑  收藏  举报