第2讲 分治算法和二分搜索算法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
3
2 return Fib(1) + Fib(0) 1 1 return 1 return 1
1 return 1
n=4时,递归法进行了多 时 少次函数调用? 少次函数调用?
第2讲 分治法和二分搜索算法
本讲内容: 本讲内容: (1) 分治法的基本思想 (2) 二分搜索技术
4
分治法的基本思想
分治法的思想: 分而治之。将一个规模为n的问题分解为k 分治法的思想: 分而治之。将一个规模为n的问题分解为k个 规模较小的子问题,这些子问题互相独立且与原问题相同, 规模较小的子问题,这些子问题互相独立且与原问题相同, (如果子问题的规模仍然不够小,则再划分为k个子问题), 然 如果子问题的规模仍然不够小,则再划分为k个子问题), 后递归的求解这些子问题, 后递归的求解这些子问题,最后用适当的方法将各子问题的解 合并成原问题的解。 合并成原问题的解。 原问题(规模为 规模为n) 原问题 规模为 相同 类型
8
2-2 二分搜索算法
迭代法的程序代码
#include<stdio.h> #define N 10 // 符号常量定义,便于修改数组的大小 符号常量定义, int find(int a[ ], int x, int bott, int top);// 函数声明 ; void main( ) { int i, x, a[N], result; printf("\n 输入数组 a:\n"); for(i=0; i<N; i++) scanf("%d", &a[i]); printf(“输入要查找的数 x:"); 输入要查找的数 scanf("%d", &x); result=find(a, x, 0, N-1); // 函数调用 if (result== -1) printf("%d is not found.\n", x); else printf("Find %d==a[%d]\n", x, result); }
7
2-2 二分搜索算法
二分搜索实例:设在数组 中顺序放了以下 个元素: 二分搜索实例 设在数组a中顺序放了以下 个元素: 设在数组 中顺序放了以下9个元素 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
-15 -6
③ ②
0
③
7
④
9
①
23
54
②
82 101
③ ④
11
递归法的程序代码 int find(int a[ ], int x, int bott, int top) { int mid; if(bott<=top) { mid=(bott+top)/2; if(x==a[mid]) return mid; // 找到 ,返回 找到x,返回mid的值 的值 else if(x<a[mid]) 小则查找数组中较小的一半 return find(a,x,bott,mid-1); x小则查找数组中较小的一半 else return find(a,x,mid+1,top); x大则查找数组中较大的一半 大则查找数组中较大的一半 } return -1; // 没找到时返回 没找到时返回-1 }
Biblioteka Baidu
合 并 解
子问题1 子问题
子问题2
…
子问题k
子问题1 子问题2 子问题 子问题
… 子问题 子问题k
子问题1 子问题2 子问题 子问题
子问题1 子问题2 子问题 子问题
… 子问题k 子问题
… 子问题 子问题k
5
分治法的基本思想
分治法的适用条件 分治法所能解决的问题一般具有以下几个特征: 分治法所能解决的问题一般具有以下几个特征:
检索x=9, 9==a[4], 一次比较就成功 最好情况 一次比较就成功, 检索 检索x=-15, -15<a[4], -15<a[1], -15==a[0], 3次比较 成功 次比较, 检索 次比较 检索x=101, 101>a[4], 101>a[6], 101>a[7], 101==a[8], 检索 4次比较 成功 次比较, 次比较 检索x=8, 8<a[4], 8>a[1], 8>a[2], 8>a[3], 4次比较 不成功 次比较, 检索 次比较
9
2-2 二分搜索算法
迭代法的程序代码
int find(int a[ ], int x, int bott, int top) { int mid; // 满足条件时进行二分搜索 while(bott<=top) { mid=(bott+top)/2; // 计算中间位置的下标 if(x==a[mid]) // 若x等于 等于a[mid],表示找到 等于 , return(mid); // 找到 ,返回 找到x,返回mid的值 的值 else // x不等于 不等于a[mid]的情况 不等于 的情况 小则查找数组中较小的一半 if(x<a[mid]) // x小则查找数组中较小的一半 top=mid-1; else bott=mid+1; // x大则查找数组中较大的一半 大则查找数组中较大的一半 } return(-1); // 没找到时返回 没找到时返回-1 }
12
10
2-2 用递归函数实现二分搜索算法
分析:若使用递归算法, 分析:若使用递归算法,需要获得递归的终止条件和 递推关系
递归函数的终止条件: 递归函数的终止条件: 终止条件 1. 搜索成功,即x == a[mid],返回 mid 搜索成功, , 即 , 2. 搜索不成功, bott > top,返回 -1 搜索不成功, 递归函数的递推关系: 递归函数的递推关系: 递推关系 1. 如果 如果x>a[mid],bott = mid + 1,返回 find(a,x,bott,top) 返回find(a,x,mid+1,top) , 返回 , 2. 如果x<a[mid], 返回find(a,x,bott,mid-1) 如果 , 返回
2
2-1 递归法求Fibonacci数列
用递归法求Fibonacci数列 Fib(4) 数列 用递归法求 5 n=20时, 要进行 时 21891次递归调用 return Fib(3) + Fib(2) 次递归调用 3 return Fib(2) + Fib(1) 2 return Fib(1) + Fib(0) 1 1 return 1 return 1 讨论: 讨论 求Fibonacci数列的 数列的 迭代法和递归法谁好? 迭代法和递归法谁好?
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
-15
bott
-6
0
7
9
mid
23
54
82 101
top
二分搜索的步骤: 二分搜索的步骤: 1、确定三个关键下标的初值:bott=0, top=8, mid=(bott+top)/2; 、确定三个关键下标的初值: 2、判断要找的数 是否等于 是否等于a[mid] 、判断要找的数x是否等于 找到, ① x==a[mid] 找到,结束 之间继续查找x ② x<a[mid] 在a[bott]—a[mid-1]之间继续查找 之间继续查找 top=mid-1; mid=(bott+top)/2; 之间继续查找x ③ x>a[mid] 在a[mid+1]—a[top]之间继续查找 之间继续查找 bott=mid+1; mid=(bott+top)/2;
2-1 递归法求Fibonacci数列
Fibonacci数列 1, 1, 2, 3, 5, 8, 13… 数列: 数列
迭代法求Fibonacci数列的前 项 数列的前20项 迭代法求 数列的前
#include <stdio.h> 迭代法在已知数列前2项 迭代法在已知数列前 项 void main( ) 的基础上, 从第3项开始 项开始, 的基础上 从第 项开始 { int i , f1=1 , f2=1 , f3; 依次向后计算, 依次向后计算 得出数列 printf("%8d%8d", f1 , f2); 的每一项 for ( i=3 ; i<=20 ; i++ ) { f3=f1+f2; 思考: 思考:怎样用递 f1=f2; 归的方法求解? 归的方法求解? f2=f3; printf("%8d", f3); if ( i%4==0) putchar('\n'); } }
该问题的规模缩小到一定的程度就可以容易地解决 该问题可以分解为若干个规模较小的相同问题 该问题所分解出的各个子问题是相互独立的 利用分解出的子问题的解可以合并为该问题的解
6
2-2 二分搜索算法
前提条件:有一组数已经按从小到大 或从大到小 或从大到小)排序 前提条件:有一组数已经按从小到大(或从大到小 排序 目标:输入一个数x,在这组数查找是否有x 目标:输入一个数 ,在这组数查找是否有
1
2-1 递归法求Fibonacci数列
递归法求Fibonacci数列 数列 递归法求 定义Fibonacci数列的递归数学模型: 数列的递归数学模型: 定义 数列的递归数学模型 递归的终止条件
F(n)=
递归公式
1 F(n-1)+F(n-2)
n=0,1 n>1
int Fib(int n) { if (n<0) { printf("error!"); exit(0); } else if (n <= 1) return 1; else return Fib(n-1)+Fib(n-2); }
2 return Fib(1) + Fib(0) 1 1 return 1 return 1
1 return 1
n=4时,递归法进行了多 时 少次函数调用? 少次函数调用?
第2讲 分治法和二分搜索算法
本讲内容: 本讲内容: (1) 分治法的基本思想 (2) 二分搜索技术
4
分治法的基本思想
分治法的思想: 分而治之。将一个规模为n的问题分解为k 分治法的思想: 分而治之。将一个规模为n的问题分解为k个 规模较小的子问题,这些子问题互相独立且与原问题相同, 规模较小的子问题,这些子问题互相独立且与原问题相同, (如果子问题的规模仍然不够小,则再划分为k个子问题), 然 如果子问题的规模仍然不够小,则再划分为k个子问题), 后递归的求解这些子问题, 后递归的求解这些子问题,最后用适当的方法将各子问题的解 合并成原问题的解。 合并成原问题的解。 原问题(规模为 规模为n) 原问题 规模为 相同 类型
8
2-2 二分搜索算法
迭代法的程序代码
#include<stdio.h> #define N 10 // 符号常量定义,便于修改数组的大小 符号常量定义, int find(int a[ ], int x, int bott, int top);// 函数声明 ; void main( ) { int i, x, a[N], result; printf("\n 输入数组 a:\n"); for(i=0; i<N; i++) scanf("%d", &a[i]); printf(“输入要查找的数 x:"); 输入要查找的数 scanf("%d", &x); result=find(a, x, 0, N-1); // 函数调用 if (result== -1) printf("%d is not found.\n", x); else printf("Find %d==a[%d]\n", x, result); }
7
2-2 二分搜索算法
二分搜索实例:设在数组 中顺序放了以下 个元素: 二分搜索实例 设在数组a中顺序放了以下 个元素: 设在数组 中顺序放了以下9个元素 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
-15 -6
③ ②
0
③
7
④
9
①
23
54
②
82 101
③ ④
11
递归法的程序代码 int find(int a[ ], int x, int bott, int top) { int mid; if(bott<=top) { mid=(bott+top)/2; if(x==a[mid]) return mid; // 找到 ,返回 找到x,返回mid的值 的值 else if(x<a[mid]) 小则查找数组中较小的一半 return find(a,x,bott,mid-1); x小则查找数组中较小的一半 else return find(a,x,mid+1,top); x大则查找数组中较大的一半 大则查找数组中较大的一半 } return -1; // 没找到时返回 没找到时返回-1 }
Biblioteka Baidu
合 并 解
子问题1 子问题
子问题2
…
子问题k
子问题1 子问题2 子问题 子问题
… 子问题 子问题k
子问题1 子问题2 子问题 子问题
子问题1 子问题2 子问题 子问题
… 子问题k 子问题
… 子问题 子问题k
5
分治法的基本思想
分治法的适用条件 分治法所能解决的问题一般具有以下几个特征: 分治法所能解决的问题一般具有以下几个特征:
检索x=9, 9==a[4], 一次比较就成功 最好情况 一次比较就成功, 检索 检索x=-15, -15<a[4], -15<a[1], -15==a[0], 3次比较 成功 次比较, 检索 次比较 检索x=101, 101>a[4], 101>a[6], 101>a[7], 101==a[8], 检索 4次比较 成功 次比较, 次比较 检索x=8, 8<a[4], 8>a[1], 8>a[2], 8>a[3], 4次比较 不成功 次比较, 检索 次比较
9
2-2 二分搜索算法
迭代法的程序代码
int find(int a[ ], int x, int bott, int top) { int mid; // 满足条件时进行二分搜索 while(bott<=top) { mid=(bott+top)/2; // 计算中间位置的下标 if(x==a[mid]) // 若x等于 等于a[mid],表示找到 等于 , return(mid); // 找到 ,返回 找到x,返回mid的值 的值 else // x不等于 不等于a[mid]的情况 不等于 的情况 小则查找数组中较小的一半 if(x<a[mid]) // x小则查找数组中较小的一半 top=mid-1; else bott=mid+1; // x大则查找数组中较大的一半 大则查找数组中较大的一半 } return(-1); // 没找到时返回 没找到时返回-1 }
12
10
2-2 用递归函数实现二分搜索算法
分析:若使用递归算法, 分析:若使用递归算法,需要获得递归的终止条件和 递推关系
递归函数的终止条件: 递归函数的终止条件: 终止条件 1. 搜索成功,即x == a[mid],返回 mid 搜索成功, , 即 , 2. 搜索不成功, bott > top,返回 -1 搜索不成功, 递归函数的递推关系: 递归函数的递推关系: 递推关系 1. 如果 如果x>a[mid],bott = mid + 1,返回 find(a,x,bott,top) 返回find(a,x,mid+1,top) , 返回 , 2. 如果x<a[mid], 返回find(a,x,bott,mid-1) 如果 , 返回
2
2-1 递归法求Fibonacci数列
用递归法求Fibonacci数列 Fib(4) 数列 用递归法求 5 n=20时, 要进行 时 21891次递归调用 return Fib(3) + Fib(2) 次递归调用 3 return Fib(2) + Fib(1) 2 return Fib(1) + Fib(0) 1 1 return 1 return 1 讨论: 讨论 求Fibonacci数列的 数列的 迭代法和递归法谁好? 迭代法和递归法谁好?
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
-15
bott
-6
0
7
9
mid
23
54
82 101
top
二分搜索的步骤: 二分搜索的步骤: 1、确定三个关键下标的初值:bott=0, top=8, mid=(bott+top)/2; 、确定三个关键下标的初值: 2、判断要找的数 是否等于 是否等于a[mid] 、判断要找的数x是否等于 找到, ① x==a[mid] 找到,结束 之间继续查找x ② x<a[mid] 在a[bott]—a[mid-1]之间继续查找 之间继续查找 top=mid-1; mid=(bott+top)/2; 之间继续查找x ③ x>a[mid] 在a[mid+1]—a[top]之间继续查找 之间继续查找 bott=mid+1; mid=(bott+top)/2;
2-1 递归法求Fibonacci数列
Fibonacci数列 1, 1, 2, 3, 5, 8, 13… 数列: 数列
迭代法求Fibonacci数列的前 项 数列的前20项 迭代法求 数列的前
#include <stdio.h> 迭代法在已知数列前2项 迭代法在已知数列前 项 void main( ) 的基础上, 从第3项开始 项开始, 的基础上 从第 项开始 { int i , f1=1 , f2=1 , f3; 依次向后计算, 依次向后计算 得出数列 printf("%8d%8d", f1 , f2); 的每一项 for ( i=3 ; i<=20 ; i++ ) { f3=f1+f2; 思考: 思考:怎样用递 f1=f2; 归的方法求解? 归的方法求解? f2=f3; printf("%8d", f3); if ( i%4==0) putchar('\n'); } }
该问题的规模缩小到一定的程度就可以容易地解决 该问题可以分解为若干个规模较小的相同问题 该问题所分解出的各个子问题是相互独立的 利用分解出的子问题的解可以合并为该问题的解
6
2-2 二分搜索算法
前提条件:有一组数已经按从小到大 或从大到小 或从大到小)排序 前提条件:有一组数已经按从小到大(或从大到小 排序 目标:输入一个数x,在这组数查找是否有x 目标:输入一个数 ,在这组数查找是否有
1
2-1 递归法求Fibonacci数列
递归法求Fibonacci数列 数列 递归法求 定义Fibonacci数列的递归数学模型: 数列的递归数学模型: 定义 数列的递归数学模型 递归的终止条件
F(n)=
递归公式
1 F(n-1)+F(n-2)
n=0,1 n>1
int Fib(int n) { if (n<0) { printf("error!"); exit(0); } else if (n <= 1) return 1; else return Fib(n-1)+Fib(n-2); }