数据结构与算法之分治法

这篇具有很好参考价值的文章主要介绍了数据结构与算法之分治法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

分治法首先需要明白递归的概念:

递归: 是指子程序直接调用自己或者通过一系列调用语句间接调用自己,是一种描述问题和解决问题的常用方法。递归的两个基本要素:
1.边界条件:也就是递归终止调用的条件。
2.递归出口:递归表达式,大问题分解为小问题。

分治算法的一般有几个步骤:

  1. 分解 :分析原来的问题,将原问题分解成一系列子问题。
  2. 求解:递归求解各个子问题。若子问题足够小,则直接求解。
  3. 合并:将子问题的解合并成原问题的解。

以下将分析几个典型例子。

1.递归解决阶乘函数

阶乘函数的定义大家都知道。
1)边界条件 n=0,n!=1
2) 递归体 n>0,n!=n*(n-1)

C语言代码:

/**
 1. 阶乘的算法
 2. @param n
 3. @return
 */
int Fac(int n){
    if(n==0)
        return 1;
    else
        return n* Fac(n-1);
}

数据结构与算法之分治法,数据结构与算法,算法,排序算法,数据结构

2.归并排序算法

2.1 归并排序的概念

归并排序是将待排序的元素分成两个大致相同的两个子序列,分别对子序列进行排序,最终将排好序的子序列合并为排序的序列。

2.2 分治法的三步曲

大致分为以下几步:

  1. 分解。将n个元素分成n/2个元素的子序列。
  2. 求解。用归并排序对两个子序列递归排序。
  3. 合并。合并两个排序好的子序列得到排序结果。

2.3 归并排序的动画

数据结构与算法之分治法,数据结构与算法,算法,排序算法,数据结构

2.4 归并排序算法(C语言代码)

/**
 * 归并排序
 * @param a 待排序的数组
 * @param l 左边的
 * @param r 右端
 */
void MergeSort(int a[],int l, int r){
    //计算分组的中间位置
    int m;
    if (l < r){
        //计算中间的位置
        m = (l+r)/2;
        //递归左边
        MergeSort(a,l,m);
        //递归右边
        MergeSort(a,m+1,r);
        //合并结果
        Merge(a,l,m,r);
    }
}
/**
 * 合并排序的结果
 * @param a
 * @param l
 * @param m
 * @param r
 */
void Merge(int a[], int l, int m, int r) {
    //左边的长度,定义右边的长度
    int lLen=m-l+1 ,rLen=r-m;
    //定义临时数组存放左边的排序结果以及右边的排序结果
    int L[50],R[50];
    //取出左边的元素
    for(int i=0 ; i < lLen ; i++){
       L[i]=a[l+i];
    }
    //取出右边的元素
    for(int j = 0 ; j < rLen; j++){
        R[j]=a[m+j+1];
    }
    //很关键,这个值一定要设置为最大
    L[lLen] = INT_MAX;
    R[rLen] = INT_MAX;
    //开始比较大小
    int i=0,j=0;
    for(int k = l; k < r+1 ; k++){
        if(L[i] < R[j]){
            a[k]=L[i];
            i++;
        }else{
            a[k]=R[j];
            j++;
        }
    }
}

测试代码:
数据结构与算法之分治法,数据结构与算法,算法,排序算法,数据结构

3.最大子序列和问题

3.1 问题的定义

给定n个整型数组组成的蓄力A1,A2,…An,求该序列中子序列的字段和的最大值,当所有序列所有的整型均为负数整数时,其最大字段和为0。
example:
当序号为[-2,6,-4,8,-5,3]时,最大子序列的和为10=6+(-4)+8。

3.2 分治的思路

普通的计算,只有循环遍历所有的子段求和进行比较求解,这样的时间复杂度比较高,这种也就是暴力算法解题的思路,第一遍单个元素作为和比较,得出最大和为8,第二次遍历两个连续元素的组合,第三次遍历三个元素的组合,第四次组合…比较简单,这里不在代码。

  1. 分解。将序列拆分为n个子序列,最大值分为三种情况,所有序列的和分为三种情况。
    (1) 所有序列的的最大字段和在序列的1/2序列左边的和相同。
    (2) 所有序列的的最大字段和在序列的1/2序列右边的和相同。
    (3) 所有序列的的最大字段和在序列的1/2序列左和右边的和相同

  2. 求解。
    递归分段求解1/2字段和。由于序列是连续的,此问题的关键在于求和的时候从1/2向两边扩展求和,这样就能包含前两种情况,第三种情况是从中间1/2处左右两边子序列和的最大值。

  3. 合并。最终的结果就是三个情况的和最大结果。

3.3 简单的分解下代码的结果

以序列[-2,6,-4,8,-5,3]为例。
数据结构与算法之分治法,数据结构与算法,算法,排序算法,数据结构
此处写比较费劲,看代码输出。

3.4 算法代码

/**
 * 打印数组
 * @param a
 * @param left
 * @param right
 */
void printArr(int *a,int left,int right){
    for (int i = left; i <= right ; ++i) {
        printf("%d,",a[i]);
    }
    printf("\n");
}
/**
 * 求解最大的字段序列和
 * @param a
 * @param left
 * @param right
 * @return
 */
int MaxSubSeqSum(int * a,int left,int right){
    int sum = 0 ;
    int i;
    //遍历到单个元素
    if(left == right){
        if(a[left]>0)  sum=a[left];
        else sum=0;
    }else{
        //循环遍历
        int med=(left+right)/2;
        int leftSum= MaxSubSeqSum(a,left,med);
        int rightSum= MaxSubSeqSum(a,med+1,right);
        //计算左边的序列的字段和
        int subLeftSum=0,s1=0;
        printArr(a,left,med);

        for ( i = med; i >=left ; i--) {
            subLeftSum+=a[i];
            if (subLeftSum > s1) s1=subLeftSum;
        }
        printf("the left sum is %d",subLeftSum);
        printf("\n");
        //计算右边的序列的字段和
        printArr(a,med,right);
        int subRightSum=0,s2=0;
        for (i = med+1; i <= right  ; i++) {
            subRightSum+=a[i];
            if (subRightSum > s2) s2=subRightSum;
        }
        printf("the right sum is %d",subRightSum);
        printf("\n");
        //左右两边之和
        sum=s1+s2;
        if(sum < leftSum) sum=leftSum;
        if(sum < rightSum) sum=rightSum;
    }
    return sum;
}

3.5 测试结果

int main(){
    int a[] = {-2,6,-4,8,-5,3};
    int result= MaxSubSeqSum(a,0,5);
    printf("the final result is :%d",result);
}

代码执行递归过程。文章来源地址https://www.toymoban.com/news/detail-709519.html

-2,
the left sum is -2 
-2,6,
the right sum is 6 
-2,6,
the left sum is 4  
6,-4,
the right sum is -4
8,
the left sum is 8  
8,-5,
the right sum is -5
8,-5,
the left sum is 3  
-5,3,
the right sum is 3 
-2,6,-4,
the left sum is 0 
-4,8,-5,3,        
the right sum is 6
the final result is :10

到了这里,关于数据结构与算法之分治法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构和算法笔记4:排序算法-归并排序

    归并排序算法完全遵循分治模式。直观上其操作如下: 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。 解决:使用归并排序递归地排序两个子序列。 合并:合并两个已排序的子序列以产生已排序的答案。 我们直接来看例子理解算法的过程,下面是要排序

    2024年01月21日
    浏览(62)
  • 【数据结构与算法】十大经典排序算法-希尔排序

    🌟 个人博客: www.hellocode.top 🏰 Java知识导航: Java-Navigate 🔥 CSDN: HelloCode. 🌞 知乎 :HelloCode 🌴 掘金 :HelloCode ⚡如有问题,欢迎指正,一起学习~~ 希尔排序是一种插入排序的改进版本,旨在解决插入排序在处理大规模数据时的效率问题。通过将数组分为多个子序列并对

    2024年02月12日
    浏览(75)
  • 【数据结构与算法】十大经典排序算法-插入排序

    🌟 个人博客: www.hellocode.top 🏰 Java知识导航: Java-Navigate 🔥 CSDN: HelloCode. 🌞 知乎 :HelloCode 🌴 掘金 :HelloCode ⚡如有问题,欢迎指正,一起学习~~ 插入排序(Insertion Sort)是一种简单直观的排序算法,其基本思想是将一个记录插入到已排好序的有序序列中,直到所有记录

    2024年02月13日
    浏览(80)
  • 【数据结构与算法】十大经典排序算法-冒泡排序

    🌟 个人博客: www.hellocode.top 🏰 Java知识导航: Java-Navigate 🔥 CSDN: HelloCode. 🌴 掘金 :HelloCode 🌞 知乎 :HelloCode ⚡如有问题,欢迎指正,一起学习~~ 冒泡排序(Bubble Sort)是一种简单的排序算法,它通过重复地交换相邻元素的位置来将最大(或最小)的元素逐步“冒泡”到

    2024年02月14日
    浏览(69)
  • 【数据结构与算法】十大经典排序算法-快速排序

    🌟 个人博客: www.hellocode.top 🏰 Java知识导航: Java-Navigate 🔥 CSDN: HelloCode. 🌞 知乎 :HelloCode 🌴 掘金 :HelloCode ⚡如有问题,欢迎指正,一起学习~~ 快速排序(Quick Sort)是一种高效的排序算法,是对冒泡排序的优化。它采用分治法(Divide and Conquer)的思想,将待排序序列

    2024年02月13日
    浏览(62)
  • 数据结构——排序算法之快速排序

        个人主页: 日刷百题 系列专栏 : 〖C/C++小游戏〗 〖Linux〗 〖数据结构〗   〖C语言〗 🌎 欢迎各位 → 点赞 👍+ 收藏 ⭐️+ 留言 📝  ​ ​ 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法。 基本思想: 任取待排序元素序列中 的某元素作为基准值,按照

    2024年01月21日
    浏览(54)
  • 【数据结构与算法】排序算法(选择排序,冒泡排序,插入排序,希尔排序)

    基本概念这了就不浪费时间解释了,这四种都是很简单的排序方式,本专栏后续文章会出归并排序,计数排序,快速排序,堆排序,桶排序等排序算法,今天这篇文章中给出选择排序,冒泡排序,插入排序和希尔排序的实现; 如果发现文章中有错误,还请大家指出来,我会非

    2024年02月15日
    浏览(81)
  • 数据结构与算法-排序算法

    递归将整个函数的调用过程 调用过程 如何在CSDN博客中插入公式和各种符号 类似二叉树的后续遍历 递归行为和递归行为时间复杂度的估算 master 公式 : T ( n ) = a × T ( n b ) + O ( n d ) T(n) = a times T (frac{n}{b}) + O(n^d) T ( n ) = a × T ( b n ​ ) + O ( n d ) T ( n ) T(n) T ( n ) : 母问题的规模

    2024年02月15日
    浏览(51)
  • 算法 数据结构 递归插入排序 java插入排序 递归求解插入排序算法 如何用递归写插入排序 插入排序动图 插入排序优化 数据结构(十)

    1. 插入排序(insertion-sort):                                           是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入     算法稳定性:                  

    2024年02月09日
    浏览(53)
  • 数据结构算法练习 插入排序 冒泡排序

    插入排序 代码如下  package main import \\\"fmt\\\" func main() {     a := []int{4, 5, 6, 1, 3, 2}         b := insert(a)     for i := 0; i len(b); i++ {         fmt.Println(b[i])     } } func insert(a []int) []int {     if len(a) = 1 {                   如果数组长度小于等于1 不用排序直接返回          retur

    2024年02月08日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包