1.二分排序(快排)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int n, a[1000001];
void qsort(int l, int r)//应用二分思想
{
int mid = a[(l + r) / 2];//中间数
int i = l, j = r;
int x;
do {
while (a[i] < mid) i++;//查找左半部分比中间数大的数
while (a[j] > mid) j--;//查找右半部分比中间数小的数
if (i <= j)//如果有一组不满足排序条件(左小右大)的数
{
x=a[i];
a[i] = a[j];
a[j] = x;//交换
i++;
j--;
}
} while (i <= j);//这里注意要有=
if (l < j) qsort(l, j);
if (i < r) qsort(i, r);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
qsort(1, n);
for (int i = 1; i <= n; i++) printf("%d ", a[i]);
return 0;
}
由于mid取的是a[(l + r) / 2],因此不担心i或j越界。
2.二分查找
例一:
输入n个数,查找从小到大的第k+1个数
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int n, a[5000000];
int qsort(int l, int r, int k)//应用二分思想
{
int mid = a[(l + r) / 2];//中间数
int i = l, j = r;
int x;
do {
while (a[i] < mid) i++;//查找左半部分比中间数大的数
while (a[j] > mid) j--;//查找右半部分比中间数小的数
if (i <= j)//如果有一组不满足排序条件(左小右大)的数
{
x = a[i];
a[i] = a[j];
a[j] = x;//交换
i++;
j--;
}
} while (i <= j);//这里注意要有=
if (i == j)
{
if (i == k)
return a[i];
else
return (i > k ? qsort(l, i - 1, k) : qsort(i + 1, r, k));
}
else
{
if (k <= j)return qsort(l, j, k);
else if (k >= i)return qsort(i, r, k);
else
return a[j + 1];
}
}
int main()
{
int k;
scanf("%d %d", &n, &k);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
printf("%d\n", qsort(0, n - 1, k));
return 0;
}
由于只用只用查找某一位置的数,故不需要将整个数列都排好。每次只用排一半。
例二:
题目如下:(原题链接:P1873 [COCI 2011/2012 #5] EKO / 砍树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))
用枚举法做固然可以,但是会超时;用二分答案的方法锁定答案。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int n, m, a[1000000];
int main()
{
scanf("%d %d", &n, &m);
int left , right, mid, sum = 0, max = 0, min;
for (int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
if (a[i] > max)max = a[i];
if (i == 0)min = a[i];
else min = (min < a[i] ? min : a[i]);
}
right = max, left = min;
while (left < right)
{
mid = (left + right + 1) / 2;
for (int i = 0; i < n; i++)
if (a[i] > mid)sum += (a[i] - mid);
if (sum >= m)left = mid;
else right = mid - 1;
sum = 0;
}
printf("%d\n", left);
return 0;
}
注意,mid需设置为(left + right + 1) / 2才能顺利结束循环;如果不加1,将陷入死循环。循环条件注意是left < right。循环结束时left == right。