/* * 算法导论 第九章 中位数和顺序统计学 * 线性时间选择元素 */ #include <iostream> #include <ctime> using namespace std; int minimum(int *arr, int len); int randomizedSelect(int *arr, int p, int r, int i); int randomizedPartition(int *arr, int p, int r); void exchange(int arr[], int i, int j); int partition(int arr[], int p, int r); int select(int *arr, int p, int r, int i); int partitionWithPivot(int *arr, int p, int r, int pivot); void printArray(int arr[], int len, char *str); int getMedian(int *arr, int p, int r); void randomizedQuickSort(int *arr, int p, int r); int main() { int len = 15; int *arr = new int[len]; srand(time(NULL)); for (int i=0; i<len; i++) { arr[i] = rand() % 100; } printArray(arr, len, "原数组"); cout<<"最小元素为:"<<minimum(arr, len)<<endl; int i = 3; int elem = randomizedSelect(arr, 0, len-1, i); randomizedQuickSort(arr, 0, len-1); printArray(arr, len, "排序后的数组"); cout<<"第 "<<i<<" 小的元素为:"<<elem<<endl<<endl; for (int i=0; i<len; i++) { arr[i] = rand() % 100; } printArray(arr, len, "原数组"); i = 10; elem = select(arr, 0, len-1, i); randomizedQuickSort(arr, 0, len-1); printArray(arr, len, "排序后的数组"); cout<<"第 "<<i<<" 小的元素为:"<<elem<<endl; delete[] arr; return 0; } /* * 求数组中的最小值 * 时间复杂度为O(n) */ int minimum(int *arr, int len) { int min = arr[0]; for (int i=1; i<len; i++) { if (arr[i] < min) min = arr[i]; } return min; } /* * 随机化选择算法 * 选择arr[p..r]中第 i 小的元素 * 使用快速排序中的随机化划分方法,平均情况下每次将选择空间缩小一半 * 所以在平均情况下,时间复杂度为O(n) */ int randomizedSelect(int *arr, int p, int r, int i) { if (p == r) { return arr[p]; } int q = randomizedPartition(arr, p, r); int k = q - p + 1; if (k == i) { return arr[q]; } else if (i < k) { return randomizedSelect(arr, p, q-1, i); } else { return randomizedSelect(arr, q+1, r, i-k); } } /* * 随机化快速排序 * 期望时间复杂度为O(nlgn) */ void randomizedQuickSort(int *arr, int p, int r) { if (p < r) { int q = randomizedPartition(arr, p, r); randomizedQuickSort(arr, p, q-1); randomizedQuickSort(arr, q+1, r); } } /* * 随机化划分 */ int randomizedPartition(int *arr, int p, int r) { srand(time(NULL)); int i = p + rand() % (r-p+1); exchange(arr, i, r); return partition(arr, p, r); } void exchange(int arr[], int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } int partition(int arr[], int p, int r) { int pivot = arr[r]; int i = p - 1;//i前面的(包括i)的元素都是不大于pivot的,i后面的都是大于pivot的元素 int j;//j后面的(包括j)都是还没有划分的 for (j=p; j<=r-1; j++) { if (arr[j] <= pivot) { i++; exchange(arr, i, j); } } i++; exchange(arr, i, r); return i; } /* * 最坏情况下线性时间选择算法 * 此算法依然是建立在快速排序的划分算法基础之上的 * 但是与randomizedSelect算法的不同指之处,就是次算法的本质 * 是保证了每次划分选择的划分主元一定是一个较好的主元,算法先对数组5个一组进行分组 * 然后选择每组的中位数,再递归的选择各组中位数中的中位数作为数组的划分主元,以此保证划分的平衡性 * 选择中位数的时候必须使用递归调用的方法才能降低时间复杂度 * 从而保证在最坏情况下都得到一个好的划分 * 最坏情况下时间复杂度为O(n) */ int select(int *arr, int p, int r, int i) { if (p == r) { return arr[p]; } int len = r-p+1; int medianCnt = 1; if (len > 5) medianCnt = len%5 > 0 ? len/5+1 : len/5; int *medians = new int[medianCnt]; //使用插入排序找出每组的中位数 for (int j=0, k=p; j<medianCnt; j++) { if (j == medianCnt-1) { medians[j] = getMedian(arr, k, r); } else { medians[j] = getMedian(arr, k, k+4); k += 5; } } //递归调用select线性时间函数自身选择中位数组中的中位数 int pivot = select(medians, 0, medianCnt-1, (medianCnt+1)/2); delete[] medians; int q = partitionWithPivot(arr, p, r, pivot); int k = q-p+1; if (i == k) { return pivot; } else if (i < k) { return select(arr, p, q-1, i); } else { return select(arr, q+1, r, i-k); } } /* * 根据指定的划分主元pivot来划分数组 * 并返回主元的顺序位置 */ int partitionWithPivot(int *arr, int p, int r, int pivot) { int i = p - 1; int j = p; for (; j<=r; j++) { //此处用<较为准确 if (arr[j] < pivot) { i++; exchange(arr, i, j); } } for (int j=i+1; j<=r; j++) { if(arr[j] == pivot) { exchange(arr, i+1, j); break; } } return i+1; } /* * 利用插入排序选择中位数 */ int getMedian(int *arr, int p, int r) { //插入排序 for (int i=p+1; i<=r; i++) { int key = arr[i]; int j = i - 1; while (j >= p && arr[j] > key) { arr[j+1] = arr[j]; j--; } arr[j+1] = key; } return arr[(p+r)/2]; } void printArray(int arr[], int len, char *str) { cout << str << endl; for (int i=0; i<len; i++) { cout << arr[i] << " "; } cout << endl; }
算法导论 第9章 中位数和顺序统计学,布布扣,bubuko.com
原文地址:http://blog.csdn.net/lucienduan/article/details/38664255