查找与排序先从讲递归开始。课程列举了很多递归典例,按照理解的难度从简到繁,部分过于简单的就不再赘述了,只写一些有意义的代码。
递归的要点
找变化,找重复,找出口,子问题要与原问题有同样的结构。
【一】
辗转相除法, 又名欧几里德算法(Euclidean algorithm),是求最大公约数的一种方法。它的具体做法是:用较大数除以较小数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。(采自百度词条)
/* 辗转相除法求最大公约数 */
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <cmath>
using namespace std;
#define MON 1000000
/*m是较大数,n是较小数*/
int gcd(int m, int n){
if(n == 0){
return m;
}
else{
return gcd(n, m%n);
}
}
int main() {
cout << gcd(36,24) <<endl;
}
m%n < (m/2)
所以 n%(m%n)< (n/2),每两次进行折半计算。
2*lgn,O(lgn)
性能分析:
【二】
插入法排序
/*插入排序改递归*/
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <cmath>
using namespace std;
#define MAX 100
void insertsort(int arr[], int k){
if(k == 0){
return;
}
insertsort(arr, k-1);
int x = arr[k];
int index = k - 1;
while(x < arr[index]){
/*将比第k个元素大的数后挪一位*/
arr[index + 1] = arr[index];
index --;
}
/*元素k应在的位置*/
arr[index + 1] = x;
}
int main() {
int arr[MAX];
int N;
cin >> N;
int i;
for(i=0; i<N; i++){
cin >> arr[i];
}
insertsort(arr, N-1);
for(i=0; i<N; i++){
cout << arr[i] << " ";
}
cout <<endl;
}
【三】
汉诺塔问题
1~N从A移动到B,C作为辅助等价于:
1、1~(N-1)从A移动到C,B为辅助
2、把N从A移动到B
3、1~(N-1)从C移动到B,A为辅助(最终结果都是移动到B上,所以子问题形式与原问题相同)
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <cmath>
using namespace std;
#define MAX 100
/*汉诺塔*/
void Hanoi(int N, string from, string to, string help){
if(N == 1){
cout << "move " << N << " from " << from << " to " << to << endl;
return;
}
else{
Hanoi(N-1, from, help, to);
cout << "move " << N << " from " << from << " to " << to << endl;
Hanoi(N-1, help, to, from);
}
}
int main() {
Hanoi(5, "A", "B", "C");
}
算法性能分析:
递归关系:T(n) = 2T(b-1) + O(1)
结果:O(2^n)
【四】
二分查找的递归解法
三个子问题:
左边找
中间比
右边找
/*二分查找*/
int binarysearch(int arr[], int low, int high, int key){
if(low > high)
return -1;//未找到
int mid = low + ( (high - low) >> 1 );
int val = arr[mid];
if(key > val){
binarysearch(arr, mid+1, high, key);
}
else if(key < val){
binarysearch(arr, low, mid-1, key);
}
else{
return 1;//找到
}
}
【五】
希尔排序
一趟一个增量,每个增量对应于N/inerval组,每组内采用插入排序
/*希尔排序*/
void ShellSort(int arr[], int K){
int interval;//增量
//不断缩小增量
for(interval=K/2; interval>0; interval=interval/2){
//增量为interval的插入排序
int i;//i表示组
for(i=interval; i<K; i++){//遍历每一组
int x = arr[i];
int index = i - interval;
while(index>-1 && x < arr[index]){
/*将比当前元素大的数后挪interval位*/
arr[index + interval] = arr[index];
index -= interval;
}
/*元素k应在的位置*/
arr[index + interval] = x;
}
}
}
【六】
关于性能计算的知识