参考算法导论9.3节的内容和这位大神的博客:http://blog.csdn.net/v_JULY_v上对这一节内容代码的实现进行了学习
尝试实现了以查找中位数为前提的select算法。
算法功能:可以确定一个数组中第k大的元素。
算法思想描述如下:
1、将输入n个元素划分为(n/5:向下取整)个组,每组有5个元素。而只有最后一组为数组剩下的(n mod 5)个元素组成。
2、寻找这些组的中位数:通过对每一个小组进行插入排序,确定中位数。保存到数组mid_arr中。(下标:第i组中位数存在第i位上)
3、对2中查找的中位数数组继续递归调用select函数来查找中位数。
4、最后找到中位数的中位数,记为x。以x为枢纽,对数组进行1次划分,设y为比划分低区元素数目+1。划分以后有(n-y)个元素在高区,x为第y小元素。
5、当k==y时 函数结束,返回x值
k<y:对低区调用select函数来寻找第k小个数
k>y:对高区调用select函数来寻找第(k-y)小个元素。k-y是因为已知了y个元素比高区元素小。
具体实现与注释见代码
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 const int num=21; 5 const int numdev=num/5+1;//向上取整 6 int arr[num]; 7 int mid_arr[numdev]; 8 9 void insert_sort(int arr[],int left,int r) 10 { 11 for(int i=left; i<left+r; i++) //对于传入的数组arr中下标为left到left+r的元素进行插入排序 12 { 13 int key=arr[i]; 14 int j=i-1; 15 while(j>left&&arr[j]>key) 16 { 17 arr[j+1]=arr[j]; 18 j--; 19 } 20 arr[j+1]=key; 21 } 22 } 23 int find_mid(int arr[],int left,int right) 24 { 25 if(left==right) return arr[left]; 26 27 int index; 28 for(index=left; index<right-5; index+=5) 29 { 30 insert_sort(arr,index,4); 31 int number=index-left;//中位数的计算与寻找 32 mid_arr[number/5]=arr[index+2];//把插入排序后的这一组数字中5组数的中位数放到mid_arr对应下标的位置中 33 34 } 35 36 //对剩余元素的处理 37 int remain_num=right-index+1;//注意这个下标细节,计算最后一组元素的个数 38 if(remain_num>0) 39 { 40 insert_sort(arr,index,remain_num-1); 41 int number=index-left; 42 mid_arr[number/5]=arr[index+remain_num/2]; 43 } 44 45 int num_group=(right-left)/5-1; 46 if((right-left)%5!=0) num_group++; 47 48 if(num_group==0) return mid_arr[0]; 49 else return find_mid(mid_arr,0,num_group); 50 } 51 52 int find_mid_index(int arr[],int left,int right,int mid)//寻找中位数的位置 53 { 54 for(int i=left; i<=right; i++) 55 { 56 if(arr[i]==mid) return i; 57 } 58 return -1; 59 } 60 int quick_select(int arr[],int left,int right,int k) 61 { 62 int mid=find_mid(arr,left,right); 63 64 int index=find_mid_index(arr,left,right,mid); 65 swap(arr[index],arr[right]); 66 int pivot=arr[right]; 67 68 int i=left; 69 int j=right-1; 70 //按中位数的中位数对数组进行1次划分。 71 while(1) 72 { 73 while(arr[i]<pivot) i++; 74 while(arr[j]>pivot) j--; 75 if(i<j) 76 swap(arr[i],arr[j]); 77 else break; 78 } 79 swap(arr[i],arr[right]); 80 /*对于下一次划分的处理*/ 81 int m=i-left+1; 82 if(m==k) return arr[i]; 83 else if(m>k) return quick_select(arr,left,i-1,k); 84 else return quick_select(arr,i+1,right,k-m); 85 86 } 87 int main() 88 { 89 int arr[num]= {1,5,9,7,8,4,6,3,2,10,15,13,12,17,18,14,19,21,20,11,16}; 90 int k=7; 91 int ans=quick_select(arr,0,num-1,k); 92 cout<<ans<<endl; 93 return 0; 94 }