算法设计 || 实验一 用分治法实现元素的归并与检索 (头歌详解+本题分析笔记)

news2024/11/19 5:47:22

目录

(一)递归与分治是个啥?

1.递归(归并排序)

2.分治(二分检索算法)

(二)头歌代码怎么写?

(三)代码部分详解:

(四)本题educoder平台要求是输入了10个数字,其实题目要求是随机生成20个数字,那么代码:

(五)一个小小报错的解决新路历程


鉴于最近看人家的超级好朋友每次写实验报告思考的那么认真,本人对自己囫囵吞枣的行为深感抱歉和惋惜,之后会励志当个有内涵的好孩子!

本文为Molly的原创内容,请勿转载!

随机生成20个从1-100之间的随机数,用递归与分治法编程实现元素的查找算法。

(一)递归与分治是个啥?

1.递归(归并排序)

 

2.分治(二分检索算法)

大佬的笔记呈上:(222条消息) 二分搜索算法详解(Binary Search)_bfhonor的博客-CSDN博客

(二)头歌代码怎么写?

PS:这个代码可以借鉴的学习,但是觉得真的是特别冗长(注释希望可以帮助你理解)

/*
本关任务:随机生成20个从1-100之间的随机数,用递归与分治法编程实现元素的查找算法。
*/
//2100300805 毛姝垚
#include <stdlib.h>//标准函数库:常用函数定义(内存分配+随机数生成...)
#include <stdio.h>//标准输入输出库,主要包含标准输入输出函数的定义。
//#include <time.h>// 时间库,主要包含与时间有关的函数的定义
#define N 10//定义宏,将常量N设为10。
//合并函数:将a数组中p到mid,mid+1到r之间的数排序合并
void Merge(int a[],int p,int mid,int r)
{
    int result[r-p+1]; 定义一个数组result,长度为r-p+1。
    int k;//循环变量,当前遍历到的元素位置
    int i=p;//p:待排序数组的左边界
    int j=mid+1;
    // 将a数组中p到r之间的数复制到result数组中。
    /*目的是为了方便后续的归并操作,因为归并排序算法需要将待排序数组不断分割成若干个小数组,然后将这些小数组按照一定的顺序进行合并,而将待排序数组的一部分复制到新数组中就是为了方便后续的合并操作,避免在原数组中进行复杂的操作。*/
    for(k=p;k<=r;k++)
    {
        result[k-p]=a[k];//result[k-p]表示新数组result中第k-p个元素,a[k]表示待排序数组a中第k个元素。 
    }
    // 将result数组中的数按顺序赋值给a数组中p到r之间的数。(归并排序中合并操作)
    /*if-else语句来判断当前需要将哪个子数组中的元素放入合并后的结果数组a中。*/
    for(k=p;k<=r;++k){
        if(i>mid)//左侧已放入结果数组,只需放入右侧
        {
            a[k]=result[j-p];
            j++;
        }
        else if(j>r){//右半部分子数组中的元素已经全部放入了结果数组中,此时只需将左半部分子数组中尚未放入结果数组的元素依次放入即可
            a[k]=result[i-p];
            i++;
        }
        else if (result[i-p]>result[j-p])
        {
            a[k]=result[j-p];
            j++;
        }
        else//左半部分子数组中的第i个元素小于或等于右半部分子数组中的第j个元素
        {
            a[k]=result[i-p];
            i++;
        }
    }
}
// 归并排序函数,将a数组中p到r之间的数进行排序。
void Mergesort(int a[],int p,int r)
{
    int mid;
    if(p < r)
    {
        mid= (p + r) / 2; // 求出中间位置。
        // 递归调用Mergesort函数,将数组不断分为左右两部分进行排序。
        Mergesort(a, p , mid);
        Mergesort(a, mid + 1, r);
        // 将左右两部分合并排序。
        Merge(a, p , mid, r);
    }
}

// 二分查找函数,将a数组中p到r之间的数进行二分查找,寻找目标数target。
void search(int a[],int target,int p,int r)
{
    int mid =(p+r)/2; // 求出中间位置。
    if(target > a[mid]) // 如果目标数大于中间位置的数,则在右半部分查找。
    {
        p=mid+1;
    }
    if(target < a[mid]) // 如果目标数小于中间位置的数,则在左半部分查找。
    {
        r=mid-1;
    }
    if(target==a[mid]) // 如果目标数等于中间位置的数,则输出中间位置的数并返回。
    {
        printf("%d",a[mid]);
        return;
    }
    else // 否则递归调用serch函数,在左右两部分中继续查找。
    {
       search(a,target,p,r);
    }
}

int main(void)
{
    int a[21]; // 数组长度为N+1,为了避免输出后面的空格
    for(int i=0; i<10; ++i){
        scanf("%d",&a[i]); // 输入10个数
    }

    int target;
    scanf("%d",&target); // 输入目标数
    Mergesort(a, 0, 9); // 对数组进行归并排序

    int j=0;
    for(int j=0; j<N; ++j){
        printf("%d",a[j]); // 输出排序后的数组
        if(j < N-1) { // 判断是否为最后一个元素,如果不是,在元素后面加空格
            printf(" ");
        }
    }
    printf("\n");
    search(a, target, 0, 9); // 在排序后的数组中进行二分查找
    return 0;
}

(三)代码部分详解:

1. 将待排序的数组a中p到r范围内的元素复制到一个名为result的新数组中。其中,p表示待排序数组的左边界,r表示待排序数组的右边界,k为循环变量,result[k-p]表示新数组result中第k-p个元素,a[k]表示待排序数组a中第k个元素。 举个例子,如果p=2,r=5,那么就是将待排序数组a中第2个元素到第5个元素(即a[2]到a[5])复制到新数组result中,分别存储在result[0]、result[1]、result[2]、result[3]四个位置上。这样做的目的是为了方便后续的归并操作,因为归并排序算法需要将待排序数组不断分割成若干个小数组,然后将这些小数组按照一定的顺序进行合并,而将待排序数组的一部分复制到新数组中就是为了方便后续的合并操作,避免在原数组中进行复杂的操作。

2. if-else循环部分:

归并排序中的合并(merge)操作,将已经排好序的子数组合并成一个更大的有序数组。其中,p表示待合并数组的左边界,r表示待合并数组的右边界,mid表示待合并数组的中间位置,result是一个辅助数组,用于存放合并后的结果。具体的解释如下: 首先,for循环遍历待合并数组中的所有元素。其中,变量k表示当前遍历到的元素位置。 接着,代码使用了if-else语句来判断当前需要将哪个子数组中的元素放入合并后的结果数组a中。具体的判断逻辑如下:

  • 如果i已经大于mid了,说明左半部分子数组中的元素已经全部放入了结果数组中,此时只需将右半部分子数组中尚未放入结果数组的元素依次放入即可。因此,将result数组中j-p位置的元素放入结果数组a的第k个位置中,并将j自增1,以便下一次循环。
  • 如果j已经大于r了,说明右半部分子数组中的元素已经全部放入了结果数组中,此时只需将左半部分子数组中尚未放入结果数组的元素依次放入即可。因此,将result数组中i-p位置的元素放入结果数组a的第k个位置中,并将i自增1,以便下一次循环。
  • 如果左半部分子数组中的第i个元素大于右半部分子数组中的第j个元素,说明应该将右半部分子数组中的第j个元素放入结果数组中,因为右半部分子数组中的元素已经排好序,且当前右半部分子数组中的第j个元素是所有右半部分子数组中尚未放入结果数组的元素中最小的一个。因此,将result数组中j-p位置的元素放入结果数组a的第k个位置中,并将j自增1,以便下一次循环。
  • 如果左半部分子数组中的第i个元素小于或等于右半部分子数组中的第j个元素,说明应该将左半部分子数组中的第i个元素放入结果数组中,因为左半部分子数组中的元素已经排好序,且当前左半部分子数组中的第i个元素是所有左半部分子数组中尚未放入结果数组的元素中最小的一个。因此,将result数组中i-p位置的元素放入结果数组a的第k个位置中,并将i自增1,以便下一次循环。 最后,当for循环结束时,结果数组a中就包含了待合并数组中所有元素,并且这些元素已经按从小到大的顺序排好了序。

(四)本题educoder平台要求是输入了10个数字,其实题目要求是随机生成20个数字,那么代码:

/*使用了两个函数来实现元素的查找算法,一个是递归实现的recursive_search函数,一个是分治法实现的divide_search函数。在主函数中,先随机生成20个1-100之间的整数,然后输入要查找的元素,最后调用recursive_search或divide_search函数进行查找,并输出查找结果。*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_NUM 100  // 随机数的范围
#define NUM_COUNT 20  // 随机数的个数
// 递归实现元素查找算法
int recursive_search(int arr[], int left, int right, int target)
{
    if (left > right) {
        return -1;  // 查找失败,返回-1
    }
    int mid = left + (right - left) / 2;  // 计算中间位置
    if (arr[mid] == target) {
        return mid;  // 查找成功,返回元素下标
    } else if (arr[mid] < target) {
        return recursive_search(arr, mid+1, right, target);  // 在右半部分继续查找
    } else {
        return recursive_search(arr, left, mid-1, target);  // 在左半部分继续查找
    }
}
// 分治法实现元素查找算法
int divide_search(int arr[], int left, int right, int target)
{
    while (left <= right) {
        int mid = left + (right - left) / 2;  // 计算中间位置
        if (arr[mid] == target) {
            return mid;  // 查找成功,返回元素下标
        } else if (arr[mid] < target) {
            left = mid + 1;  // 在右半部分继续查找
        } else {
            right = mid - 1;  // 在左半部分继续查找
        }
    }
    return -1;  // 查找失败,返回-1
}
int main()
{
    int arr[NUM_COUNT];
    srand(time(NULL));  // 设置随机数种子
    printf("随机生成的数组为:");
    for (int i = 0; i < NUM_COUNT; i++) {
        arr[i] = rand() % MAX_NUM + 1;  // 随机生成1-100之间的整数
        printf("%d ", arr[i]);
    }
    printf("\n请输入要查找的元素:");
    int target;
    scanf("%d", &target);
    int index = recursive_search(arr, 0, NUM_COUNT-1, target);  // 递归查找
    // int index = divide_search(arr, 0, NUM_COUNT-1, target);  // 分治法查找
    if (index == -1) {
        printf("未找到该元素\n");
    } else {
        printf("该元素位于数组的第%d个位置\n", index+1);
    }
    return 0;
}

(五)一个小小报错的解决新路历程

错误分析:在输出后面有一串乱码,估计是因为没有给数组a[]进行初始化,就在主函数中将数组a的所有元素初始化为0。添加代码:

for(int i=0;i<N;++i){

        a[i]=0;

    }

但是显示结果为:

为什么会有一串0在后面呢?发现在定义时,数组a的长度定义为20,但是实际只给前10个进行了赋值,后面10个元素就自然保持了上面的0。

然后又遇到神奇的问题,添加了定义数组长度为10:

#define N 10//定义宏,将常量N设为10

其运行结果为:

那么就自然的修改为了11,但是运行结果为:

如何去掉10后面的一个空格又保证前面的每个数后面空一个格子呢?

printf("%d ",a[m]);

修改为:

  for(int j=0; j<N; ++j){

        printf("%d",a[j]); // 输出排序后的数组

        if(j < N-1) { // 判断是否为最后一个元素,如果不是,在元素后面加空格

            printf(" ");

        }

    }

 

 

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

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

相关文章

Android内嵌Unity (Activity)

Unity2019.4.4 AndropidStudio4.2.1 参考文档&#xff1a; Android内嵌Unity并实现互相跳转的实例代码_Android_脚本之家 Android Fragment中加载,嵌套Unity视图_unity 导入并作为fragment_周灬浩的博客-CSDN博客 本文只实现了Activity整个切换过去&#xff0c;而Fragment…

WSL2 ubuntu ip 自动同步 、静态ip(解决wsl2 ip 每次开机ip会变化的问题)

​ 利用python脚本解决wsl2 ip不固定的问题 环境信息 ​ wsl2 中linux版本&#xff1a;ubuntu ​ windows版本&#xff1a; win10/win11 问题描述 最近装了wsl2&#xff0c;使用vscode远程连接wsl2时遇到了如下问题&#xff1a; 1、wsl2的ip无法固定 2、wsl2的ssh服务不能…

vue项目使用element-ui

最近新建一个vue项目&#xff0c;配置了element-ui&#xff0c;较之前使用时发生了些许变化&#xff0c;对新的配置方式进行记录 node版本 v14.21.3 npm版本 v6.14.18 vue版本 v2.6.14 element-ui版本 v2.15.13 创建项目vue项目&#xff0c;使用…

设计原则之【迪米特法则】

文章目录 一、什么是迪米特法则1、理解迪米特法则2、如何理解“高内聚、松耦合”&#xff1f; 二、实例1、实例12、实例2 一、什么是迪米特法则 迪米特原则&#xff08;Law of Demeter LoD&#xff09;是指一个对象应该对其他对象保持最少的了解&#xff0c;又叫最少知道原则&…

Navicat自动提交的开和关

使用Navicat时&#xff0c;若是自动提交是打开状态&#xff0c;就相当于是自动执行了commit操作&#xff0c;就无法进行回滚操作。 一.相关指令 1.查询Navicat的自动提交开关状态&#xff1a; -- 查询自动提交 ON:是自动提交&#xff0c;即commit ;OFF:不是自动提交&#xf…

Java-注解

文章目录 前言一、概述二、元注解TargetRetentionDocumentedInherited 三、自定义注解四、常用内置注解OverrideDeprecatedSuppressWarnings 前言 注解用于修饰包、类、方法、属性、构造器、局部变量等数据信息&#xff0c;它可以用于创建文档&#xff0c;跟踪代码的依赖性&am…

怎么在VMware ESXi添加NAS存储?

案例&#xff1a;需要将NAS添加到VMware ESXi “我的本地空间不是很多&#xff0c;虚拟机占了我很多空间&#xff0c;但是我有一个NAS&#xff0c;所以我想问一下有没有办法可以让VMware ESXi添加NAS存储来扩展空间&#xff1f;” 网络附加存储&#xff08;NAS&#xff09;设…

2023年6月CDGP数据治理专家认证考试,5月报名及学习

目前6月DAMA-CDGP数据治理专家认证考试开放报名地区有&#xff1a;北京、上海、广州、深圳、长沙、呼和浩特。 目前南京、济南、西安、杭州等地区还在接近开考人数中&#xff0c;打算参加6月考试的朋友们可以抓紧时间报名啦&#xff01;&#xff01;&#xff01; DAMA认证为数据…

为什么每个有影响力的内容创作者都需要一个Kadence WordPress网站

创作者经济正在蓬勃发展&#xff0c;内容创作者正在以前所未有的方式建立受众和收入来源。无论您是在 YouTube、Instagram、TikTok 还是任何其他平台上增加受众&#xff0c;充分利用这些受众变得越来越重要。 Adobe 于 2022 年 8 月发布的一项研究表明&#xff0c;过去 2 年全…

关于加强珠宝玉石类小程序把控的公告

各位小程序开发者为进一步加强小程序的规范管理&#xff0c;保障用户合法权益&#xff0c;平台将对珠宝玉石类小程序加强把控&#xff0c;具体内容如下&#xff1a; 一、 【商家自营-珠宝玉石】类目资质调整 备注&#xff1a;若小程序涉及经营随形加工的原石或摆件相关服务&…

Vue入门简介【第一篇】

大纲 一、Vue介绍 &#x1f334; 1.1 什么是Vue vue是一个构建用户界面UI的渐进式javascript框架&#xff0c;渐进式的框架是指可以一步一步的由浅入深的去使用该框架。 vue官网&#xff1a; https://cn.vuejs.org/ &#x1f334; 1.2 Vue的优点 ⭐️ 1、体积小 压缩后33…

大数据分析就业班课程大纲

大数据分析就业班课程大纲列举&#xff1a; 第一阶段 Mysql从入门到精通/Python从入门到精通课程模块课程内容 MySQL 数据库 数据库概念及其功能介绍、数据库的安装与配置、数据库表的创建及注意事项、数据库的增、删、改、查等操作、多表的关系及查询、多表的…

OSI七层模型中的MAC和PHY

最近做服务器项目在学习MAC和PHY&#xff0c;总结了一些知识点&#xff0c;拿来分享一下 说到MAC和PHY首先要提到OSI七层模型 OSI七层模型 TCP/IP四层模型 对应网络协议 应用层&#xff08;Application&#xff09; 应用层 HTTP、TFTP, FTP, NFS, WAIS、SMTP 表示层&…

【Python入门知识】NumPy 数组排序/过滤,案例+理论讲解

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 数组排序 排序是指将元素按有序顺序排列。 有序序列是拥有与元素相对应的顺序的任何序列&#xff0c;例如数字或字母、升序或降序。 NumPy ndarray 对象有一个名为 sort() 的函数&#xff0c;该函数将对指定的数组进行排…

功率放大器在Lamb波信号波包模型验证研究中的应用

实验名称&#xff1a;窄带激励条件下的兰姆波时域信号参数估计研究 研究方向&#xff1a;Lamb波 测试目的&#xff1a; 基于Lamb波的二阶频散理论&#xff0c;提出了时域信号的波包模型&#xff0c;为全文奠定理论基础。模型考虑两种情况&#xff1a;初始激励以单模态传播和…

【面试】说说什么是 Java 内存模型(JMM)?

文章目录 一、 为什么要有内存模型&#xff1f;1.1. 硬件内存架构1.2. 缓存一致性问题1.3. 处理器优化和指令重排序 二、并发编程的问题三、Java 内存模型3.1. Java 运行时内存区域与硬件内存的关系3.2. Java 线程与主内存的关系3.3. 线程间通信 四、总结 一、 为什么要有内存模…

Java阶段二Day16

Java阶段二Day16 文章目录 Java阶段二Day16SSMSpringBoot简述核心特性创建SpringBoot工程创建工程失败排查 MyBatis框架-注解管理概述MyBatis环境初始化整合MyBatisPojo对象设计Dao接口设计 SSM Spring&#xff1a;Spring是一个轻量级的容器和框架&#xff0c;为开发者提供了一…

沃通“SSL证书+代码签名证书”,防范高仿“钓鱼网站+钓鱼软件”攻击

近日&#xff0c;360发布威胁预警&#xff0c;因监测发现多起利用钓鱼网站对特定用户进行攻击的安全事件&#xff0c;呼吁警惕“高仿”软件安装程序暗藏钓鱼木马。“钓鱼网站钓鱼软件”是非常典型的钓鱼攻击组合&#xff0c;而沃通“SSL证书代码签名证书”能够帮助企业建立安全…

一文带你直观感受,BPM管理系统如何在低代码平台实现搭建

BPM系统&#xff08;英文全称&#xff1a;Business Process Management&#xff0c;翻译后简称BPM&#xff09;即业务流程管理系统&#xff0c;是指对端到端业务流程进行建模、分析和优化&#xff0c;用以实现战略业务目标&#xff0c;其特点是注重流程驱动为核心&#xff0c;实…

通过修改根证书绕过rustls的证书固定机制,抓包解密ssl流量

例子&#xff0c;cloudflare的warp-svc.exe。抓包获取密钥。 用proxifier尝试了一下强行代理&#xff0c;无效&#xff0c;因为proxifier是通过Hook Socket函数方式实现的&#xff0c;但这个程序可能没有用Socket函数进行通信。 之后发现通过nekoray基于gvisor的VPN白名单模式全…