一种查找中值的方法——Rank_Select
2011-11-08 16:34
49 查看
看Kd树时,建立Kd-tree需要为第split维的值排序,并查找位于正中间的那个数据点。询问了好多同学,他们说,可以首先用堆排序,然后找第(n-1)/2的数。觉得挺有道理。
但是,还看到一种方法,就是Rank_Select方法。
代码如下:
Rank_Select方法
此方法,利用到了递归。
输入为该保持数据的数组,和数组中的元素个数,还有需要找到的中间值的索引。
昨天看了本书,才知道在C/C++中,如果将数据作为参数传递给函数,在函数内部利用sizeof(a)只是将a作为指针,所以sizeof(a)=4 而不是数组长度。因此,此处传的后两个参数必不可少。
首先把数据分为几组,每组含有5个数据,然后每组利用插入排序方法进行排序,最后取中值。
然后,在将取到的所有组的中值放入一个数组。进行取中值,即重复上述操作,直至传入的第二个参数为1,返回数组的第一个数据。
(1)查找索引为r=3的数据。
Tmp中包含两项 tmp[0]=13,tmp[1]=20
(2)因此,此时输入为tmp,2,0
(3)因此,输入为tmp[0]=13,并返回至第二步中。
第二个递归中,med=13.通过,partition_array函数,返回13的索引为2.但,2比3小。因此进入由25,67,20,30组成的查找特定值的递归中。此时,传入第二个参数为n-(j+1),原因是查找到的13,太靠前了,因此需要从后面的数据中查找。而返回的13的索引,与要查找的索引相差值,就是本次查找中,需要返回的索引,于是第三个参数为r-(j+1)。
然后,新一轮就开始了。Array 为下表数据,第二个参数为 4,第三个参数为0.
Tmp[0]= array[n-1-rem_elts/2] 即4-1-4/2 =1
Tmp[0]=25.
此时经过partition_array函数,返回25的索引为1.而第三个参数为0,因此找到的25就太靠后了,因此需要查找数组前面的数据。于是再开始新一轮的递归。
此时传入array,第二个参数为1(即查找到的索引),第三个参数因为要查找的索引,就包含在这部分中,因此直接传入这个索引即可.此时,返回值为20.即为要查找的值。
也许此算法分析不够准确,还望有人指出。
但是,还看到一种方法,就是Rank_Select方法。
代码如下:
Rank_Select方法
static void insertion_sort( double* array, int n ) { double k; int i, j; for( i = 1; i < n; i++ ) { k = array[i]; j = i-1; while( j >= 0 && array[j] > k ) { array[j+1] = array[j]; j -= 1; } array[j+1] = k; } } /* Partitions an array around a specified value. @param array an array @param n number of elements @param pivot value around which to partition @return Returns index of the pivot after partitioning */ static int partition_array( double* array, int n, double pivot ) { double tmp; int p, i, j; i = -1; for( j = 0; j < n; j++ ) if( array[j] <= pivot ) { tmp = array[++i]; array[i] = array[j]; array[j] = tmp; if( array[i] == pivot ) p = i; } array[p] = array[i]; array[i] = pivot; return i; } static double rank_select( double* array, int n, int r ) { double* tmp, med; int gr_5, gr_tot, rem_elts, i, j; /* base case */ if( n == 1 ) return array[0]; /* divide array into groups of 5 and sort them */ gr_5 = n / 5; gr_tot = cvCeil( n / 5.0 ); rem_elts = n % 5; tmp = array; for( i = 0; i < gr_5; i++ ) { insertion_sort( tmp, 5 ); tmp += 5; } insertion_sort( tmp, rem_elts ); /* recursively find the median of the medians of the groups of 5 取所有中间值*/ tmp = (double*)calloc( gr_tot, sizeof( double ) ); for( i = 0, j = 2; i < gr_5; i++, j += 5 ) tmp[i] = array[j]; if( rem_elts ) tmp[i++] = array[n - 1 - rem_elts/2]; //取中间值 med = rank_select( tmp, i, ( i - 1 ) / 2 ); free( tmp ); /* partition around median of medians and recursively select if necessary */ j = partition_array( array, n, med ); if( r == j ) return med; else if( r < j ) return rank_select( array, j, r ); else { array += j+1; return rank_select( array, ( n - j - 1 ), ( r - j - 1 ) ); } }
此方法,利用到了递归。
输入为该保持数据的数组,和数组中的元素个数,还有需要找到的中间值的索引。
昨天看了本书,才知道在C/C++中,如果将数据作为参数传递给函数,在函数内部利用sizeof(a)只是将a作为指针,所以sizeof(a)=4 而不是数组长度。因此,此处传的后两个参数必不可少。
首先把数据分为几组,每组含有5个数据,然后每组利用插入排序方法进行排序,最后取中值。
然后,在将取到的所有组的中值放入一个数组。进行取中值,即重复上述操作,直至传入的第二个参数为1,返回数组的第一个数据。
13:0 | 25:1 | 67:2 | 2:3 | 10:4 | 30:5 | 20:6 |
2:0 | 10:1 | 13:2 | 25:3 | 67:4 | 20:5 | 30:6 |
(2)因此,此时输入为tmp,2,0
(3)因此,输入为tmp[0]=13,并返回至第二步中。
第二个递归中,med=13.通过,partition_array函数,返回13的索引为2.但,2比3小。因此进入由25,67,20,30组成的查找特定值的递归中。此时,传入第二个参数为n-(j+1),原因是查找到的13,太靠前了,因此需要从后面的数据中查找。而返回的13的索引,与要查找的索引相差值,就是本次查找中,需要返回的索引,于是第三个参数为r-(j+1)。
然后,新一轮就开始了。Array 为下表数据,第二个参数为 4,第三个参数为0.
25:0 | 67:1 | 20:2 | 30:3 |
20:0 | 25:1 | 30:2 | 67:3 |
Tmp[0]=25.
此时经过partition_array函数,返回25的索引为1.而第三个参数为0,因此找到的25就太靠后了,因此需要查找数组前面的数据。于是再开始新一轮的递归。
此时传入array,第二个参数为1(即查找到的索引),第三个参数因为要查找的索引,就包含在这部分中,因此直接传入这个索引即可.此时,返回值为20.即为要查找的值。
也许此算法分析不够准确,还望有人指出。
相关文章推荐
- MySQL学习笔记(二):查找记录方法-SELECT(详细)
- BeautifulSoup 使用select方法详解(通过标签名,类名, id,组合,属性查找)
- 实现一种快速查找Richedit中可见区域内OLE对象的方法
- 设计一个最优算法来查找一n个元素数组中的最大值和最小值。已知一种需要比较2n次的方法,请给一个更优的算法。
- 内网ARP攻击的一种查找方法(学习石头)
- Validate对select组件不进行验证的一种解决方法
- jqGrid 行编辑 select 3级联动 的一种实现方法
- 折半查找------- 一种高效的查找方法
- 【select级联】一种新的方法
- 《可信计算的研究与发展》;C-Rank:一种Deep Web数据记录可信度评估方法
- 一种动态call地址查找及使用方法 -- QQ游戏斗地主角色版-喊话call定位技巧
- 一种查找k个最小元素的方法
- 推荐系统(recommender systems):预测电影评分--构造推荐系统的一种方法:低秩矩阵分解(low rank matrix factorization)
- 二叉树的实现、键的最大值、最小值、Rank()、select()、get()、put()方法实现
- [git]查找某个地方是谁修改的一种方法
- 快捷方式查找目标失效的一种解决方法
- 实现一种快速查找Richedit中可见区域内OLE对象的方法
- .net datatable 查找一行时的方法比较datatable.rows.find vs datable.select vs dataview vs for loop
- 稀疏数据压缩查询方法:Rank & Select 操作
- vx系统下查找内存被篡改的一种方法