【问题标题】:median of median implementation中位数实施的中位数
【发布时间】:2012-03-29 19:30:57
【问题描述】:

这里是通过将数组分成5组来实现中位数的伪代码

select(int A[],int first, int last, int i) {
    n = last - first + 1; /* n is the number elements to select from */
    if (i > n) {return ERROR;} /* there is no ith smallest element */
    if( n < = 100 ) {
        /********************* For Small n *********************/
        Run selection on A[first..last] taking at most n(n-1)/2 < 50n comparisons;
        swap A[first+i-1] with A[first] /* put ith smallest in A[first] */
    }
    else /* n > 100 */ {
        /********** main recursion *************************/
        numGroups = n / 5; /* integer division, round down */
        for group = 0 to numGroups-1 do {
            shift = group*5;
            /* A[first+shift] is the start of the group, A[first+shift+4] is end of group */
            find median of A[first+shift .. first+shift+4] and swap it into A[first + group];
        } /* for group */;
        lastMedian = first+numGroups-1;
        /* now the medians of the numGroups groups are all A[first .. lastMedian] */
        /****** the first recursive call to find median of medians ******/
        select(A, first, lastMedian, numGroups/2);
        /* now median of medians is in slot A[first] */
        /*********** partition array *********************/
        k = partition(A,first, last); /* See partition on page 146 of text */
        /* now k is the index where the median of median winds up, the smaller elements */
        /* will be in A[first..k-1] and larger elements will be in A[k+1..last] */
        /************ where is the ith smallest element? ********/
        if (k == first + i -1) {
            /* ith smallest is the median of medians in A[k] */
            swap A[k] and A[first] and return
        } else if (k > = first + i -1) {
            /* second recursion to find ith smallest among the "small" keys in A[first..k-1] */
            select(A, first, k-1, i);
        } else /* k < first + i -1 */ {
            /* second recursion to find the proper element among the "large" keys */
            numSmaller = k-first+1; /* the number of "smaller" keys not recursed on */
            newi = i - numSmaller;
            /* the ith smallest of A[first..last] is the newi smallest of A[k+1..last] */
            select(A, k+1, last, newi);
            /* ith smallest now in A[k+1], put it in A[first] */
            swap A[k+1] and A[first];
        } /* if k - second else */
    } /* if n - else part */
} /*select */

我有两个问题:

  1. 第一个与分区代码有关,这里我们只给出数组及其边界,没有指示枢轴元素,那么这个分区代码应该是什么样子?我们应该选择枢轴索引和枢轴元素为:

    int pivotindex=(end-begin)/2
    int pivot values=a[pivotindex];
    

    还是随机选择?

  2. 如何输出选中的中位数?

通常语言无关紧要,但如果示例能用 C++ 显示就更好了。

【问题讨论】:

  • 谁看到了投反对票的理由?
  • 不是我,但我理解反对意见,您粘贴了一大段代码(尽管注释丰富),但实际上并没有说明 select 函数本身应该做什么。 “中位数三的中位数”到底是什么?
  • 没有中位数,没有三个地方写了这个名字,我弄错了
  • 您应该说明要解决的问题,并且当您可以访问您的笔记和教科书来解决任务时,其他人则没有,因此 参见第 146 页上的分区几乎没用。如果这是家庭作业,你应该这样标记它。您基本上是在要求人们在没有任何上下文信息的情况下为您解决作业,这是拒绝投票的一个很好的理由。由于缺乏答案,只是太多不需要的信息难以消化,以及缺乏重要信息。你应该真正解决这个问题,而不是把它扔在这里。
  • 如伪代码所述,第一个问题的答案在教科书的第 146 页。只需谷歌搜索“参见第 146 页上的分区”即可提供 C++ 和 java 解决方案。

标签: algorithm median-of-medians


【解决方案1】:

select 代码分别放置中位数。稍后将所需的i-th 最小元素放入数组的first 槽中,因此分区的枢轴,中位数的中位数,在A[first] 中(最后,那将是A[0]) .所以要输出,请阅读这个位置。

伪代码到可编译代码的翻译很简单,因为伪代码非常详细。唯一不明显的部分是 n &lt;= 100 分支的代码、分区和中位数 5 的查找。对于 n &lt;= 100 分支,最简单的方法是使用与 @ 相同的 partition 函数进行快速排序987654329@。要找到五个元素的中位数,可以使用简单的排序算法,例如冒泡排序、插入排序、香槟排序。

自己尝试翻译,如果您有具体的困难,我们很乐意为您提供帮助。

【讨论】:

    【解决方案2】:

    可以在此处找到用于查找 n 中第 k 个最大整数的中位数算法的说明: http://cs.indstate.edu/~spitla/presentation.pdf

    c++实现如下:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    int findMedian(vector<int> vec){
    //    Find median of a vector
        int median;
        size_t size = vec.size();
        median = vec[(size/2)];
        return median;
    }
    
    int findMedianOfMedians(vector<vector<int> > values){
        vector<int> medians;
    
        for (int i = 0; i < values.size(); i++) {
            int m = findMedian(values[i]);
            medians.push_back(m);
        }
    
        return findMedian(medians);
    }
    
    void selectionByMedianOfMedians(const vector<int> values, int k){
    //    Divide the list into n/5 lists of 5 elements each
        vector<vector<int> > vec2D;
    
        int count = 0;
        while (count != values.size()) {
            int countRow = 0;
            vector<int> row;
    
            while ((countRow < 5) && (count < values.size())) {
                row.push_back(values[count]);
                count++;
                countRow++;
            }
            vec2D.push_back(row);
        }
    
        cout<<endl<<endl<<"Printing 2D vector : "<<endl;
        for (int i = 0; i < vec2D.size(); i++) {
            for (int j = 0; j < vec2D[i].size(); j++) {
                cout<<vec2D[i][j]<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    
    //    Calculating a new pivot for making splits
        int m = findMedianOfMedians(vec2D);
        cout<<"Median of medians is : "<<m<<endl;
    
    //    Partition the list into unique elements larger than 'm' (call this sublist L1) and
    //    those smaller them 'm' (call this sublist L2)
        vector<int> L1, L2;
    
        for (int i = 0; i < vec2D.size(); i++) {
            for (int j = 0; j < vec2D[i].size(); j++) {
                if (vec2D[i][j] > m) {
                    L1.push_back(vec2D[i][j]);
                }else if (vec2D[i][j] < m){
                    L2.push_back(vec2D[i][j]);
                }
            }
        }
    
    //    Checking the splits as per the new pivot 'm'
        cout<<endl<<"Printing L1 : "<<endl;
        for (int i = 0; i < L1.size(); i++) {
            cout<<L1[i]<<" ";
        }
    
        cout<<endl<<endl<<"Printing L2 : "<<endl;
        for (int i = 0; i < L2.size(); i++) {
            cout<<L2[i]<<" ";
        }
    
    //    Recursive calls
        if ((k - 1) == L1.size()) {
            cout<<endl<<endl<<"Answer :"<<m;
        }else if (k <= L1.size()) {
            return selectionByMedianOfMedians(L1, k);
        }else if (k > (L1.size() + 1)){
            return selectionByMedianOfMedians(L2, k-((int)L1.size())-1);
        }
    
    }
    
    int main()
    {
        int values[] = {2, 3, 5, 4, 1, 12, 11, 13, 16, 7, 8, 6, 10, 9, 17, 15, 19, 20, 18, 23, 21, 22, 25, 24, 14};
    
        vector<int> vec(values, values + 25);
    
        cout<<"The given array is : "<<endl;
        for (int i = 0; i < vec.size(); i++) {
            cout<<vec[i]<<" ";
        }
    
        selectionByMedianOfMedians(vec, 8);
    
        return 0;
    }
    

    【讨论】:

    • 任何解释你做了什么?
    • 此代码不起作用。您的 findMedian() 方法应该在 median = vec[(size/2)]; 之前排序。
    • 是的,我同意@blueskin。您的代码只是选择中间值作为枢轴,而不是实际计算中位数的中位数。您链接的演示文稿不正确。
    • 此解决方案并未真正利用 MedianOfMedians。此外,计算中位数的中位数不仅仅是选择它们的中间元素,它应该是一个递归调用。
    猜你喜欢
    • 1970-01-01
    • 2012-02-23
    • 2013-07-09
    • 2021-08-27
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 2014-05-19
    • 2018-04-01
    相关资源
    最近更新 更多