排序总结

排序总结


排序最差时间平均时间稳定度空间
冒泡排序o(n2)o(n2)稳定o(1)
选择排序o(n2)o(n2)稳定o(1)
二叉树排序o(n2)o(nlogn)不一定o(n)
插入排序o(n2)o(n2)稳定o(1)
快速排序o(n2)o(nlogn)不稳定o(log2n)~o(n)
堆排序o(nlogn)o(nlogn)不稳定o(1)
希尔排序o(n^s) 1

冒泡排序

这种方法的基本思想是,将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮。在冒泡排序算法中我们要对这个“气泡”序列处理若干遍。自底向上检查一遍这个序列,并时刻注意两个相邻的元素的顺序是否正确。如果发现两个相邻元素的顺序不对,即“轻”的元素在下面,就交换它们的位置。显然,处理一遍之后,“最轻”的元素就浮到了最高位置;处理二遍之后,“次轻”的元素就浮到了次高位置。

public static void bubble(int[] a) {
        if (a.length <= 0) {
            return;
        }
        for (int j = 0; j < a.length; j++) {
            for (int i = a.length - 1; i > j; i--) {
                if (a[i] < a[i - 1]) {
                    swap(a, i ,i - 1);
                }
            }
        }
    }
    public static void swap(int[] a, int m, int n) {
        if (m == n) {
            return;
        }
        a[m] = a[m] + a[n];
        a[n] = a[m] - a[n];
        a[m] = a[m] - a[n];
    }

选择排序

选择排序的基本思想是对待排序的记录序列进行n-1遍的处理,第i遍处理是将L[i..n]中最小者与L[i]交换位置。这样,经过i遍处理之后,前i个记录的位置已经是正确的了。

插入排序

插入排序的基本思想是,经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得L[1..i] 又是排好序的序列。

希尔排序

一张图解释:
这里写图片描述
图来自:http://www.cnblogs.com/Ph-one/p/7307267.html

     /**
      * 希尔排序 针对有序序列在插入时采用交换法
      * @param arr
      */
     public static void sort(int []arr){
         //增量gap,并逐步缩小增量
        for(int gap=arr.length/2;gap>0;gap/=2){
            //从第gap个元素,逐个对其所在组进行直接插入排序操作
            for(int i=gap;i<arr.length;i++){
                int j = i;
                while(j-gap>=0 && arr[j]<arr[j-gap]){
                    //插入排序采用交换法
                    swap(arr,j,j-gap);
                    j-=gap;
                }
            }
        }
     }

计数排序

   public static int[] countSort(int[]a){
        int b[] = new int[a.length];
        int max = a[0], min = a[0];
        for (int i:a) {
            if (i > max) {
                max=i;
            }
            if (i < min) {
                min=i;
            }
        }//这里k的大小是要排序的数组中,元素大小的极值差+1
        int k = max - min + 1;
        int c[] = new int[k];
        for(int i = 0; i < a.length; ++i) {
            c[a[i] - min] += 1;//优化过的地方,减小了数组c的大小
        }
        for (int i = 1; i < c.length; ++i) {
            c[i] = c[i] + c[i-1];
        }
        for (int i = a.length - 1; i >= 0; --i) {
            b[--c[a[i] - min]] = a[i];//按存取的方式取出c的元素
        }
        return b;
    }

归并排序

/*
     * 归并排序,将两个(或以上)有序列表合并成一个新的有序表
     * 即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列 
     */
    public static int[] sort(int[] nums, int low, int high) { 
        if (low < high) {
            int mid = (low + high) / 2;
            sort(nums, low, mid);
            sort(nums, mid + 1, high);
            merge(nums, low, mid, high);
        }
        return nums;
    }
    public static void merge(int[] nums, int low, int mid, int high) {
        int p_left = low;
        int p_right = mid + 1;
        int p_final = low;
        int[] tmp = new int[nums.length];
        while (p_left <= mid && p_right <= high) {
            if (nums[p_left] < nums[p_right]) {
                tmp[p_final++] = nums[p_left++];
            } else {
                tmp[p_final++] = nums[p_right++];
            }
        }
        while (p_left <= mid) {
            tmp[p_final++] = nums[p_left++];
        }
        while (p_right <= high) {
            tmp[p_final++] = nums[p_right++];
        }
        for (int i = low; i <= high; i++) {
            nums[i] = tmp[i];
        }
    }
    /*
     * 简洁版
     */
    public static void mergeSort(int[] a, int[] temp, int low, int high) {
        if (low >= high) {
            return;
        }
        int mid = (low + high) / 2;
        mergeSort(a, temp, low, mid);
        mergeSort(a, temp, mid + 1, high);

        int p_left = low, p_right = mid + 1, p_final = low;

        while (p_left <= mid || p_right <= high) {
            if (p_left <= mid && (p_right > high || a[p_left] <= a[p_right])) {
                temp[p_final++] = a[p_left++];
            } else {
                temp[p_final++] = a[p_right++];
            }
        }
        for (int i = low; i <= high; i++) {
            a[i] = temp[i];
        }
    }

归并迭代版

以往使用的归并排序都是利用“分而治之”的思想递归进行,也就是不断二分到最小之后递归地归并上来
然而,再引入一个数组就可以进行迭代法的归并排序
把一个数组A里的先两两排序到另一个数组B里
再把数组B里的数据四个四个排序到A里,以此类推

    public static void mergeSort(int[] a){
        int[] tmp = new int[a.length];//用于存放归并结果
        int k=1;//起始,子序列长度为1
        while(k<a.length){
            mergePass(a, tmp, k, a.length);//将原先无序的数据两两归并入tmp
            k = 2*k;//子序列长度加倍
            mergePass(tmp, a, k, a.length);//将tmp中已经两两归并的有序序列再归并回数组a
            k = 2*k;//子序列长度加倍
        }
    }
    public static void mergePass(int[] SR, int [] TR,int s,int len){

        int i=0;
        while (i < len - 2 * s + 1) {
            merge(SR, TR, i, i + s - 1, i + 2 * s - 1);//两两归并
            i = i + 2 * s;
        }
        //处理最后的尾数
        if(i < len - s + 1) {
            merge(SR, TR, i, i + s - 1, len - 1);//归并最后两个序列
        }else {
            for (int j = i; j < len; j++) {//若最后只剩下单个子序列
                TR[j] = SR[j];
            }
        }
    }
    // merge i-(m-1) and m-n
    public static void merge(int[] s, int[] t,int i,int m,int n){
        int j,k,l;
        for(j = m + 1, k = i; i <= m && j <= n; k++){

            if(s[i] < s[j]){
                t[k] = s[i++];
            }else{
                t[k] = s[j++];
            }
        }
        if(i <= m){
            for (l = 0; l <= m-i ; l++) {
                t[k+l] = s[i+l];
            }
        }
        if(j<=n){
            for (l = 0; l <= n-j; l++) {
                t[k+l] = s[j+l];
            }
        }
    }

快排


    /*
     * 算法导论版
     */
    public void quicksort(int[] A, int p, int r) {
        if (p < r) {
            int q = partition(A, p, r);
            System.out.println("输出q" + q);
            quicksort(A, p, q - 1);
            quicksort(A, q + 1, r);
        }
    }
    //每次分区返回一个int值,保证其左全小于该值,其右全大于该值
    public int partition(int[] A, int l, int r) {
        int key = A[r]; // 保证所有i + 1左边的都比A[r]小,从i+1开始比A[r]大
        int i = l - 1;
        for (int j = l; j < r; j++) {
            if (A[j] < key) {
                i++;
                swap(A, i, j);
            }
        }
        //交换A[r]和A[i+1]
        swap(A, r, i+1);
        System.out.println("h " + Arrays.toString(A));
        return i+1;
    }
    public static void swap(int[] A, int i, int j) {
        if(i == j) return; // 注意一定要去掉!!!!
        A[i] = A[i] + A[j];
        A[j] = A[i] - A[j];
        A[i] = A[i] - A[j];
    }
    /*
     * 简洁
     * 示例:453126
     */
    public static void qSort(int[] a, int low, int high) {
        if (low >= high) return;
        int first = low, last = high, key = a[first];
        while (first < last) {
            while(first < last && a[last] >= key) 
                --last;
            a[first] = a[last];
            while(first < last && a[first] <= key) 
                ++first;
            a[last] = a[first];
        }
        a[first] = key;
        qSort(a, low, first - 1);
        qSort(a, last + 1, high);
    }

快排递归和迭代版

迭代的性能高于递归:
递归会把中间结果压到栈中,而且每次调用函数都会将参数,局部变量压栈。导致大量地消耗栈空间,而且,每次函数调用还要将下一次指令执行的位置压栈,这些上下文(Context)切换会导致不少开销,甚至会导致栈溢出。
Java的方法栈深度只有几k,而java.util的Stack是基于数组实现的。

    public static void qsort(int[] a, int s, int e) {
        if (s >= e) {
            return;
        }
        int l = s, r = e, key = a[e];
        while (l < r) {
            while (a[l] <= key && l < r) {
                l++;
            }
            while (a[r] >= key && r > l) {
                r--;
            }
            swap(a, l, r);
        }
        swap(a, l, e);
        qsort(a, s, l - 1);
        qsort(a, r + 1, e);
    }
    public static void qsortIteration(int[] a) {
        Queue<Integer> q = new ArrayDeque<Integer>();
        q.add(0);
        q.add(a.length - 1);
        while (q.size() != 0) {
            int s = q.poll();
            int e = q.poll();
            int l = s, r = e, key = a[e];
            while (l < r) {
                while (a[l] <= key && l < r) {
                    l++;
                }
                while (a[r] >= key && r > l) {
                    r--;
                }
                swap(a, l, r);
            }
            if (l < e) {
                swap(a, l, e);
                if (s != (l - 1)) {
                    q.add(s);
                    q.add(l - 1);
                }
                if ((r + 1) != e) {
                    q.add(r + 1);
                    q.add(e);
                }
            }
        }
    }
    public static void swap(int[] a, int i, int j) {
        if (i == j) {
            return;
        }
        a[i] = a[i] + a[j];
        a[j] = a[i] - a[j];
        a[i] = a[i] - a[j];
    }

堆排序

public class Main {
    public static void main(String[] args) {
        int[] data=new int[] {5,3,6,2,1,9,4,8,7,10};

        print(data);
        heapsort(data);
        System.out.println("排序后数组");
        print(data);
    }
    public static void heapsort(int[] data) {
        build(data);
        for(int i=data.length -1;i>0;i--) {
            swap(data,0,i);
            creatMax(data,i,0);
        }
    }
//建一个最大堆
    public static void build(int[] data) {
        for(int i=(data.length-2)/2;i>=0;i--){//这里i=data.length/2也行
            creatMax(data,data.length,i);
        }
    }
    // heapsize表多少个堆元素存储在数组中
// 建堆时,只需要保证第一个数为最大。所以从倒数第二行的最后一个有子节点的数开始遍历
// 排序时,从第一位开始遍历,交换最大的,再调用creatMax找到剩下的最大值,遍历从data.length-1依次减小。保证最大的放在最后。
    public static void creatMax(int[] data,int heapsize,int last) { //last=4
        int  l=last*2+1;
        int r=last*2+2;
        int largest=last;
        if(l<heapsize&&data[l]>data[last]) largest=l;
        if(r<heapsize&&data[r]>data[largest]) largest=r;
        if(largest!=last){
            swap(data,largest,last);
            creatMax(data,heapsize,largest);
        }
    }
    public static void swap(int[] data,int i,int j) {
        if(i==j) return;
        data[i]=data[i]+data[j];
        data[j]=data[i]-data[j];
        data[i]=data[i]-data[j];
    }
    //打印方法
    public static void print(int[] data) {
        for(int i=0;i<data.length;i++) {
            System.out.print(data[i]+" ");
            }
            System.out.println();
    }
}

整数数组,输出所有可能的子集(整数可能有重复)
递归和迭代

递归
public static void main(String[] args) {
        int[] a = {1,2,3,5};
        List<List<Integer>> res =  new ArrayList<List<Integer>>();
        List<Integer> tmp = new ArrayList<Integer>();
        helper(a, 0, res, tmp);
        System.out.println(res);
    }
    public static void helper(int[] a, int level, List<List<Integer>> res, List<Integer> tmp) {
        if (level >= a.length) {
            return;
        }
        for (int i = level; i< a.length; i++,level++) {
            tmp.add(a[i]);
            res.add(new ArrayList<Integer>(tmp));
            helper(a, level + 1, res, tmp);
            tmp.remove(tmp.size() - 1);
        }
    }
迭代
    public static void main(String[] args) {
        int[] a = {1,2,3,5};
        List<List<Integer>> res =  new ArrayList<List<Integer>>();
        List<Integer> tmp = new ArrayList<Integer>();
        helper(a,res, tmp);
        System.out.println(res);
    }
    public static void helper(int[] a,List<List<Integer>> res, List<Integer> tmp) {
        for (int i = 0; i < a.length; i++) {
            List<List<Integer>> re = new ArrayList<List<Integer>>();
            tmp = new ArrayList<Integer>();
            tmp.add(a[i]);
            re.add(new ArrayList<Integer>(tmp));
            for (int j = i+1; j< a.length; j++) {
                List<List<Integer>> toAdd = new ArrayList<List<Integer>>();
                for (List<Integer> l : re) {
                    List<Integer> ll = new ArrayList<Integer>(l);
                    ll.add(a[j]);
                    toAdd.add(new ArrayList<Integer>(ll));
                }
                re.addAll(toAdd);
            }
            res.addAll(re);
        }
    }

第k大值


    public static int helper(int[] nums, int k) {
        if (k < 1 || nums == null || nums.length == 0) {
            return 0;
        }
        return getK(nums, nums.length - k + 1, 0, nums.length - 1);
    }
    public static int getK(int[] nums,int k, int begin, int end) {
        int p = nums[end];
        int l = begin;
        int r = end;
        while (true) {

            while (nums[l] < p && l < r) {
                l++;
            }

            while (nums[r] >= p && r > l) {
                r--;
            }

            if (l == r) {
                break;
            }
            swap(nums, l, r);
        }
        swap(nums, l, end);
        if (k == l + 1) {
            return p;
        } else if (k < l + 1) {
            return getK(nums, k, begin, l - 1);
        } else {
            return getK(nums, k, l + 1, end);
        }
    }
    public static void swap(int[] nums, int a, int b) {
        int tmp = nums[a];
        nums[a] = nums[b];
        nums[b] = tmp;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值