算法分析与设计—分治法

news2024/11/20 0:22:22

分治者,分而治之也。

概述

分治法也称为分解法、分治策略等。分治法算法思想如下:

(1) 将一个问题划分为同一类型的若干子问题,子问题最好规模相同。

(2) 对这些子问题求解(一般使用递归方法,但在问题规模足够小时,有时也会利用另一个算法)。

(3) 有必要的话,合并这些子问题的解,以得到原始问题的答案。

当子问题足够大时,需要递归求解时,我们称之为递归情况(Recursive Case)。当子问题变得足够小,不再需要递归时,表示递归已经“触底”,进入了基本情况(Base Case)。

递归式与分治方法紧密相关。因为使用递归式可以很自然地刻画分治算法的运行时间。一个递归式(Recurrence)就是一个等式或不等式,它通过更小的输入上的函数值来描述一个函数。如使用递归式表示归并排序(Merge Sort)的最坏运行时间 T ( n ) T(n) T(n):

T ( n ) = O ( 1 ) ( n = 1 ) T(n) = O(1) (n=1) T(n)=O(1)(n=1)

T ( n ) = 2 T ( n / 2 ) + O ( n ) ( n > 1 ) T(n) = 2T(n/2) + O(n) (n>1) T(n)=2T(n/2)+O(n)(n>1)

递归与分治

递归的定义:

程序调用自身的编程技巧称为递归。递归做为一种算法在程序设计语言中广泛应用。

一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。边界条件与递归方程是递归函数的两个要素,递归函数只有具备了这两个要素,才能在有限次计算后得出结果。

例如:计算阶乘

#include<iostream>
using namespace std;
int factorial(int n) {
    if(n==0) return 1;
    else return n*factorial(n-1);
} 
int main(){
    cout<<factorial(5)<<endl;
}

汉诺塔问题

汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

思路:

1.将n-1个碟子从A杆经C杆移动到B杆 2.将A杆上的第n个碟子移动到C杆 3.将n-1个碟子从B杆经A杆移动到C杆

算法分析

当n=1时             T(n)=1

当n>1时 T(n)=2T(n-1)+1

代码实现

#include <stdio.h>
#include <stdlib.h>
 
static int count = -1;
 
void move(char x,char y);      // 对move函数的声明 
void hanoi(int n,char one,char two,char three) ;//对hanoi函数的声明
int main()
{          
    int m;
    printf("请输入一共有多少个板子需要移动:");
    scanf("%d",&m);
    printf("以下是%d个板子的移动方案:\n",m);
    hanoi(m,'A','B','C');
    system("pause");
    return 0;
}
 
void hanoi(int n,char one,char two,char three)  // 定义hanoi函数  
// 将n个盘从one座借助two座,移到three座 
{
    
    if(n==1)
        move(one,three);
    else
    {
        hanoi(n-1,one,three,two);  //首先把n-1个从one移动到two
        move(one,three);//然后把最后一个n从one移动到three
        hanoi(n-1,two,one,three); //最后再把n-1个从two移动到three
    }
} 
void move(char x,char y)  //  定义move函数 
{
    count++;
    if( !(count%5) )
        printf("\n");
    printf("%c移动至%c  ",x,y);
}

成果图片

排序问题中的分治法

归并排序

  归并排序(Merge Sort)是建立在归并操作上的一种既有效又稳定的排序算法,该算法是采用
分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的
序列。即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二
路归并。

步骤

  1. 划分:将待排序的序列从中间划分为两个长度相同的子序列

  1. 求解子问题:分别对两个子序列进行排序,得到两个有序的子序列

  1. 合并:将两个有序子序列合并成一个有序序列

图解

算法

输入:待排序数组r[n],待排序区间[s,t]

输出:升序序列r[s]-r[t]

  1. 如果s等于t,则待排序区间只有一个记录,算法结束

  1. 计算划分的位置:m=(s+t)/2;

  1. 对前半个子序列 r[s]~r[m]进行升序排列;

  1. 对后半个子序列 r[m+1]~[t]进行升序排列;

  1. 合并两个升序序列 r[s]~r[m]和r[m+1]~r[t];

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
void merge(int* a, int low, int mid, int hight)  //合并函数
{
    int* b = new int[hight - low + 1];  //用 new 申请一个辅助函数
    int i = low, j = mid + 1, k = 0;    // k为 b 数组的小标
    while (i <= mid && j <= hight)  
    {
        if (a[i] <= a[j])
        {
            b[k++] = a[i++];  //按从小到大存放在 b 数组里面
        }
        else
        {
            b[k++] = a[j++];
        }
    }
    while (i <= mid)  // j 序列结束,将剩余的 i 序列补充在 b 数组中 
    {
        b[k++] = a[i++];
    }
    while (j <= hight)// i 序列结束,将剩余的 j 序列补充在 b 数组中 
    {
        b[k++] = a[j++];
    }
    k = 0;  //从小标为 0 开始传送
    for (int i = low; i <= hight; i++)  //将 b 数组的值传递给数组 a
    {
        a[i] = b[k++];
    }
    delete[]b;     // 辅助数组用完后,将其的空间进行释放(销毁)
}
void mergesort(int* a, int low, int hight) //归并排序
{
    if (low < hight)
    {
        int mid = (low + hight) / 2;
        mergesort(a, low, mid);          //对 a[low,mid]进行排序
        mergesort(a, mid + 1, hight);    //对 a[mid+1,hight]进行排序
        merge(a, low, mid, hight);       //进行合并操作
    }
}
int main()
{
    int n, a[100];
    cout << "请输入数列中的元素个数 n 为:" << endl;
    cin >> n;
    cout << "请依次输入数列中的元素:" << endl;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    mergesort(a, 0, n-1);
    cout << "归并排序结果" << endl;
    for (int i = 0; i < n; i++)
    {
        cout << a[i] << " ";
    }
    cout << endl;
    return 0;
}

快速排序

快速排序是对冒泡排序的一种改进。基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

首先用数组的第一个数作为枢轴,然后将所有比它小的数都放到它的位置之前,所有比它大的数都放到它的位置之后,由此可以该“枢轴“记录最后所落的位置i作为分界线,将序列分割成两个子序列。这个过程称为一趟快速排序。

步骤

  1. 划分:选定一个记录作为轴值,以轴值为基准将整个序列分为两个子序列,左侧数小于轴值,右侧大于

  1. 求解子问题:对每一个子序列进行递归处理

  1. 合并:对于子序列的排序是就地进行,不需要任何操作

代码

void quickSort(int left, int right, vector<int>& arr)
{
    if(left >= right)
        return;
    int i, j, base, temp;
    i = left, j = right;
    base = arr[left];  //取最左边的数为基准数
    while (i < j)
    {
        while (arr[j] >= base && i < j)
            j--;
        while (arr[i] <= base && i < j)
            i++;
        if(i < j)
        {
            temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    //基准数归位
    arr[left] = arr[i];
    arr[i] = base;
    quickSort(left, i - 1, arr);//递归左边
    quickSort(i + 1, right, arr);//递归右边
}

算法分析

最好情况下,每次划分对一个记录定位后,该记录的左侧子序列与右侧子序列的长度相同。在具有 n 个记录的序列中,一次划分需要对整个待划分序列扫描一遍,所需时间为 O(n),则有:

T(n)=2T(n/2)+n

=2(2T(n/4)+n/2)+n=4T(n/4)+2n-4(2T(n/8)+n/4)+2n =8T(n/8)+3n

=nT(1)+nlog2n =O(nlog2n)

最坏情况下,待排序记录序列正序或逆序,每次划分只得到一个比上一次划分少一个记录的子序列(另一个子序列为空)。此时,必须经过 n-1 次递归调用才能把所有记录定位,而且第,趟划分需要经过n一次比较才能找到第个记录的位置,因此,时间复杂度为:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/418828.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

fileinclude(通过cookie赋值的文件包含)

打开链接&#xff0c;提示flag在flag.php里 内容里还有一个路径/var/www/html/index.php&#xff0c;猜测flag.php应该也是在这个路径下 Ctrlu查看网页源码 代码中发现 include($lan.".php"); 可知这里存在文件包 且包含与lan的值有关 由代码 $lan $_COOKIE[lang…

安装kafka及一些命令

1&#xff0c;先把压缩包放到/opt/install目录下 2&#xff0c;解压&#xff0c;更名 解压&#xff1a;[rootsiwen install]# tar -zxf kafka_2.12-2.8.0.tgz -C ../soft 更名&#xff1a;[rootsiwen soft]# mv kafka_2.12-2.8.0/ kafka212 3&#xff0c;配置文件 cd opt/so…

讯飞 语音唤醒 Android SDK

语音唤醒 Android SDK 文档 | 讯飞开放平台文档中心https://www.xfyun.cn/doc/asr/awaken/Android-SDK.html前往控制台&#xff0c;设置唤醒关键词&#xff1a; 控制台-讯飞开放平台https://console.xfyun.cn/services/awaken注意&#xff0c;可以对唤醒词进行评估&#xff0c…

游戏开发需要学什么

游戏开发可以说是当下最热门的专业了&#xff0c;不过这一行业虽然很火热&#xff0c;但也有一定的竞争压力。这个行业需要大量的人才&#xff0c;而且游戏开发这个行业目前还处于初级阶段&#xff0c;所以发展空间还是很大的。现在有很多人都想进入这个行业&#xff0c;但却不…

ESP32-IDF开发笔记 | 03 - 使用SPI外设驱动ST7789 SPILCD

一、硬件说明 ST7789屏幕引脚ESP32C3F引脚3V33V3GNDGNDMOSIIO_07CLKIO_06DCIO_08RSTIO_04BLIO_05 二、ESP32的SPI外设 1. 外设功能 ESP32-C3具有三个SPI接口(SPI0、SPI1和SPI2)。 SPI0和SPI1只能配置为在SPI内存模式下操作&#xff0c;而SPI2可以配置为在SPI内存和通用SPI模…

2023年MathorCup数学建模C题电商物流网络包裹应急调运与结构优化问题解题全过程

2023年第十三届MathorCup高校数学建模挑战赛 C题 电商物流网络包裹应急调运与结构优化问题 原题再现&#xff1a; 电商物流网络由物流场地&#xff08;接货仓、分拣中心、营业部等&#xff09;和物流场地之间的运输线路组成&#xff0c;如图 1 所示。受节假日和“双十一”、“…

手机应用开发之如何利用蓝牙与HC-05通信?

文章目录0、引言1、创建工程2、准备真机调试3、应用布局4、代码编写5、功能演示0、引言 本文通过AndroidStudio开发手机应用软件&#xff0c;实现蓝牙连接功能&#xff0c;并且能发送消息给HC-05蓝牙&#xff0c;也能接收HC-05回传的消息。本文在【AndroidStudio如何进行手机应…

C++基础学习笔记(八)——提高编程PART3

参考链接&#xff1a;https://www.bilibili.com/video/BV1et411b73Z/p237&spm_id_frompageDriver&vd_sourceb4d9cee68649c8adcb1e266f7147cd5c 4 STL- 函数对象 4.1 函数对象 4.1.1 函数对象概念 概念&#xff1a; 重载函数调用操作符的类&#xff0c;其对象常称为…

STL的并行遍历:for_each(依赖TBB)和omp parallel

文章目录OMP parallelOpenMP安装OpenMP示例1) OMP Hello World2) OMP for 并行3. OMP 官方示例4) map使用OMP遍历TBB的安装和使用Gcc9的安装TBB 安装TBB使用在图像处理等应用中&#xff0c;我们经常需要对矩阵&#xff0c;大数量STL对象进行遍历操作&#xff0c;因此并行化对算…

R语言与作物模型(以DSSAT模型为例)融合应用

随着基于过程的作物生长模型&#xff08;Process-based Crop Growth Simulation Model&#xff09;的发展&#xff0c;R语言在作物生长模型和数据分析、挖掘和可视化中发挥着越来越重要的作用。想要成为一名优秀的作物模型使用者与科研团队不可或缺的人才&#xff0c;除了掌握对…

MySQL存储过程 if、case、while、loop、游标、变量、条件处理程序

存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合&#xff0c;调用存储过程可以简化很多工作&#xff0c;减少数据在数据库和应用服务器之间的传输&#xff0c;对于提高数据处理的效率是有好处的。 存储过程思想上很简单&#xff0c;就是数据库 SQL 语言层面的代…

barret reduction原理详解及硬件优化

背景介绍 约减算法&#xff0c;通常应用在硬件领域&#xff0c;因为模运算mod是一个除法运算&#xff0c;在硬件中实现速度会比乘法慢的多&#xff0c;并且还会占用大量资源&#xff0c;因此需要想办法用乘法及其它简单运算来替代模运算。模约减算法可以利用乘法、加法和移位等…

怎么评价2023年第十三届MathorCup高校数学建模挑战赛?

文章目录赛题思路选题建议1 竞赛信息2 竞赛时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; 选题建议 首先要注意&#xff0c;A、B题为研究生组可选题目&#xff0c;A…

还在用 if else 做参数校验?快来学习高级参数校验吧

文章目录一、前言二、自定义校验2.1 定义 GenderArrayValuable 接口2.2 定义性别 GenderEnum 枚举类2.3 自定义 GenderCheck 自定义约束注解2.4 自定义约束的校验器 GenderValidator2.5 定义 UserUpdateGenderDTO2.6 定义一个对外访问接口2.7 请求接口 进行验证三、总结一、前言…

从C出发 17 --- 函数调用

从表面上来看&#xff0c;函数就是一个代码片段&#xff0c;只不过说这个代码片段可以反复利用&#xff0c;通过调用的方式反复利用&#xff0c;通过函数调用&#xff0c;我们可以将参数传到函数所对应的代码片段里面&#xff0c;然后代码片段去处理这些参数&#xff0c;得到一…

Linux下Samba服务器的安装与配置(简单实用)

为了可以实现Linux与windows之间实现文件的共享&#xff0c;方便文件可以直接修改&#xff0c;而不是像以前需要拷贝文件再进行修改&#xff0c;samba的诞生是为了实现现在的这些需求。我们知道Linux之间可以使用NFS服务器来实现文件的共享&#xff0c;samba的诞生就是为了使wi…

Spring Cloud Security

Spring Cloud Security Spring Cloud Security用于构建微服务的安全应用程序和服务&#xff0c;它可以轻松实现微服务系统架构下的统一安全认证与授权。 Spring Cloud Security 有以下组件。 spring-cloud-security&#xff1a;为Zuul、Feign、Oauth 2.0 的Resource Serve…

ChatGPT5是否会影响人类的发展和工作?

目录前言ChatGPT5是什么ChatGPT5 的潜在影响挑战与风险总结前言 ChatGPT的普及也带来了大量的讨论&#xff0c;关于它是否会影响人类的发展和工作。本文将讨论 ChatGPT5 如何可能改变人类的工作和发展&#xff0c;以及潜在的利弊和挑战。在话题开始之前&#xff0c;让我们先从…

QxOrm的使用-数据操作--增删改查

文章目录QxOrm的使用-数据操作使用QxOrm对数据库进行增删改查新增数据删除数据修改数据查询数据QxOrm的使用-数据操作 上一篇我们讲了QxOrm的基本的数据映射操作&#xff0c;这里面再补充一点东西 数据类型映射 Qt/C类型数据库类型boolSMALLINTqx_boolSMALLINTshortSMALLINT…

【谷粒商城之整合阿里云OSS对象存储】

本笔记内容为尚硅谷谷粒商城整合阿里云OSS对象存储部分 目录 一 、简介 二、云存储开通与使用 1、开通阿里云对象存储服务 2、创建bucket 3、创建子用户&#xff08;获取密钥访问OSS服务器&#xff09; 给该子账户添加权限 4、阿里云对象存储上传方式 三、整合 1、…