文章目录
1. 递归算法
1.1 特点
1.2 优缺点
优点:结构清晰、可读性强
缺点:运行时效率较低,耗费较多的时间、空间资源
2. 分治策略
2.1 基本思想
分治策略的基本思想是将一个规模为n的问题分解为k个较小的子问题,这些子问题互相独立,并且和原问题相同,递归的求解这些子问题,然后将各个子问题的解合并到原问题的解。
2.2 适用的条件
(1)该问题的规模缩小到一定的程度就可以容易地解决;
(2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;
(3)利用该问题分解出的子问题的解可以合并为该问题的解;
(4)原问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
2.3 求解过程(步骤)
(1)分解:将原问题分解为若干个规模较小、相互独立、与原问题形式相同的子问题。
(2)解决:若子问题规模较小而容易解决则直接解决,否则递归地解各个子问题。
(3)合并:将各个子问题的解合并为原问题的解。
3. 典型算法案例
3.1 二分搜索
3.1.1 非递归实现
- 代码实现
/**
* 二分查找(非递归实现)
* @param a 数据
* @param x 待查找的元素
* @param n 数组长度
* @return 若查找到,用于带回元素的位置
*/
int BinarySearch(int a[], const int& x, int n){
int left = 0;
int right = n-1;
while (left <= right){
int middle = (left + right) / 2;
if (x==a[middle]) return middle; // 查找成功
if (x > a[middle]) left = middle+1; // x大于中间的值时,说明x位于数组的后半段,跟新left的值
else right = middle-1; // x小于中间的值时,说明x位于数组的前半段,跟新right的值
}
return -1; // 查找失败
}
需要先对数组data进行升序排序。
- 时间复杂度
2的k次方 > n,k为 int middle = (left + right) / 2;
执行的次数,因此T=O(log2n)。
3.1.1 递归实现
- 代码实现
/**
* 二分查找(递归实现)
* @param a 数据
* @param x 待查找值
* @param left 左指针
* @param right 右指针
* @return 返回key的下标
*/
int DGSearch(int a[], const int& x,int left, int right){
if (right < left) return -1; // 查找失败
int middle = (left + right) / 2; // 设置中间指针
if (x < a[middle]) DGSearch(a,x,left,middle-1); // x位于数组的前半段
else if (x > a[middle]) DGSearch(a,x,middle+1,right); // x位于数组后半段
else return middle; // 查找成功
}
- 时间复杂度
与非递归算法实现的时间复杂度相同。
3.2 棋盘覆盖问题
3.2.1 L型骨牌放置顺序
棋盘覆盖中,L型骨牌放置的顺序是先将原问题分割为相同类型的子问题,即让其他四分之三的也都各有一个被覆盖的格子。然后对这些子问题按照从左上、到右上、左下、右下的顺序,填充L型骨牌;当每到一个较小的正方形当中,就在中心放置L型骨牌,将原问题化简为四个相同类型的子问题,然后在进行子问题的填充,直到填充完毕。
3.2.2 时间复杂度
T(k) = O(4^k)。
3.3 快速排序
3.3.1 案例解释
- 方式一(i、j分次序向中间移动)
对(49,38,65,97,76,13,27,49)进行排序
- 方式二
i、j 同时向中间移动,j 找到小于基准值的就停下,i 找打大于基准值的就停下,然后将 i、j 相互交换,当 i = j 时,将该位置的值与基准值互换,然后递归的进行下去,知道左右子集均为 1 个元素。
该方式更高效。
3.3.2 复杂度分析
快速排序的时间主要耗费在划分操作上,对长度为n的区间进行划分,共需n-1次关键字的比较,时间复杂度为O(n)。
对n个记录进行快速排序的过程构成一棵递归树,在这样的递归树中,每一层至多对n个记录进行划分,所花时间为O(n)。
当初始排序数据正序或反序时,此时的递归树高度为n,快速排序呈现最坏情况,即最坏情况下的时间复杂度为O(n2);当初始排序数据随机分布,使每次分成的两个子区间中的记录个数大致相等,此时的递归树高度为log2n,快速排序呈现最好情况,即最好情况下的时间复杂度为O(nlog2n)。
- 最坏时间复杂度:O(n2)
- 最好时间复杂度:O(nlog2n)
- 平均时间复杂度:O(nlog2n)