您的位置:首页 > 编程语言 > C语言/C++

二分搜索应用(旋转数组)——C语言

2012-09-12 17:08 239 查看
出处——《剑指offer》

题目:把一个数组最开始的若干个元素搬到数组的末尾,称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。

1.用遍历数组的方法来实现

int MinInOrder( int num[], index1, index2 ) /*index1为数组起始位置,index2为数组终止位置*/

{

int result = num[ index1 ];

int i;

for( i = index1 + 1; i <= index2; i++ )

{

if( result > num[i] )

result = num[i];

}

return result;

}

算法复杂度O(n)

2.若能够使用二分搜索实现可以使算法复杂度为O(logn)

书中有详细的讲解,跟一般的二分搜索类似,但由于不是查找特定的数,而是要找到最小的数,因此要找到如何能够确定最小数的方法。根据旋转数组的特点,可以将其看作两个递增数组的组合,且左边数组的所有元素都大于右边数组,最小数所在的位置为右边数组的第一位。

设定三个指针i1,i2以及mid,使得i1始终处在左边数组中,i2始终处在右边数组中, mid为中间数,通过i1,i2,mid元素间的大小关系来逐步确定最小数的位置。

例如:若num[mid] >= num[i1]表明mid在左边数组中,那么令i1 = mid就可以使得i1趋近于左边数组末尾;若num[mid] <= num[i2]表明mid在右边数组中,此时则可令i2 = mid。

最终当i2 - i1 == 1时,i2就为最小元素的位置。

int Min( int num[], int length ) /*length为数组长度*/

{

int i1, i2, mid;

i1 = 0;

i2 = length - 1;

while( num[i1] >= num[i2] ) /*保证i1,i2处在不同的子数组中*/

{

if( i2 - i1 == 1 )

return num[i2];

mid = ( i1 + i2 ) / 2;

if( num[mid] >= num[i1] )

i1 = mid;

if( num[mid] <= num[i2] )

i2 = mid;

}

return num[i1]; /*完全递增的数组也是旋转数组的一种,当出现这种情况时,由于num[i1] < num[i2]使得循环不执行,此时返回数组首元素*/

}

不过上面的程序面对一些特例时会出现问题,如数组{ 1, 0, 1, 1, 1 },会出现num[i1] = num[i2] = num[mid] = 1的情况,此时循环中的两个if语句中的判断条件都为真,因此当第一次循环结束后就会出现i1 = i2 = mid的情况,使得循环无限执行。因此需要将这种情况考虑到函数中。

int Min( int num[], int length )

{

int i1, i2, mid;

i1 = 0;

i2 = length - 1;

while( num[i1] >= num[i2] )

{

if( i2 - i1 == 1 )

return num[i2];

mid = ( i1 + i2 ) / 2;

if( num[i1] == num[i2] && num[i1] == num[mid] ) /*出现i1, i2, mid三个元素都相等的情况则采用顺序搜索的方法*/

return MinInOrder( num, i1, i2 );

if( num[mid] >= num[i1] )

i1 = mid;

if( num[mid] <= num[i2] )

i2 = mid;

}

return num[i1];

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: