代码改变世界

算法实践系列--查找第K大值

2011-09-15 07:23  java线程例子  阅读(386)  评论(0编辑  收藏  举报

下面的算法实现基于随机化快排,有一个前提是需要假设所有的元素都不相等,否则算法不成立。下面是具体实现:

1)随机划分算法与快排一样:

  /// <summary>
        /// 快速排序的分隔,即:对于一个指定的主元x,找到位置i,使得i的左边元素都小于等于x,右边都大于等于x.
        /// </summary>
        /// <param name="A"></param>
        /// <param name="p"></param>
        /// <param name="q"></param>
        /// <returns></returns>
        private int QuickSortPartion(int[] A, int p, int q)
        {
            count2++;
            int theCount = q - p + 1;
            //只有一个元素的情况,返回-1表示不用继续分割
            if (theCount==1)
            {
               
                return -1;
            }
            //如果元素为2,则不用继续分割,只需要简单处理即可,这可以节省一些时间,但不是必须.
            if (theCount == 2)
            {
                if (A[p] > A[q])
                {
                    int tmp = A[p];
                    A[p] = A[q];
                    A[q] = tmp;
                }
                return -1;
            }
            //随机获取主元
            Random theR=new Random(10);
            int theMasterIndex = theR.Next(1, theCount);
            int theMasterP = p + theMasterIndex -1;
            //找到主元x,并与下界元素交换。
            int theX = A[theMasterP];
            A[theMasterP] = A[p];
            A[p] = theX;
            int i = p;
            //寻找i,使得小于i位置的元素都小于等于thex,大于i位置的元素都大于thex.
            for(int j=p+1;j<=q;j++)
            {
                if (A[j] <= theX)
                {
                    i++;
                    int theTmp = A[j];
                    A[j] = A[i];
                    A[i] = theTmp;
                }
                count2++;
            }
            //将主元放到位置i.
            A[p] = A[i];
            A[i] = theX;
            return i;
        }

2)查找算法,与快排类似:

 /// <summary>
        /// 寻找序列中第K大的值.
        /// </summary>
        /// <param name="A">序列</param>
        /// <param name="S">序列开始位置</param>
        /// <param name="E">序列结束位置</param>
        /// <param name="K">查找结果条件</param>
        private int FindNOKValue(int[] A, int S, int E,int K)
        {
            count2++;
            //先找划分位置i
            int theDivI = QuickSortPartion(A, S, E);
            //不需要划分,也表示没找到.
            if (theDivI < 0)
            {
                return -1;
            }
            //查找跟快排的区别就是每次只需要进入一个分支。
            //如果划分位置刚好是K,就表示第K大值找到.
            if (theDivI == K)
            {
                return A[K];
            }
            //如果查找划分位置大于K,则进入小的划分,否则进入大的划分.
            if (theDivI > K)
            {
                int theP1_S = S, theP1_E = theDivI - 1;
                //对左边递归快排
                if (theP1_E >= S)
                {
                    return FindNOKValue(A, theP1_S, theP1_E,K);

                }
            }
            else
            {
                int theP2_S = theDivI + 1, theP2_E = E;
                //对右边递归快排.
                if (theP2_S <= theP2_E)
                {
                    return FindNOKValue(A, theP2_S, theP2_E,K);
                }
            }
            return -1;
        }