1、选择最大最小值:
a)选择最大或最小值,可以遍历数组所有元素,在线性时间O(n)内完成。
代码:
int findmax(int* A,int N)
{
int max = A[0];
int tmp;
for(int i = 1;i<N;i++){
tmp = A[i];
if(tmp>max){ max = tmp; }
}
return max;
}
b) 同时选出最大和最小值
分析:独立找最大和最小值,时间复杂度为O(2(n-1))
;
因此改为,将一对输入数据进行比较,较小的于当前最小值比较,较大的与当前最大值比较。所以4个元素比较3次,时间复杂度为O(3[n/2])
。
伪代码:
int findmax(int* A,int N)
{
int max,min;
if(n%2 == 0) { //n为偶数
if(A[0]>A[1]) {max =A[0]; min =A[1];}
else { max =A[1]; min =A[0]; }
}
else{
max =min =A[0];
}
int tmp1,tmp2; //同时比较两个数
。。。
return max, min;
}
2、选择算法:返回数组A[p…r]中第i小的元素
思路:分治思路,快速排序的修改,时间复杂度为O(n)
;
与快速排序一样,仍然将输入数据进行递归划分。但快速排序对两边都进行继续递归,因此时间复杂度为O(nlgn),但选择算法只对一边进行递归,时间复杂度为O(n)。
代码(假设各元素互异):
int SelectK(int *A, int l, int r, int k);//找第k小数
{
if(l == r) return A[l];
int pivot = Partition(A, l, r); //返回主元的下标
if(pivot == k-1) return A[pivot]; // 主元的下标为k-1则返回(下标从0开始,所以-1)
else if(pivot >k-1) return SelectK(A, l, pivot-1, k); // 若下标大则在左边递归
else return SelectK(A, pivot+1, r, k-pivor-2); // 小则在右边递归
}
int Partition(int *A, int l, int r)
{
int pivot = A[r]; //将数组最后一个值作为主元
int i = l;
int j = r-1;
for(;;){
while (A[i]<pivot){i++;}
while (A[j]>pivot){j--;}
if(i<j) swap(A[i],A[j]);
else break;
}
swap(A[i],A[right]); //将主元放在中间位置
return i;
}
注:数组最后一个值作为主元,利用主元所在下标表示元素个数。