`

算法分析之分治法总结(二)

阅读更多
3)分类和合并同时进行
典型事例 快速排序:(以整数类型为例)
快速排序的思想是,对于输入,按照以下二个步骤进行排序
对于数组a[p:r]
1)分解(其实包括合并过程):以a[p]为基准将数组分成三段a[p:q-1]、a[q]、a[q+1:r]使得a[p:q-1]中的任意元素都小于等于a[q],a[q+1:r]中的任意元素都大于等于a[q].
2)递归求解:通过递归调用快速排序,分别完成a[p:q-1]和a[q+1:r]的排序。
程序代码:
int partition(int a[],int p,int r)
{
 int i=p,j=r+1,x=a[p],temp;
 while(true)
 {
  while(x>a[i]){++i;}
  while(x<a[j]){--j;}
     if(i>=j) break;
  temp=a[i];
  a[i]=a[j];
  a[j]=temp;
 }
 a[p]=a[j];
 a[j]=x;
 return j;
}
void QuickSort(int a[],int p,int r)
{
 if(p < r)
 {
  int q=partition(a,p,r);
  QuickSort(a,p,q-1);
  QuickSort(a,q+1,r);
 }
}

与QuickSort类似的例子是选择问题:
我们经常遇到的选择问题是选择最大元素和最小元素的问题,这个问题解决起来比较容易,而且时间复杂度为O(n),但是当我们把这个问题一般化的时候,既选择第k小(大)的元素的时候,思考一下,最容易想到的方法是排一下序,第k个 位置就是第k小的元素,在想一想可以找一些能够在每一次能够确定一个元素的最终位置的排序方法(如冒泡法,直接选择排序法等)只需要排好k(k<=n/2时)个的元素或者n-k(k>n/2),但是这样的话其实时间复杂性仍然是O(n^2),比找最大和最小所用的时间复杂度大的多。如果采用QuickSort算法其时间复杂度为O(nlogn),对于排序的确是个非常好的算法,但是我们想QuickSort是把所有的元素都排好的时间复杂度,我们找第k小的元素,从感性上也可以知道这是比排序要简单的问题,但是找第k小的元素,k本身就是个序号问题,如果不排序似乎解决不了这个问题。似乎有一个简单的情形会给我们以启发:我们在桌子上摆了一副扑克,我们规定了各个扑克的大小,现在是找第k小的元素,人或许很容易看出,但计算机似乎有点困难,那就找个就简单的方法吧---瞢,瞢当然不是瞎瞢,瞢错了你可以去掉一些不符和条件的扑克,例如瞢到了一张红桃k,现在好办了,把比红桃k小的扑克数一数,如果小于k-1,那好把红桃k和那些扑克仍在一边,如果等于k-1,恭喜你,瞢对了,否则,把其他的扑克和k仍在一边。对剩余的扑克继续重复上述过程(当然这是k应适当的变化一下)。其实我们发现上述过程如果不是运气特差的话,一次就能够扔掉不少扑克牌。
其算法如下:
//搜索第k小的元素
int partition(int a[],int p,int r)//分化
{
 int i=p,j=r+1,x=a[p],temp;
 while(true)
 {
  while(x>a[i]){++i;}
  while(x<a[j]){--j;}
     if(i>=j) break;
  temp=a[i];
  a[i]=a[j];
  a[j]=temp;
 }
 a[p]=a[j];
 a[j]=x;
 return j;
}
int SelectK(int a[],int p,int n,int k)//选择
{
 int q,i;
    q=partition(a,p,n);
 i=q-p+1;
 if(i<k)
      return SelectK(a,q+1,n,k-i);
 else if(i==k)
   return a[q];
 else
   return SelectK(a,p,q-1,k);
}


//上述的算法当然不是优化之后的算法,虽然这个算法最坏情况下仍然是O(n^2),但平均复杂度只是o(n),虽然改进后的的算法在最坏的情况下时间复杂度线性的T(n)<=72c1n,即nlog(10^72)这个算法显然在实际上已经没有什么应用的价值,只有理论价值,因为当数据的规模在比10^72这个数量大的时候,他的速度才会超过快速排序的最坏结果。下面是改进后的算法(线性搜索)的思路.考虑上面程序算法最坏的情况在什么时候发生?当每一次你选择的元素都离你要选择的基准元素相差最远的时候。改进算法就是为了不至于每次都遇到这么差的运气,所以他在选择分化基准元素的时候,他尽量选择大小在中间大小的元素,因为这样在平均的情况下效率挺高,一次就扔掉一半,在最坏的情况下也不会很坏。所以在partition之前要在n个元素中选择中间元素,这当然也是个很难简单就解决的问题,所以不一定真的是最中间的,大体上差不多就行了,因为这样远远比最中间的元素的时间复杂度小得多。算法的步骤如下:
1)将参加划分的n个元素分成[n/r]组(r>1),每组有r个元素,将n-r[n/r]的元素扔掉,然后对每一组的元素找出中间的元素,然后再从中间元素选择中间元素,这样的元素已经满足我们的要求了,虽然不一定是真正的中间元素。二次取中间值的方法复杂度是o(n)数量级的。其他的就和上面没改进的算法步骤一样了,不再详述。
分治法作为一种算法思想和前人总结的经验,关键是理解其算法的思想,不同的题难度不一,应具体问题具体分析。
分享到:
评论

相关推荐

    第十讲 分治法总结

    第十讲 分治法总结.ppt 算法分析与设计

    算法分析与设计实验报告-分治法.docx

    【分治算法】是计算机科学中一种重要的算法思想,它将一个大...总结来说,本实验报告通过实例详细介绍了分治法在快速排序算法中的应用,包括算法的设计、分析以及具体的C++实现,展示了分治策略如何有效解决复杂问题。

    算法分析 2.3快速排序 分治法

    归并排序也是基于分治法的排序算法,但与快速排序不同的是,它不是通过交换元素来实现排序,而是通过合并已排序的子数组来达到目的。归并排序的过程如下: 1. **分割**:将原始数组分为两个或更多个子数组,每个子...

    《算法设计与分析》实验报告:实验一(分治策略)

    总结来说,这个实验报告着重于理解和应用分治策略,通过实现二分搜索、合并排序和快速排序等算法,以及探索阶乘计算的不同方法,加深了对分治算法设计和分析的理解。同时,通过实验数据分析,进一步掌握了算法效率的...

    计算机算法分析 二分查找 分治算法

    **二分查找与分治算法详解** 二分查找是一种基于分治策略的高效搜索算法,主要应用于有序数据集合。在给定的升序排列的数组a[0:n-1]中,二分查找的目标是找到特定元素x的位置,或者确认元素不在数组中。算法的基本...

    分治法求两个大整数相乘

    这种方法有效地解决了大整数乘法问题,同时也展示了分治法的强大之处。 #### 六、总结 通过分治法实现大整数的乘法是一种高效的方法,尤其适用于处理超出标准整型变量范围的大整数运算。本文介绍了分治法的基本...

    算法分析- 分治.ppt

    对于满足分治法适用条件的问题,如排序(如归并排序)、查找(如二分查找)和矩阵乘法等,分治法是一种高效的方法。然而,对于子问题之间存在依赖的情况,分治法可能不是最佳选择,这时可以考虑使用贪心算法或动态...

    算法设计与分析 汉诺塔 分治法

    汉诺塔问题是一种经典的递归问题,它使用了分治法...总结来说,这个题目涵盖了分治法在解决汉诺塔问题、计算阶乘以及排序算法中的应用。通过理解和实践这些算法,我们可以更好地掌握分治法的精髓,提高解决问题的能力。

    分治法求解序列最大最小元素【算法设计与分析】

    此外,分治法还可以应用于许多其他领域,如排序(快速排序、归并排序)、查找(二分查找)、矩阵乘法(Strassen算法)、大整数乘法(Karatsuba算法)等。它提供了一种通用的解决问题的方法论,对于学习和理解算法...

    分治法求众数.doc

    总结一下,本实验通过分治法和快速排序的启发,设计了一个高效的求解众数的算法。它避免了完全排序,减少了时间复杂度,同时利用递归策略缩小搜索范围,提高了算法效率。在实际编程中,这种思想可以广泛应用于解决...

    算法与分析实验一:分治与递归

    实验总结指出,通过此次实验,对分治法的理解得到了加深,尤其是在问题划分和二维数组的使用上有了更直观的认识。然而,实验也暴露出在算法推导方面的不足,需要进一步提升对算法逻辑的熟练度和速度,以提高未来解决...

    分治法的应用

    分治法的应用范围非常广泛,尤其是在计算机科学领域,包括但不限于排序算法(如快速排序)、查找算法(如二分查找)以及其他一些重要的计算问题。 #### 二、分治法的基本思想 对于任何可以用计算机求解的问题,其...

    分治法实现最近对问题

    分治法是一种将复杂问题分解成较小的子问题来求解的算法策略。这些子问题通常与原问题属于同一类型,且规模较小。分治法的核心思想包括三个步骤: 1. **分解**:将原问题分解为若干个规模较小的相同问题。 2. **解决...

    分治法旋转数组

    在计算机科学中,分治法被广泛应用于排序算法(如快速排序)、查找算法(如二分查找)以及许多其他算法设计中。 #### 二、旋转数组问题背景 旋转数组通常是指将一个一维数组按照一定的规则进行旋转操作后得到的...

    分治法程序代码

    根据给定的信息,我们可以了解到这段程序是关于分治法中的归并排序算法的实现。下面,我们将基于这个程序代码来详细解析与分治法相关的知识点。 ### 分治法概述 分治法是一种重要的算法设计思想,它将一个复杂的...

    算法设计与分析(用分治法求解棋盘覆盖问题)

    **算法设计与分析——棋盘覆盖问题的分治法求解** 在计算机科学中,算法设计与分析是核心部分,它涉及到如何有效地解决问题并优化计算效率。本篇将重点探讨如何利用分治策略来解决棋盘覆盖问题。棋盘覆盖问题是一个...

    分治法-中位数

    分治法是一种重要的算法设计思想,其核心在于将一个复杂的问题分解成若干个规模较小但结构相似的子问题,然后递归地解决这些子问题,并将各个子问题的解组合起来得到原问题的解。分治法在很多情况下都能达到较高的...

    分治法求最大值的C++实现

    在计算机科学领域,分治法(Divide and Conquer)是一种高效的...掌握分治法的基本原理和应用,对于理解和设计高效的算法至关重要。通过深入学习和实践,我们可以更好地应对各种编程挑战,特别是在处理大规模数据集时。

Global site tag (gtag.js) - Google Analytics