冒泡排序、递归算法
首先给出一种让你可能耳目一新的冒泡排序算法
void bubblesort(const int a[], const int& n){
bool sorted = false; // 整体排序标志,这是本算法的有力手段
while(!sorted){
sorted = true; // 假定已经排序
for(int i = 1; i < n; ++i){
// 自左向右逐对检查当前范围 a[0, n)内的各相邻元素
if(a[i - 1] > a[i]){
// 逆序则交换
std::swap(a[i - 1], a[i]);
sorted = false; // 因整体排序不能保证,需要清除排序标志位
}
}
n--; // 至此末元素必然就位,故可以缩短待排序序列的有效长度
}
}
☆ 借助布尔型标志位 sorted,可以提前退出,而不总是蛮力地做 n - 1趟扫描交换。
下面你会看到更加强大的算法内容
考虑一个数组求和问题,一般人的算法如下
const int sum(const int* p, const int& n) {
int sum = 0;
for (int i = 0; i < n; ++i) {
// T(n) = σ(n)
sum += p[i];
}
return sum;
}
- 迭代求和
const int sum(int* p, int n) {
int sumA = 0;
while (n-- > 0) {
sumA += p[n];
}
return sumA;
}
现在我们来考虑用递归求数组元素总和
- 线性递归
const int sum(const int a[], const int& n) {
if (1 > n) {
return 0;
}
else {
return sum(a, n - 1) + a[n - 1];
}
}
- 我把上述两函数放在一起(这里是函数重载,所以可以放一起)然后调用 sum 函数,调用形式(sum(a,
int n
))是一样的。你猜谁被编译器选择了,是下面的递归求和函数而非一般的求和函数。
再深入一点,二分递归求和
// 算法入口的调用形式 sum(a, 0, n - 1)
const int sum(const int a[], const int& l, const int& r) {
if (l == r) {
return a[l];
}
else {
int mid = (l + r) >> 1; // 算术右移一位,相当于除以 2
return sum(a, l, mid) + sum(a, mid + 1, r);
}
}
递归是不是很强大,反正我觉得很牛
由此我想到了用递归来求最大值和最小值。我试了一下,代码放下面,当然递归的方式也有多种多样,也许你也能创造不一样的精彩递归哦。
- 线性递归求最大值
// 线性递归求最大值
inline int maxdouble(const int& a, const int& b) {
return a > b ? a : b;
}
// 算法入口的调用形式 max(a, 0, n - 1)
const int max(const int a[], const int& l, const int& n) {
if (n == l) {
return a[l];
}
else {
return maxdouble(max(a, l + 1, n), a[l]);
}
}
- 线性递归求最小值
另外一种更简化的方法
//调用形式为 min(a,0,n - 1)
const int min(const int a[], const int& l, const int& n) {
if (l == n) {
return a[l];
}
else {
return min(a, l + 1, n) < a[l] ? min(a, l + 1, n) : a[l];
}
}
当然,以此类推,还可以用二分递归来求最大值、最小值
☆ 但是,递归算法比较耗内存,所消耗的空间主要取决于递归深度,所以对运行速度要求极高、存储空间需要精打细算的场合,往往应将递归算法改写成等价的非递归版本。