示例#1
0
int medianOfMedians(int A[], int p, int q, int k, int *pos)
{
    if(p == q)
    {
        *pos = p;
        return A[p];
    }
    int i, m, n, B[(q-p+1)/5+1], small, index, b = 0, j;
    for(i = p; i <= q; i+=5)
    {
        for(m = p; m < p+5 && m <=q; m++)
        {
            small = A[m];
            index = m;
            for(n = m+1; n < p+5 && n <= q; n++)
            {
                if(small > A[n])
                {
                    small = A[n];
                    index = n;
                }
            }
            if(m != index)
            {
                A[index] = A[m];
                A[m] = small;        
            }
        }
        if(i+5 > q)
        {
            B[b] = A[(i+q)/2];
        }
        else
        {
            B[b] =  A[i+2];
        }
        b++;
    }
    int pivot = medianOfMedians(B, 0, b-1, (b-1)/2, pos);
    int rank = partition(A, p, q, pivot);
    *pos = p+rank;
    if(k == rank)
        return pivot;
    else if(k < rank)
        return medianOfMedians(A, p, p+rank-1, k, pos);
    else
        return medianOfMedians(A, p+rank+1, q, (k-rank-1), pos);
}
/** Linear worst-case time algorithm to find median in ar[left,right]. The
 * comparison function, cmp, is needed to compare elements. */
int selectMedian (void **ar, int(*cmp)(const void *,const void *),
                  int left, int right) {
    int k = (right-left+1)/2;
    while (k > 0) {
        /* Make guess */
        int idx = medianOfMedians (ar, cmp, left, right, 1);

        /**
         * Partition input array around the median of medians x. If kth
         * largest is found, return absolute index; otherwise narrow to
         * find kth smallest in A[left,pivotIndex-1] or (k-p)-th
         * in A[pivotIndex+1,right].
         *
         */
        int pivotIndex = partition (ar, cmp, left, right, idx);

        /* Note that k is in range 0 <=k <= right-left while the returned
           pivotIndex is in range left <= pivotIndex <= right. */
        int p = left+k;
        if (p == pivotIndex) {
            return pivotIndex;
        } else if (p < pivotIndex) {
            right = pivotIndex-1;
        } else {
            k = k - (pivotIndex-left+1);
            left = pivotIndex+1;
        }
    }

    /* If we get here, then left=right, so just return one as median. */
    return left;
}
/**
 * Find suitable pivotIndex to use for ar[left,right] with closed bound
 * on both sides.
 *
 * 1. Divide the elements into floor(n/size) groups of size elements and
 *    use _insertion on each group
 * 2. Pick median from each sorted groups (size/2 element).
 * 3. Use select recursively to find median x of floor(n/size) medians
 *    found in step 2. This is known as the median-of-medians.
 */
static int medianOfMedians (void **ar, int(*cmp)(const void *,const void *),
                            int left, int right, int gap) {
    int s, num;
    int span = groupingSize*gap;

    /* less than five? Insertion sort and return median.  */
    num = (right - left + 1) / span;
    if (num == 0) {
        _insertion (ar, cmp, left, right, gap);
        num = (right - left + 1)/gap;
        return left + gap*(num-1)/2;
    }

    /* set up all median values of groups of groupingSize elements */
    for (s = left; s+span < right; s += span) {
        _insertion (ar, cmp, s, s + span-1, gap);
    }

    /* Recursively apply to subarray [left, s-1] with increased gap
     * if more than 'groupingSize' groupings remain. */
    if (num < groupingSize) {
        /* find median of this reduced set. BASE CASE */
        _insertion (ar, cmp, left+span/2, right, span);
        return left + num*span/2;
    } else {
        return medianOfMedians (ar, cmp, left+span/2, s-1, span);
    }
}
static int medianOfMedians(double** a, int l, int r)
{
  int i; int medianInd; 
  int M=(r-l+1)/5; /* M = # 5-groups */
  /* Note that M might be increased by one below */
  if (M<=1){ /* recursion exit criterion */
    insertionSort(a,l,r);
    medianInd=l+(r-l)/2;
  } else{
    int medOfFive;
    for (i=0;i<M;i++){
      medOfFive=medianOfFive(a,l+i*5);
      swap(a,l+i,medOfFive); /* move in the beginning */
    }
    
    /* the last group (size < 5) */
    int sizeLast=(r-l)+1-M*5;
    if (sizeLast>2){
      insertionSort(a,l+M*5,r);
      swap(a,l+M,l+M*5+sizeLast/2);
      M++;
    }
    medianInd = medianOfMedians(a,l,l+M-1);
  }
  return medianInd;
}
// Median of medians algorithm: find k th smallest number in the sub-array[l..r]
int medianOfMedians(int *arr, const int &l, const int &r, const int &k)
{
    int n = r - l + 1; // length of the sub array

    // if k is out of range, throw exception
    if (k <= 0 || k > n)
        throw std::invalid_argument("invalid k-th");

    // divide sub-arrary[l..r] in groups of size GROUP_NUM (the last group length can be less than GROUP_NUM)
    // calculate median of each groups and store them in median array
    int const medianNum = static_cast<int>(ceil(static_cast<double>(n) / static_cast<double>(GROUP_NUM)));
    //int const medianNum = (n + 4) / GROUP_NUM;
    int median[medianNum];
    int median_i;
    for (median_i = 0; median_i < n / GROUP_NUM; ++median_i)
        median[median_i] = findMedian(arr + l + median_i * GROUP_NUM, GROUP_NUM);
    if (median_i * GROUP_NUM < n) { // last group with elements less than GROUP_NUM
        median[median_i] = findMedian(arr + l + median_i * GROUP_NUM, n % GROUP_NUM); 
    }    

    // Find median of all medians recursively
    int medOfMedians;
    if (medianNum == 1) // first median is the median of medians since there's only one median
        medOfMedians = median[0];
    else {
        // we don't need to consider odd and even array length cases,
        // since this median is used for partition
        medOfMedians = medianOfMedians(median, 0, medianNum - 1, medianNum / 2);
    }

    // get the medOfMedians's index
    int pivot_i;
    for (pivot_i = l; pivot_i < r; ++pivot_i) {
        if (arr[pivot_i] == medOfMedians)
            break;
    }
    // partition the array around median of medians
    int pos = partition(arr, l, r, pivot_i);

    if (pos - l + 1 == k) // if the pos is the kth number, return it   
        return arr[pos];
    if (pos - l + 1 > k)  // if position is more than kth, find kth within left sub-array
        return medianOfMedians(arr, l, pos - 1, k);
    else                  // if position is less than kth, find kth within right sub-array 
        return medianOfMedians(arr, pos + 1, r, k - pos + l - 1);  
}
示例#6
0
int selectIdx(ll *nums, int left, int right, int k) {
	int pivotIdx;
	if(left == right) return k;
	pivotIdx = medianOfMedians(nums, left, right);
	pivotIdx = partition(nums, left, right, pivotIdx);
	if(pivotIdx == left || k == pivotIdx)
		return k;
	else if(k < pivotIdx)
		return selectIdx(nums, left, pivotIdx - 1, k);
	else
		return selectIdx(nums, pivotIdx + 1, right, k);
}
/* changes order of elements in x and in w (weights)! */
static void median(double **xadd, int left, int right, int* res)
{
  int i;
  int N = right - left + 1;
  int M = left + N/2; if (N % 2 == 0) {M --;} /* lower median */
  /* int M = left + N/2; */ /* upper median */
  int l = left; int r = right; 
  int* momInds = new int[2]; int momInd, momIndL, momIndR;
  
  while (1>0){
    momInd = medianOfMedians(xadd,l,r);
    partition(xadd,l,momInd,r,momInds);
    momIndL = momInds[0]; momIndR = momInds[1];
    if (momIndL>M) {r=momIndL-1;}
    if (momIndR<M) {l=momIndR+1;}
    if ((momIndL<=M)&&(momIndR>=M)) {break;}
  }
  delete[] momInds; res[0]=momIndL; res[1]=momIndR;
}
示例#8
0
int process(int A[], int B[], int n, int k)
{
    int pos1, pos2, k1, k2, min, max, a, b, i;
    if(k == 1)
    {
        k1 = medianOfMedians(A, 0, n-1, 0, &pos1);
        k2 = medianOfMedians(A, 0, n-1, 0, &pos2);
        if(k1 < k2)
            return k1;
        else
            return k2;
    }
    k1 = medianOfMedians(A, 0, n-1, k/2-1, &pos1);
    getchar();
    if(k%2 == 0)
        k2 = medianOfMedians(B, 0, n-1, k/2-1, &pos2);
    else
        k2 = medianOfMedians(B, 0, n-1, k/2, &pos2);
    if(k1 > k2)
    {
        a = pos1-1;
        b = n-1;
        if(b < (pos2+1))
        {
            return k1;
        }
        buildHeap(A, 0, (pos1-1), 0);
        buildHeap(B, (pos2+1), n-1, 1);
        while(k1 > k2)
        {
            if(b == pos2+1)
            {
                if(k1 > B[b])
                {
                    if(a >= 0)
                    {
                        max = extract(A, 0, &a, 0);
                        if(B[b] < max)
                            return max;
                        else
                            return B[b];
                    }
                    else B[b];
                }
                else
                    return k1;
            }
            if(a < 0)
            {
                min = extract(B, (pos2+1), &b, 1);
                if(min < k1)
                    return min;
                else
                    return k1;
            }
            max = extract(A, 0, &a, 0);
            min = extract(B, (pos2+1), &b, 1);
            if(min < k1)
            {
                k1 = max;
                k2 = min;
            }
            else
                return k1;
        }
        return k2;
    }
    if(k1 < k2)
    {
        a = n-1;
        b = pos2-1;
        if(a < (pos1+1))
        {
            return k2;
        }
        buildHeap(A, pos1+1, n-1, 1);
        buildHeap(B, 0, pos2-1, 0);
        while(k1 < k2)
        {
            if(a == pos1+1)
            {
                if(k2 > A[a])
                {
                    if(b >= 0)
                    {
                        max = extract(B, 0, &b, 0);
                        if(A[a] < max)
                            return max;
                        else
                            return A[a];
                    }
                    else A[a];

                }
                else
                    return k2;
            }
            if(b < 0)
            {
                min = extract(A, (pos1+1), &a, 1);
                if(min < k2)
                    return min;
                else
                    return k2;
            }
            max = extract(B, 0, &b, 0);
            min = extract(A, (pos1+1), &a, 1);
            if(min < k2)
            {
                k2 = max;
                k1 = min;
            }
            else
                return k2;
        }
        return k1;
    }
}