Select算法(最坏复杂度O(n))

  1 #include<iostream>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <string>
  6 #include <string.h>
  7 using namespace std;
  8 
  9 const int nMax = 3000;
 10 int A[nMax+1];
 11 int B[nMax+1];//用来每次5分法后保存要比较的值在A中的下标
 12 int AIndex[nMax+1]; //用来保存A的初始化下标
 13 
 14 //通过插入排序获取中位数下标
 15 int InsertSort(int A[], int B[], int start, int end)
 16 {
 17     if (start == end)
 18     {
 19         return B[start];
 20     }
 21 
 22     for (int i = start+1; i <= end; ++i)
 23     {
 24         int num = A[B[i]];
 25         int j = i-1;
 26         for ( ; j >= start; --j)
 27         {
 28             if (num < A[B[j]])
 29             {
 30                 A[B[j + 1]] = A[B[j]];
 31             }
 32             else
 33             {
 34                 break;
 35             }
 36         }
 37         A[B[j + 1]] = num;
 38     }
 39 
 40     return B[(start + end)/2];
 41 }
 42 
 43 //获取中位数的中位数的下标
 44 int GetMidMid(int A[], int AIndex[], int k, int n)
 45 {
 46     if (k == n)
 47     {
 48         return AIndex[n];
 49     }
 50 
 51     int len_s = n - k + 1;
 52     //筛选出n/5份的中位数
 53     int mod = len_s % 5;
 54     int len = len_s / 5 + (mod != 0);
 55     for (int i = 1, j = k; i<= len && j <= n-mod; ++i, j+=5)
 56     {
 57         B[i] = InsertSort(A, AIndex,j, j+4);
 58     }
 59     if (mod != 0)
 60     {
 61         B[len] = InsertSort(A, AIndex, n - mod + 1, n);
 62     }
 63     return GetMidMid(A, B, 1, len);
 64 }
 65 
 66 //原址排序
 67 int Partition(int A[], int p, int n)
 68 {
 69     int pivot = A[n];
 70     int j = p - 1;
 71     for (int i = p; i <= n - 1; ++i)
 72     {
 73         if (A[i] <= pivot)
 74         {
 75             j++;
 76             swap(A[j], A[i]);
 77         }
 78     }
 79 
 80     swap(A[j + 1], A[n]);
 81     return j + 1;
 82 }
 83 
 84 int Select(int A[], int k, int n, int i)
 85 {
 86     if (k == n)
 87     {
 88         return A[n];
 89     }
 90 
 91     int midValueIndex = GetMidMid(A, AIndex, k, n);
 92 
 93     //将该中位数作为主元(pivot element)
 94     //使用一次原址重排
 95     int pivot = A[midValueIndex];
 96     swap(A[midValueIndex], A[n]);
 97     int mid = Partition(A, k, n);
 98 
 99     int t = mid - k + 1;
100     if (i == t)
101     {
102         return A[mid];
103     }
104     else if (i < t)
105     {
106         return Select(A, k, mid-1, i);
107     }
108     else
109     {
110         return Select(A, mid+1, n, i-t);
111     }
112 }
113 int main(int argc, char** argv)
114 {
115     int n = 1111;
116     for (int i = 1; i <= n; ++i)
117     {
118         A[i] = i;
119         AIndex[i] = i;
120     }
121 
122     //for (int i = 1; i <= n; ++i)
123     //{
124     //    cout << A[i] << " ";
125     //}
126     //cout << endl;
127     
128     int equalNum = 0;
129     for (int i = 1; i <= n; ++i)
130     {
131         //随机排列A数组
132         for (int i = 1; i <= n; ++i)
133         {
134             int j = i + rand() % nMax;
135             //swap(A[i], A[j]);
136             A[i] = j;
137         }
138 
139         int ans1 = Select(A, 1, n, i);
140         sort(A + 1, A + n + 1);
141         int ans2 = A[i];
142 
143         if (ans1 == ans2)
144         {
145             equalNum++;
146         }
147     }
148     cout << n << " " << equalNum << endl;
149     return 0;
150 }