乱序不重复整数数组求中位数

今天去面试遇到一道算法题,40亿整数乱序不重复的情况下,如何取它的中位数,要求时间复杂度为O(n)。
首先想到的是快排加二分查找的思想,取一个数进行partition之后确定它的绝对位置,就可以放弃少的一边的比较。
搜了一下发现有个QuickSelect算法,也一起放进来对比了。
最后仔细看了一下,QuickSelect算法其实就是快排加二分。。。一样的思路。
最后还有一种是用数组的,不过如果能用bitmap可以省下很多内存。同学说时间复杂度也是O(n),但是可能因为语言的关系,往数组存1花了很多时间。代码贴一下吧:

package cn.springmvc.test;

import java.util.Arrays;
import java.util.HashSet;

public class UserTest {


    /**
     * @param args
     */
    public static void main(String args[]) { 
        HashSet hashSet = new HashSet();
        int maxSize = 4000000;
        int random  = 10000000;
        while(hashSet.size()int x=(int)(Math.random() * random);
            hashSet.add(x);
        }
        int[] arr = new int[maxSize];
        int[] arr2 = new int[maxSize];
        int[] arr3 = new int[maxSize];
        int[] arr4 = new int[maxSize];
        int max = 0;
        Integer[] a =hashSet.toArray(new Integer[0]);

        int aLength = a.length;
        for(int i=0;i//数组算法
        long before0 = System.currentTimeMillis();
        for(int i=0;iif(maxint[] arr5 = new int[max+1];
        for(int i=0;i1;
        }
        int counter = 0;
        int ii=0;
        for(int i=0;iif(counter==aLength/2)break;
        }
        System.out.println(System.currentTimeMillis()-before0);
        System.out.println(ii);

        //QuickSelect
        long before = System.currentTimeMillis();
        int rs = quick_select(arr,maxSize);
        System.out.println(System.currentTimeMillis()-before);
        System.out.println(rs);

        //快排加二分
        long before3 = System.currentTimeMillis();
        quick_sort1(arr3,0,maxSize-1,(maxSize-1)/2);
        System.out.println(System.currentTimeMillis()-before3);
        System.out.println(arr3[(maxSize-1)/2]);

        //Arrays快排
        long before2 = System.currentTimeMillis();
        Arrays.sort(arr2);
        System.out.println(System.currentTimeMillis()-before2);
        System.out.println(arr2[maxSize/2-1]);

        //普通快排
        long before4 = System.currentTimeMillis();
        quick_sort(arr4,0,maxSize-1);
        System.out.println(System.currentTimeMillis()-before4);
        System.out.println(arr4[(maxSize-1)/2]);
    } 

    public static int quick_select(int[] arr,int n){
        int low, high;
        int median;
        int middle, ll, hh;

        low = 0 ; high = n-1 ; median = (low + high) / 2;
        for (;;) {
            if (high <= low) /* One element only */
                return arr[median];

            if (high == low + 1) {  /* Two elements only */
                if (arr[low] > arr[high])
                    ELEM_SWAP(arr, low,high) ;
                return arr[median] ;
            }

        /* Find median of low, middle and high items; swap into position low */
        middle = (low + high) / 2;
        if (arr[middle] > arr[high])    ELEM_SWAP(arr, middle,high) ;
        if (arr[low] > arr[high])       ELEM_SWAP(arr, low,high) ;
        if (arr[middle] > arr[low])     ELEM_SWAP(arr,middle, low) ;

        /* Swap low item (now in position middle) into position (low+1) */
        ELEM_SWAP(arr,middle, low+1) ;

        /* Nibble from each end towards middle, swapping items when stuck */
        ll = low + 1;
        hh = high;
        for (;;) {
            do ll++; while (arr[low] > arr[ll]) ;
            do hh--; while (arr[hh]  > arr[low]) ;

            if (hh < ll)
            break;

            ELEM_SWAP(arr,ll, hh) ;
        }

        /* Swap middle item (in position low) back into correct position */
        ELEM_SWAP(arr,low, hh) ;

        /* Re-set active partition */
        if (hh <= median)
            low = ll;
            if (hh >= median)
            high = hh - 1;
        }
    }
    public static void ELEM_SWAP(int[] arr,int a, int b){
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }


    static int AdjustArray(int s[], int l, int r) //返回调整后基准数的位置  
    {  
        int i = l, j = r;  
        int x = s[l]; //s[l]即s[i]就是第一个坑  
        while (i < j)  
        {  
            // 从右向左找小于x的数来填s[i]  
            while(i < j && s[j] >= x)   
                j--;    
            if(i < j)   
            {  
                s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑  
                i++;  
            }  

            // 从左向右找大于或等于x的数来填s[j]  
            while(i < j && s[i] < x)  
                i++;    
            if(i < j)   
            {  
                s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑  
                j--;  
            }  
        }  
        //退出时,i等于j。将x填到这个坑中。  
        s[i] = x;  

        return i;  
    }

    static void quick_sort1(int s[], int l, int r,int middle)  
    {  
        if (l < r)
        {  
            int i = AdjustArray(s, l, r);//先成挖坑填数法调整s[]  
            if(i>middle){
            quick_sort1(s, l, i - 1,middle); // 递归调用   
            }else if(i1, r,middle);  
            }else return;
        }  
    }

    static void quick_sort(int s[], int l, int r)  
    {  
        if (l < r)  
        {  
            //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1  
            int i = l, j = r, x = s[l];  
            while (i < j)  
            {  
                while(i < j && s[j] >= x) // 从右向左找第一个小于x的数  
                    j--;    
                if(i < j)   
                    s[i++] = s[j];  

                while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数  
                    i++;    
                if(i < j)   
                    s[j--] = s[i];  
            }  
            s[i] = x;  
            quick_sort(s, l, i - 1); // 递归调用   
            quick_sort(s, i + 1, r);  
        }  
    }  
}

结果是快排加二分的速度跟QuickSelect的速度基本是一样的。不知道有没有更快的方法?

参考
- http://codepad.org/pQsNnpqd
- http://blog.csdn.net/morewindows/article/details/6684558

你可能感兴趣的:(算法)