HNU_算法_实验1(2021级)-经典案例2-分治法实现合并排序

本文详细介绍了如何通过分治法实现合并排序算法,包括步骤、关键代码以及时间复杂度的计算。实验中通过编写C++代码对不同规模的数组进行排序,并记录运行时间,以加深对算法的理解。
摘要由CSDN通过智能技术生成

 一、实验名称

分治法实现合并排序

二、实验目的

通过上机实验,要求掌握分治算法的问题描述、算法设计思想、程序设计。

三、实验原理

利用用分治法实现合并排序,并计算出程序运行所需要的时间。

四、实验步骤

①划分:将所给数组分为2个小数组, mid=(l+r)/2

②给两个子数组进行递归分=划分(l-mid),(mid+1,r);

③边界: 只有一个元素时,返回该值

④归并:将两个子数组归并成一个大数组,直到归并到原数组的规模。

例:问题规模n=8,数组a[]={8,4,5,7,1,3,6,2}

五、关键代码

//归并排序
void mergeSort(int arr[], int left, int right)
{
	// 如果只有一个元素,那么不需要继续划分
	// 只有一个元素的区域,本生就是有序的,只需要被归并即可
	if (left < right)
	{
		int mid = (left + right) / 2;              //找中间点
		mergeSort(arr, left, mid);                 //递归划分左半区
		mergeSort(arr, mid + 1, right);           // 递归划分右半区
		merge(arr, left, mid, right);             // 合并已经排序的部分
	}
}

void merge(int arr[], int left, int mid, int right)
{
	int i = left;                            //标记左半区第一个未排序的元素
	int j = mid + 1;                         // 标记右半区第一个未排序的元素
	int k = 0;
	int d;  //
	int* temp = new int[right - left + 1];
	//合并
	while (i <= mid && j <= right)
	{
		if (arr[i] <= arr[j])		 //左半区第一个剩余元素更小
			temp[k++] = arr[i++];    //把元素存在临时数组里面
		else						 // 右半区第一个剩余元素更小
			temp[k++] = arr[j++];
	}
	
	while (j <= right)                // 合并右半区剩余的元素
		temp[k++] = arr[j++];
	
	while (i <= mid)                  // 合并左半区剩余的元素
		temp[k++] = arr[i++];
	
	for (i = left, k = 0; i <= right; i++, k++)      // 把临时数组中合并后的元素复制回原来的数组
		arr[i] = temp[k];
	delete[]temp;                          //删除临时数组
}

六、测试结果

时间复杂度:O(nlogn)

Tn=2*Tn/2+On

Tn=Onlog(n)

七、实验心得

通过这次实验,我更为掌握了分治算法,并且对于合并排序的过程和原理有了更加清楚的认识。在自己生成案例并测试运行时间的过程中,熟悉了随机化算法和运行时间的计算。

​ 实验可改进的地方:随机化过程的加入可能是的不同规模的测试数据与理论值有偏差,可以通过每个输入规模多次测试来减小误差。

八、完整代码

#include<iostream>
#include <fstream>
#include <windows.h>
#include <time.h>
using namespace std;
 
void merge(int arr[], int left, int mid, int right)
{
	int i = left;                            //标记左半区第一个未排序的元素
	int j = mid + 1;                         // 标记右半区第一个未排序的元素
	int k = 0;
	int d;  //
	int* temp = new int[right - left + 1];
	//合并
	while (i <= mid && j <= right)
	{
		if (arr[i] <= arr[j])		 //左半区第一个剩余元素更小
			temp[k++] = arr[i++];    //把元素存在临时数组里面
		else						 // 右半区第一个剩余元素更小
			temp[k++] = arr[j++];
	}
	
	while (j <= right)                // 合并右半区剩余的元素
		temp[k++] = arr[j++];
	
	while (i <= mid)                  // 合并左半区剩余的元素
		temp[k++] = arr[i++];
	
	for (i = left, k = 0; i <= right; i++, k++)      // 把临时数组中合并后的元素复制回原来的数组
		arr[i] = temp[k];
	delete[]temp;                          //删除临时数组
}
 
 
//归并排序
void mergeSort(int arr[], int left, int right)
{
	// 如果只有一个元素,那么不需要继续划分
	// 只有一个元素的区域,本生就是有序的,只需要被归并即可
	if (left < right)
	{
		int mid = (left + right) / 2;              //找中间点
		mergeSort(arr, left, mid);                 //递归划分左半区
		mergeSort(arr, mid + 1, right);           // 递归划分右半区
		merge(arr, left, mid, right);             // 合并已经排序的部分
	}
}
 
int main()
{
//	while(1){
//		//生成规模为n的随机数 
//		cout<<"请输入数据规模n:"<<endl; 
//		int n;
//		cin>>n;
//		ofstream out("input1.txt");
//		out<<n<<'\n';
//		srand((unsigned)time(NULL));
//		for(int i=0;i<n;i++){
//			out<<rand()<<' ';
//			if((i+1)%10==0) out<<'\n';
//		}
//		out.close();
//	
//		int i,maxi,mini;
//		LARGE_INTEGER nFreq,nBegin,nEnd;
//		double time; 
//		
//		ifstream in("input1.txt");
//		//ofstream out("output.txt");
//		in>>n;
//		int a[n];
//		for(i=0;i<n;i++)
//			in>>a[i];
//		int num = sizeof(a) / sizeof(a[0]); 
//		QueryPerformanceFrequency(&nFreq);	
//		QueryPerformanceCounter(&nBegin);
//		mergeSort(a, 0, num - 1);
//		QueryPerformanceCounter(&nEnd);
//		time=(double)(nEnd.QuadPart-nBegin.QuadPart)/(double)nFreq.QuadPart; 
//		
//		
//		cout<<"查询时间:"<<time<<endl<<endl; 
//		in.close();
//		//out.close();
//	}
	    			//生成规模为n的随机数 
		int n;
		ofstream out1("output.txt");
		for(int n=1;n<=100000;n*=10){
			ofstream out("input1.txt");
			out<<n<<'\n';
			srand((unsigned)time(NULL));
			for(int i=0;i<n;i++){
				out<<rand()<<' ';
				if((i+1)%10==0) out<<'\n';
			}
			out.close();
			
			int i,maxi,mini;
			LARGE_INTEGER nFreq,nBegin,nEnd;
			double time; 
			
			ifstream in("input1.txt");			
			in>>n;
			int a[n];
			for(i=0;i<n;i++)
				in>>a[i];
			int num = sizeof(a) / sizeof(a[0]); 
			QueryPerformanceFrequency(&nFreq);	
			QueryPerformanceCounter(&nBegin);
			mergeSort(a, 0, num - 1);
			QueryPerformanceCounter(&nEnd);
			time=(double)(nEnd.QuadPart-nBegin.QuadPart)/(double)nFreq.QuadPart; 
			
			
			out1<<time<<" ";
			in.close();
		}
		out1.close();
	return 0;
}

九、绘图代码

import matplotlib.pyplot as plt

def read_txt_file(file_path):
    with open(file_path, 'r') as file:
        lines = file.readlines()
        # 处理每一行,将字符串中的数值分割并转换为浮点数
        data = [list(map(float, line.strip().split())) for line in lines]
    return data

def plot_line_chart(data):
    # 假设每行的数据都是一个系列,可以根据需要修改
    for series in data:
        plt.plot(series)
    plt.xlabel('n')
    plt.ylabel('Run_time')
    plt.show()

if __name__ == "__main__":
    file_path ='F:\\3-CourseMaterials\\3-1\\3-算法设计与分析\实验\lab1\\1-code\\2-分治法实现归并排序\output.txt'   
    data = read_txt_file(file_path)
    plot_line_chart(data)

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值