求旋轉陣列的最小數字演算法的解析以及完整c語言程式碼實現
首先了解什麼是旋轉陣列:即把一個數組的最開始的若干個元素搬到陣列的末尾,即成為旋轉陣列,例如陣列{3,7,1,8,2}為{1,8,2,3,7}的一個旋轉陣列。
題目:輸入一個遞增排序的陣列的一個旋轉,輸出旋轉陣列的最小元素,例如{1,2,3,4,5}陣列的一個旋轉陣列{3,4,5,1,2},其最小的元素為1,
解析:看到題目以後,我們首先可能會想到遍歷這個陣列,即可找到最小的元素,時間複雜度為o(n),但是這個思路顯然沒有利用到陣列是遞增排序的特性,因此我們得繼續尋找更優 的方法,因為原本陣列是遞增排序的,那麼旋轉之後的陣列是由兩個遞增排序的陣列組成,而且前面的子陣列的元素都大於或等於後面子陣列的元素,並且這個最小的元素正好將兩個子陣列分隔,因此我們可以試著用二分查詢的思路來查詢這個最小元素。
與二分查詢方法一樣,我們可以用兩個指標分別指向這個陣列的第一個元素和最後一個元素,按照旋轉的規則,第一個元素應該是大於或者等於最後一個元素的,(這其實也不完全對,還有一種情況是特例,稍後討論),
接著我們可以找到陣列中間的元素,如果該陣列位於前面的遞增子陣列,那麼他應該大於或者等於第一個指標指向的元素,陣列的最小元素應該位於中間元素的後面,因此我們可以將指標指向中間元素,這樣就縮小了查詢的範圍,同理如果中間元素位於後一個遞增子陣列中,那麼他應該小於或等於第二個指標指向的元素,此時該陣列中最小的元素應該位於該中間元素的前面,因此我們可以將第二個指標指向該中間元素,縮小查詢的範圍,
按照上面的思路,第一個指標總是指向前面遞增陣列的元素,第二個指標指向後面遞增陣列的元素,最終第一個指標指向前面遞增陣列的最後一個元素,而第二個指標指向後面子陣列的第一個元素,而第二個指標指向的剛好是最小的元素,迴圈結束。
前面提到的第一個元素應該是大於或等於最後一個元素的,特例:如果把排序陣列的前0個元素搬到最後面,即排序陣列本身,這仍然是陣列的旋轉,因此第一個數就是最小的數,我們可以直接返回,
還有一種情況存在即陣列{1,0,1,1,1}和陣列{1,1,1,0,1}都可以看成是遞增排序陣列{0,1,1,1,1}的旋轉,這樣的話第一個元素、中間元素、最後一個元素都是1,我們無法判斷中間數字1是屬於前面的遞增子陣列還是第二個遞增子陣列,因此我們就不可以使用而二分查詢的思路解決,只能使用順序查詢的方法。
具體程式碼如下:
<span style="font-size:24px;">//求旋轉陣列的最小元素
#include<stdio.h>
int minorder(int a[],int index,int index2);
int min(int *a,int length)
{
int index,index2,mid;
if(a==NULL||length<=0)
return 0;
index=0;
index2=length-1;
mid=index; //當將前0個元素搬到後面,即排序陣列本身,可以直接返回mid
while(a[index]>=a[index2])
{
if(index2-index==1) //兩個指標指向的元素相鄰,即index2指向的元素為最小元素
{
mid=index2;
break;
}
mid=(index+index2)/2;
if(a[index]==a[index2] && a[mid]==a[index]) //如果不能判斷中間元素屬於第一個遞增元素還是第二個遞增元素,則順序查詢
{
return minorder(a,index,index2);
}
if(a[mid]>=a[index])
index=mid;
if(a[mid]<=a[index2])
index2=mid;
}
return a[mid];
}
int minorder(int a[],int index,int index2)
{
int result=a[index];
int i;
for(i=index+1;i<=index2;i++)
{
if(result>a[i]) //順序查詢比較,找到最小的元素
result=a[i];
}
return result;
}
int main()
{
int a[5];
int i,x;
for(i=0;i<5;i++)
{
scanf("%d",&a[i]);
}
x=min(a,5);
printf("%d\n",x);
return 0;
}</span>