問題描述:給定線性序集中n個元素和一個整數k,1≤k≤n,要求找出這n個元素中第k大的元素,(這里給定的線性集是無序的)。
其實這個問題很簡單,直接對線性序列集qsort,再找出第k個即可。但是這樣的時間復雜度就是qsort的時間復雜度O(nlogn)。有沒有更快的方法呢?看到網上有一種解法是采取了快排的思路,但是稍微坐了些改動,然后時間復雜度能夠接近O(n)。因為最近剛剛寫了快排的實現,所以在這我就再把這個實現一次吧。
解題思路:與快排不同的是,這里只對划分出來的其中一組進行遞歸處理。任意選定一個pivotIndex,pivotValue = arr[pivotIndex]。經過一次划分后,pivotValue存儲在storeIndex的位置,storeIndex把數組划分為兩部分。比pivoteValue大的在前面,比pivotValue小的存儲在后面(此時前后兩部分是沒有排好序的)。那么storeIndex位置的pivotValue就肯定是第storeIndex大的數。然后用K於storeIndex比較,如果K<storeIndex,那么說明第K大一定在右邊,那么再對右邊進行划分即可。如果K>storeIndex,那么說明第K大一定在左邊,那么再對左邊進行划分。然后遞歸,最后就可以得到第K大。
#include <stdio.h> void swap(int *a, int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; } int partition(int arr[], int left, int right, int pivotIndex) { int storeIndex = left; int pivotValue = arr[pivotIndex]; int i; swap(&arr[pivotIndex],&arr[right]); for (i = left; i < right; i ++) { if (arr[i] > pivotValue) { swap(&arr[i],&arr[storeIndex]); storeIndex++; } } swap(&arr[storeIndex],&arr[right]); return storeIndex; } int findKMax(int arr[], int left, int right, int k) { int nRet; int pivotIndex = left + 1; nRet = partition(arr,left,right,pivotIndex); if (nRet < k) { return findKMax(arr,nRet+1,right,k); } else if (nRet > k) { return findKMax(arr,left,nRet-1,k); } return nRet; } int main() { int i,k,nRet; int arr[] = {8,3,4,1,9,7,6,10}; scanf("%d",&k); nRet = findKMax(arr,0,7,k-1); printf("The Kth Max Number locate in %d is :%d\n",nRet,arr[nRet]); for (i = 0; i < 8; i++) { printf("%3d",arr[i]); } return 0; } 2013/6/17 19:55
蕭蕭空間列出了很多種尋找第K大數的算法。
第二次實現該算法:
#include <stdio.h> void swap(int arr[], int i, int j) { int tmp; tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } int partition(int arr[], int left, int right) { int value = arr[left]; int p_insert,p_cmp; swap(arr,left,right); p_insert = p_cmp = left; while (p_cmp < right) { if (arr[p_cmp] < value) { swap(arr,p_insert,p_cmp); p_insert++; } p_cmp++; } swap(arr,p_insert,right); return p_insert; } void max_k(int arr[], int left, int right,int k) { int ret = partition(arr,left,right); if (ret == k) return; else if (ret < k) ret = partition(arr,ret+1,right); else ret = partition(arr,left,ret); } int main() { int arr[] = {9,10,7,8,3,12,15,76,6}; int i,k = 5; max_k(arr,0,8,k); for (i = 0; i < k; i++) { printf("%d ",arr[i]); } printf("\n"); return 0; } 2013/10/21 22:42