一、实验名称
分治法实现合并排序
二、实验目的
通过上机实验,要求掌握分治算法的问题描述、算法设计思想、程序设计。
三、实验原理
利用用分治法实现合并排序,并计算出程序运行所需要的时间。
四、实验步骤
①划分:将所给数组分为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)
T(n)=2*T(n/2)+O(n)
得 T(n)=O(nlog(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)