zoukankan      html  css  js  c++  java
  • 常见排序算法--简单排序

    本文包括:

    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)。

  • 相关阅读:
    14_java之变量|参数|返回值|修饰符
    NYOJ 202 红黑树 (二叉树)
    NYOJ 138 找球号(二) (哈希)
    NYOJ 136 等式 (哈希)
    NYOJ 133 子序列 (离散化)
    NYOJ 129 树的判定 (并查集)
    NYOJ 117 求逆序数 (树状数组)
    NYOJ 93 汉诺塔 (数学)
    HDU 2050 折线分割平面 (数学)
    天梯赛L2-008 最长对称子串 (字符串处理)
  • 原文地址:https://www.cnblogs.com/yfsmooth/p/4718151.html
Copyright © 2011-2022 走看看