首页 > 编程语言 >算法分析与设计——实验1: 递归与分治

算法分析与设计——实验1: 递归与分治

时间:2024-04-05 17:31:40浏览次数:40  
标签:right 递归 int 分治 mid 算法 排序 left

实验一  递归与分治

一、实验目的

        1、理解分治算法的概念和基本要素;

        2、理解递归的概念;

        3、掌握设计有效算法的分治策略。

二、实验内容和要求

实验要求:通过上机实验进行算法实现,保存和打印出程序的运行结果,并结合程序进行分析,上交实验报告和程序文件。

实验内容

1、归并排序问题:对n个元素组成的序列进行排序。

将待排序元素分成大小大致相同的两个子集合,分别对两个集合进行排序,最终将排序好的子集合合并成所要求的排好序的集合。

2、使用二分搜索算法查找任意n个有序数列中的指定元素。至少使用两种方法进行编程。

三、算法思想分析

(1)实验内容一(归并排序算法思想)

归并排序包括分解数组、递归求解、合并排序三个步骤。

  • 分解原问题:将待排序的数组序列A[1,n] 分解成两个子序列A[1,|n/2|]和A[|n/2|+1,n],每个子序列包括n/2个元素;
  • 解决子问题:递归解决子问题,对每个子序列分别调用归并排序MergeSort,得到两个有序的子数组;
  • 合并问题解:将两个有序子序列合并为一个有序数组。

2)实验内容二(二分搜索算法思想

采用分治策略,其基本思想为:将n个元素分成个数大致相同的两半,取有序数列的中点位置a[n/2]与需查找的x作比较,如果x=a[n/2]则找到x,算法终止;如果x<a[n/2],则在数组a的左半区间继续搜索x;如果x>a[n/2],则在数组a的右半区间继续搜索x。直到找到相同元素,或者查找范围为空。需要特别注意的是,二分搜索要求待查数列必须采用顺序存储结构,而且元素必须有序排列。

二分搜索算法的优点是比较次数少,查找速度快,平均性能好;缺点是要求待查的数列必须为有序数列,且插入删除困难。

四、程序代码

(1)实验内容一

#include <bits/stdc++.h>
using namespace std;

float temp[10000];

//归并
void mergeArrays(float ar[], int left, int right)
{
    int mid= (left + right) / 2;
    int i=left;  int j= mid + 1;
    int t=left;
    while(i<=mid && j <= right)
    {
        if(ar[i] < ar[j])
        {
            temp[t++]=ar[i];
            i++;
        }
        else
        {
            temp[t++]=ar[j];
            j++;
        }
    }

    while(i <= mid)
    {
        temp[t++]=ar[i];
        i++;
    }
    while(j <= right)
    {
        temp[t++]=ar[j];
        j++;
    }

    for(int i=left; i <= right; i++) ar[i]=temp[i];
}

//归并排序
void mergeSort(float ar[],int left,int right)
{
    int mid=(left+right)/2;

    if(left>=right) return ;

    mergeSort(ar,left,mid);        //递归排序前一半数组
    mergeSort(ar,mid+1,right);   //递归排序后一半数组
    mergeArrays(ar,left,right);        //合并
}

int main()
{
    int n;
    float ar[10000];

    cout<<"请输入要排序的元素个数: "<<endl;
    while(~scanf("%d",&n))
    {
        cout<<"请输入要排序的元素: "<<endl;
        for(int i=0;i<n;i++) cin>>ar[i];

        mergeSort(ar,0,n-1);         //归并排序

        cout<<"从小到大排序后结果:"<<endl;
        for(int i=0;i<n;i++) cout<<ar[i]<<" ";
        cout<<endl;
        cout<<"请输入要排序的元素个数: "<<endl;
    }
        return 0;
}

(2)实验内容二

#include <bits/stdc++.h>
using namespace std;

int a[1000];

//方法一:
int BinarySearch1 (int a[], int left, int right, int x)
{
    int mid;
    mid = (left + right) / 2;
    if(left < right) {
        if (x == a[mid])  return mid;
        else if (x < a[mid]) {
            return BinarySearch1(a, left, mid - 1, x);     //递归调用前一半数组
        }
        else {
            return BinarySearch1(a, mid + 1, right, x);     //递归调用后一半数组
        }
    }
    return 0;
}

//方法二:
int BinarySearch2 (int a[], int left, int right, int x)
{
    int mid;
    while (left <= right) {
        mid = (left + right) / 2;
        if (x == a[mid]) return mid;
        else if (x < a[mid]){
            right = mid - 1;  //递归调用前一半数组
        }
        else{
            left = mid + 1;   //递归调用后一半数组
        }
    }
    return 0;
}

int main()
{
    int n, x;

    cout<<"请输入有序数列元素个数: "<<endl;
    cin >> n;
    cout<< "请输入要查找的元素: " <<endl;
    cin >> x;

    cout<< "请输入有序数列(从小到大): " <<endl;
    for (int i = 0; i < n; i++)  cin >> a[i];

    cout<< "方法一查找结果: "<<endl;
    int flag1 = BinarySearch1(a, 0, n-1 , x);
    if (flag1){
        cout<<"要查找的元素在数组的位置为: " << flag1 + 1 <<endl;
    }
    else{
        cout<<"没有找到!" <<endl;
    }

    cout<< "方法二查找结果: " <<endl;
    int flag2 = BinarySearch2(a, 0 , n-1 , x);
    if (flag2){
        cout<<"要查找的元素在数组的位置为: " << flag1 + 1 <<endl;
    }
    else{
        cout<<"没有找到!" <<endl;
    }
    return 0;
}

五、结果运行与分析

(1)实验内容一

运行结果:

分析:

运行结果正确。

时间复杂度O(nlogn):归并排序主要分为拆分和对有序数组进行排序,拆分操作的时间复杂度为logn,排序的复杂度为n,所以归并排序的时间复杂度为O(nlogn);

空间复杂度O(n):临时数组和递归时压如栈的数据占用的空间为n + logn,所以空间复杂度为O(n)。

2)实验内容一

运行结果:

分析:

运行结果正确。

每执行依次算法的while循环,待搜索数组的大小减小一半。在最坏情况下,while循环被只需O(logn)次。循环体内运算需要O(1)时间,因此整个算法在最坏情况下的时间复杂度为O(logn)。

六、心得与体会

通过本次实验,我理解了分治算法的概念和基本要素,对递归的概念有了更深的理解,分治法在每一层递归上有三个步骤:分解原问题、解决子问题和合并问题解。同时,通过设计有效算法(归并排序和二分搜索)的分治策略,计算其时间和空间复杂度,学习不同方式的二分算法,增进了我对分治算法的理解。

标签:right,递归,int,分治,mid,算法,排序,left
From: https://blog.csdn.net/qq_53229521/article/details/137404576

相关文章

  • 常见面试算法题-发广播
    ■ 题目描述某地有N个广播站,站点之间有些有连接,有些没有。有连接的站点在接受到广播后会互相发送。给定一个N*N的二维数组matrix,数组的元素都是字符’0’或者’1’。matrix[i][j]=‘1’,则代表i和j站点之间有连接,matrix[i][j]=‘0’代表没连接,现在要发一条广播,问初始最少......
  • 函数递归
    调用自身的编程技巧称为递归把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解把大事化小1,举例2,递归打印数字递归的两个必要条件存在限制条件,当满足这个条件时,递归便不在继续每次递归调用之后越来越接近这个限制条件3,递归模拟strlen函数  ......
  • Python递归调用应用实例-汉诺塔
    递归介绍1.简单的说:递归就是函数自己调用自己,每次调用时传入不同的值2.递归有助于编程者解决复杂问题,同时可以让代码变得简洁汉诺塔传说汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石住子,在一根柱子上从上往下按照大小顺......
  • Java中常用的加密算法及其实现原理详解(二)
    本系列文章简介:        随着互联网的快速发展,信息的安全保护愈发重要。在软件开发中,加密算法被广泛应用于数据的加密和解密过程中,以保护敏感信息的机密性和完整性。Java作为一种广泛应用于企业级开发的编程语言,也提供了丰富的加密算法库。        本文将介绍......
  • 文心一言 VS 讯飞星火 VS chatgpt (230)-- 算法导论17.1 1题
    一、如果栈操作包括MULTIPUSH操作,它将k个数据项压入栈中,那么栈操作的摊还代价的界还是O(1)吗?文心一言:在栈的基本操作中,我们通常考虑的是单个元素的压入(push)和弹出(pop)操作,这些操作的摊还代价通常是O(1)。摊还代价考虑的是一系列操作的平均代价,而不是单个操作的最坏......
  • 代码随想录算法训练营第二十四天 二十五 | 回溯的理论基础,77. 组合 216. 组合总和 II
    77.组合https://leetcode.cn/problems/combinations/description/List<List<Integer>>res=newArrayList<>();List<Integer>path=newArrayList<>();publicList<List<Integer>>combine(intn,intk){......
  • 九、算法-排序-堆排序
    常见六大排序:冒泡、选择、插入、快速、归并、堆。在了解堆排序之前,需要了解数据结构-二叉树的知识。二叉树:树中的每个节点下最多只有两个叶子节点;根节点:二叉树的首个节点;叶子节点:非根的节点;父节点-子节点:父节点下方归属的为子节点,是相对而言的关系,在顺序存储的数据结构里......
  • 分类预测 | Matlab实现CPO-LSSVM冠豪猪算法优化最小支持向量机数据分类预测
    分类预测|Matlab实现CPO-LSSVM冠豪猪算法优化最小支持向量机数据分类预测目录分类预测|Matlab实现CPO-LSSVM冠豪猪算法优化最小支持向量机数据分类预测分类效果基本介绍程序设计参考资料分类效果基本介绍1.Matlab实现CPO-LSSVM冠豪猪算法优化最小支持......
  • 代码随想录算法训练营第二天 | 数组 977.有序数组的平方
    leetcode977.有序数组的平方题目977.有序数组的平方给你一个按非递减顺序排序的整数数组nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。示例1:输入:nums=[-4,-1,0,3,10]输出:[0,1,9,16,100]解释:平方后,数组变为[16,1,0,9,100]排序后,数组变为[0,1,9......
  • C112 莫队算法 P1494 [国家集训队] 小 Z 的袜子
    视频链接:  LuoguP1494[国家集训队]小Z的袜子//普通莫队O(n*sqrt(n))#include<iostream>#include<cstring>#include<algorithm>#include<cmath>usingnamespacestd;constintN=50005;intn,m,B,a[N];intsum,cnt[N],ans1[N],ans2[N];str......