一、分治策略的概念
任何可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,解题所需的计算时间往往也越少,从而也较容易处理。例如,对于n个元素的排序问题,当n =1时,不需任何计算,n=2时,只要做一次比较即可排好序;n=3时只要进行两次比较即可;.....而当n较大时,问题就不那么容易处理了。要想直接解决一个较大的问题,有时是相当困难的。
分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。如果原问题可分割成k个子问题,1<k<=n,且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。由分治法产生的子问题往往是原问题的较小规模模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易求出其解。由此自然导致递归算法.
分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法
二、递归的概念
若一个函数直接地或间接地调用自己,则称这个函数是递归的函数(简单地描述为“自己调用自己”)
三、分治策略的特征
分治法所能解决的问题一般具有以下四个特征:
1.该问题的规模缩小到一定的程度就可以容易地解决
2.该问题可以分解为若千个规模较小的相同问题。
3.使用小规模的解,可以合并成,该问题原规模的解。
4.该问题所分解出的各个子规模是相互独立的。
分治法步骤:
分解 : 将问题划分成一些子问题,子问题的形式与原问题一样,只是规模更小。
解决:递归地求解子问题。如果子问题的规模足够小,则停止递归,直接求解
合并·将小规模的解组合成原规模问题的解
四、示例
1.输入一个整数(无符号整型) ,用递归算法将整数倒序输出分析:现在用递归过程的递推步骤中用求余运算将整数的各个位分离,并打印出来.
输入: 12345;
输出: 1 2 3 4 5 或者5 4 3 2 1
//非递归
void PrintInt1(size_t n)// size_t unsigned int
{
while (n != 0)
{
printf("%d ", n % 10);
n = n / 10;
}
}
//递归
void PrintInt2(size_t n)
{
if (n == 0)return;
else
printf("%d ", n % 10);
return PrintInt2(n / 10);
}
2.折半查找(二分查找)
非递归实现
int BinarySearch(const int* nums,int n,int key)//n为数组长度
{
int mid = 0;
int right = n - 1;
int pos = -1;
int left = 0;
while (left <= right)//小于相当于想、两指针正在逼近,等于说明找到了,只有left>right说明他俩岔开了就是没找到
{
mid = (left + right) / 2;
if (key > nums[mid])//比中间值大
{
left = mid + 1;//右半边找
}
else if (key < nums[mid])//比中间值小
{
right = mid - 1;//左半边找
}
else
{
pos = mid;
break;
}
}
return pos;
}
递归实现
int BinarySearch2(const int* nums, int left, int right,int key)
{
int pos = -1;
int mid = (left + right) / 2;
if (left <= right)
{
if (key < nums[mid])//比中间值小
{
return BinarySearch2(nums, left, mid - 1, key);//左半边找
}
else if (key >nums[mid])//比中间值小
{
return BinarySearch2(nums, mid + 1, right, key);//右半边找
}
else
{
pos = mid;
}
}
return pos;
}
3.折半查找找到最左key值
int LeftBinarySearch(const int* nums, int n, int key)//n为数组长度
{
int mid = 0;
int right = n - 1;
int pos = -1;
int left = 0;
while (left <= right)//小于相当于想、两指针正在逼近,等于说明找到了,只有left>right说明他俩岔开了就是没找到
{
mid = (left + right) / 2;
if (key > nums[mid])//比中间值大
{
left = mid + 1;//右半边找
}
else if (key < nums[mid])//比中间值小
{
right = mid - 1;//左半边找
}
else
{
while (left <= mid && nums[mid - 1] == key)
{
--mid;
}
pos = mid;
break;
}
}
return pos;
}
void main()
{
//PrintInt2(12345);
int nums[12] = { 12,23,23,23,23,56,67,78,89 };
int i = LeftBinarySearch(nums, 8,23);
printf("%d", i);
}
4.折半查找寻找第一个大于等于key值的元素
int FirstBinarySearch(const int* nums, int n, int key)
{
int left = 0;
int right = n - 1;
int mid = n/2;
int pos = -1;
while (left <= right)
{
if ( key <= nums[mid] )
{
right = mid-1;
mid = (left + right) / 2;
while (left <= mid && nums[mid - 1] >= key)
{
mid--;
}
pos = mid;
break;
}
else//(key>nums[mid])
{
left = mid + 1;
mid = (left + right) / 2;
}
}
return pos;
}
void main()
{
//PrintInt2(12345);
int nums[12] = { 1,12,23,34,45,56,78,89,90 };
int i = FirstBinarySearch(nums,9,55);
printf("%d", i);
}