数组排序(冒泡、选择、插入、快排、希尔、桶排序、堆排序)

1、冒泡排序
它是一种较简单的排序算法。它会遍历若干次要排序的数列,每次遍历时,它都会从前往后依次的比较相邻两个数的大小;如果前者比后者大,则交换它们的位置。这样,一次遍历之后,最大的元素就在数列的末尾! 采用相同的方法再次遍历时,第二大的元素就被排列在最大元素之前。重复此操作,直到整个数列都有序为止.
冒泡排序的时间复杂度是O(N2),是算法稳定的。
算法稳定性 – 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

public static void bubbleSort1(int[]a,int n){
        int i,j;
        for(i=n-1;i>0;i--){
            for(j=0;j<i;j++){
                //交换大小,使得大的后移
                if(a[j]>a[j+1]){
                    int temp=a[j];
                    a[j]=a[j+1];
                    a[j+1]=temp;
                }
            }
        }

    }

copy:[http://www.cnblogs.com/skywang12345/p/3596232.html]
2、选择排序
选择排序是在未排序的数列中找到最小(or最大)元素,然后将其存放到数列的起始位置;接着,再从剩余未排序的元素中继续寻找最小(or最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
时间复杂度是O(n*n),算法是稳定的

public static void selectSort1(int []a,int n){
        int i;
        int j;
        int min;
        for(i=0;i<n;i++){
            min=i;
            // 找出"a[i+1] ... a[n]"之间的最小元素,并赋值给min
            for(j=i+1;j<n;j++){
                if(a[j]<a[min]){
                    min=j;
                }
            }
             // 若min!=i,则交换 a[i] 和 a[min]。
             // 交换之后,保证了a[0] ... a[i] 之间的元素是有序的。
            if(min!=i){
                int temp=a[i];
                a[i]=a[min];
                a[min]=temp;
                }
        }
    }

转载这里写链接内容
3、直接插入排序
直接插入排序(Straight Insertion Sort)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表。开始时有序表中只包含1个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。
时间复杂度是O(n*n),算法是稳定的

public static void inserSort1(int []a,int n){
        int i,j,k;
        for(i=1;i<n;i++){
        //为a[i]在前面的a[0...i-1]有序区间中找一个合适的位置
            for(j=i-1;j>=0;j--){
                if(a[j]<a[i])
                    break;
            }
            //如找到了一个合适的位置
            if(j!=i-1){
             //将比a[i]大的数据向后移
                int temp=a[i];
                for(k=i-1;k>j;k--){ 
                    a[k+1]=a[k];
                }
                //将a[i]放到正确位置上
                a[k+1]=temp;
            }
        }
    }

转载:http://www.cnblogs.com/skywang12345/p/3596881.html
4、快速排序
快速排序(Quick Sort)使用分治法策略:
它的基本思想是:选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

快速排序流程:
(1) 从数列中挑出一个基准值。
(2) 将所有比基准值小的摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边);在这个分区退出之后,该基准就处于数列的中间位置。
(3) 递归地把”基准值前面的子数列”和”基准值后面的子数列”进行排序。
快速排序的最坏的时间复杂度是O(n*n),平均时间复杂度是O(n*lgn)
快排是不稳定的

public static void quickSort(int []a,int l,int r){
        /**a是待排序数组
        l是数组的左边界
        r是数组的右边界a.length-1
        **/
        if(l<r){
            int i,j,x;
             i=l;
             j=r;
             x=a[i];
             while(i<j){
                 while(i<j&&a[j]>x)
                     j--;//从右像左找第一个小于x的数
                 if(i<j)
                     a[i++]=a[j];
                 while(i<j&&a[i]<x)
                     i++;//从左向右找第一个大于x的数
                 if(i<j)
                     a[j--]=a[i];
             }
             a[i]=x;
             quickSort(a,l,i-1);//递归调用
             quickSort(a,i+1,r);

        }

        }

转载于:http://www.cnblogs.com/skywang12345/p/3596746.html
5、希尔排序

6、堆排序
1、初始化堆,将数列a[1,2,3,…,n]构造成最大堆
2、交换数据:将a[1]和a[n]交换,使a[n]是a[1,…,n]中最大值;然后将a[1,…,n-1]重新调整为最大堆中的最大值;然后将a[1,…,n-2]重新调整为最大值,以此类推,知道整个数列都是有序的。

public class HeapSort {
    public static void maxHeapDown(int [] a,int start,int end){
        int c=start;
        int l=2*c+1;
        int tmp=a[c];
        for(;l<=end;c=l,l=2*l+1){
            if(l<end&&a[l]<a[l+1])
                l++;
            if(tmp>=a[l])
                break;
            else {
                a[c]=a[l];
                a[l]=tmp;
            }
        }
    }
    /**
     * 堆排序
     * @param a 带排序的数组
     * @param n 数组的长度
     */
    public static void heapSortAsc(int [] a,int n){
        int tmp;
        // // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
        for(int i=n/2-1;i>=0;i--){
            maxHeapDown(a, i, n-1);
        }
        //把最大的值移动到最后一个节点,然后再重新就行堆排序
        for(int i=n-1;i>0;i--){
        tmp=a[0];
        a[0]=a[i];
        a[i]=tmp;
        maxHeapDown(a, 0, i-1);
        }
    }

    public static void main(String[] args) {
        int a[] = {20,30,90,40,70,110,60,10,100,50,80};
        heapSortAsc(a,a.length);
        for(int i=0;i<a.length;i++)
            System.out.println(a[i]);
    }

}

7、归并排序
将两个的有序数列合并成一个有序数列,我们称之为”归并”。
归并排序(Merge Sort)就是利用归并思想对数列进行排序。根据具体的实现,归并排序包括**”从上往下”和”从下往上”**2种方式。

1. 从下往上的归并排序:将待排序的数列分成若干个长度为1的子数列,然后将这些数列两两合并;得到若干个长度为2的有序数列,再将这些数列两两合并;得到若干个长度为4的有序数列,再将它们两两合并;直接合并成一个数列为止。这样就得到了我们想要的排序结果。(参考下面的图片)

2. 从上往下的归并排序:它与”从下往上”在排序上是反方向的。它基本包括3步:
① 分解 – 将当前区间一分为二,即求分裂点 mid = (low + high)/2;
② 求解 – 递归地对两个子区间a[low…mid] 和 a[mid+1…high]进行归并排序。递归的终结条件是子区间长度为1。
③ 合并 – 将已排序的两个子区间a[low…mid]和 a[mid+1…high]归并为一个有序的区间a[low…high]。
归并排序的时间复杂度是O(N*lgN),归并排序稳定性

public static int[] mergeSort(int []A,int n){
        //从上往下合并的方式,先拆分,再合并
        if(A==null||n<2) return A;
        process(A,0,n-1);
        return A;
    }
    private static void process(int []arr,int left,int right){
        if(left==right)return;
        int mid=(right-left)/2+left;
        process(arr, left, mid);
        process(arr, left+1, right);
        merge(arr,left,mid,right);
    }
    private static void merge(int[]arr,int left,int mid,int right){
        int []tmp=new int[right-left+1];
        int i=left;//第一个有序区的索引
        int j=mid+1;//第2个有序区的索引
        int k=0;//临时区域的索引
        while(i<=mid&&j<=right){
            if(arr[i]<=arr[j])
                tmp[k++]=arr[i++];
            else {
                tmp[k++]=arr[j++];
            }
        }
        while(i<=mid)
            tmp[k++]=arr[i++];
        while(j<=right)
            tmp[k++]=arr[j++];
        for(i=0;i<k;i++)
            arr[left+i]=tmp[i];
        tmp=null;
    }

8、桶排序
9、基数排序
基数排序是桶排序的扩展,将整数切割成不同的数字,然后按每个位数分别比较。具体方法:将所有带比较数值统一为同样的数位长度,数位较短的数前面补零,然后,从最低位开始,一次进行一次排序。这样就从最低为排序一直到最高为排序,数列就编程一个有序序列。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值