算法分析与设计实验报告一——分治算法

一、实验目的

  1. 了解分治策略算法思想
  2. 掌握快速排序、归并排序算法
  3. 了解其他分治问题典型算法

二、实验内容

  1. 编写一个简单的程序,实现归并排序。
    编写一段程序,实现快速排序。
  2. 编写程序实现循环赛日程表。设有n=2k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:
    (1)每个选手必须与其它n-1个选手各赛一次
    (2)每个选手一天只能赛一场
    (3)循环赛进行n-1天

三、算法思想分析

  1. 归并排序
    基本思想为先将一个待排序序列分成两段大小大致相同的段,然后对这两个段同样递归地进行二分,直到不能再分为止,然后把足够小的相邻序列合并成有序序列(依据最优子结构且各个子问题相互独立),再上溯,合并,直到整个序列有序化。
    合并时需要对两个已有序的序列合并成一个有序队列,因此在合并操作时就需要进行有序化操作,在这里因为本身子序列已经有序,所以采用设置两个子序列的首尾指针,首指针移动来比较两个子序列中的较小元素并存到新序列,直到一方首尾指针重合,再将另一个序列的剩余部分直接接到新序列即可。
  2. 快速排序
    基本思想为通过一次排序将需要排序的序列分割成独立的两部分,首先设置一个基准数,进行一次排序后,其中一部分的所有数据比基准数小,另一部分的所有数据都比基准数大,这样基准数当前位置就是其在有序序列的位置,然后对新分出的两个序列递归地进行排序处理(由于两方互不影响,其满足最优子结构,有独立性),直到序列大小最小,这样通过一次分治的排序可以将所有元素放到有序序列的正确位置上,从而将整个序列有序化,整体是一个“挖坑填数+分治”的过程。
  3. 循环赛日程表
    基本思想为将整个n * n表格分成n/2 * n/2的四部分,对左上角与右上角的部分递归地进行分割(独立性),直到大小为2 * 2的最小可分配部分,针对最小部分,将每个部分的左上角部分赋给右下角(在最优子结构下2 * 2的部分左上角和右上角都是一个元素),右上角部分赋给左下角,再上溯到4 * 4,重复合并操作,一直到大小为n,这样获得的表就是一个已分配好的表,其中第一列是比赛的每一方,后七列的每一列分别代表当天的对阵。

四、实验过程分析
在做本次实验的过程中,我起初对递归的理解程度不是很深,归并和快排的思想相对还好理解,实现起来也有规律可循,但当做到循环赛日程表时,发现分割从归并与快排的一维升到了二维,就在递归的设计上犯了难,通过一段时间的研究与调试,最后发现当规模没有降到最小时其实都是在进行分割,只有当规模够小之后才能简单进行合并操作,再将部分完成的矩阵升规模再合并直到完成整个矩阵。
通过分治的实验,我对分治的最优子结构性质,独立性,规模缩小策略等相关概念与思想的理解相对更加的深入,这对我在整个课程的学习中都是一个十分显著的成果,而且通过代码的实现,我对分治的基本策略与递归的结合的使用更加的娴熟了,这提高了我的编程能力。

五、算法源代码及用户屏幕
1.归并排序
①代码

#include<iostream>
using namespace std;

void merge(int array[], int left, int middle, int right) {
	int length = right - left + 1;
	//申请空间用于存储合并之后的序列
	int temp[right - left + 1];
	//设置标号
	int begin1 = left;
	int end1 = middle;
	int begin2 = middle + 1;
	int end2 = right;
	//设置新数组的计数器
	int i = 0;
	//比较,进入序列
	while ((begin1 <= end1) && (begin2 <= end2)) {
		if (array[begin1] < array[begin2]) {
			temp[i] = array[begin1];
			begin1++; i++;
		}
		else
		{
			temp[i] = array[begin2];
			begin2++; i++;
		}
	}
	//将剩余部分直接接到最后的序列上
	while (begin1 <= end1) {
		temp[i] = array[begin1];
		begin1++; i++;
	}
	while (begin2 <= end2) {
		temp[i] = array[begin2];
		begin2++; i++;
	}
	for (int j = 0; j < length; j++)
	{
		array[left + j] = temp[j];
	}

}
//递归调用完成操作
void mergeSort(int data[], int left, int right) {
	if (left < right) {
		int middle = (left + right) / 2;
		//先分后合并
		mergeSort(data, left, middle);
		mergeSort(data, middle + 1, right);
		merge(data, left, middle, right);
	}
}

int main() {
	int n;
	cout << "Please input the number of numberSet: ";
	cin >> n;
	int array[n];
	cout << "Please input the number: ";
	for (int i = 0; i < n; i++) {
		cin >> array[i];
	}
	mergeSort(array, 0, n - 1);
	cout << "the result is: ";
	for (int i = 0; i < n; i++) {
		cout << array[i] << " ";
	}
	system("pause");
	return 0;
}

②用户界面
首先输入序列中数的个数,然后输入无序序列,回车之后返回有序序列
在这里插入图片描述
2.快速排序
①代码

#include <iostream>
using namespace std;
int splitArray(int data[], int left, int right) {
	//获取最左边的元素
	int temp = data[left];
	//从左向右查找小于标志位的元素,换到左边,移指针
	while (left < right) {
		while ((left < right) && (data[right] >= temp)) {
			right--;
		}
		data[left] = data[right];
	//从右向左查找大于标志位的元素,换到右边,移指针
		while ((left < right) && (data[left] <= temp)) {
			left++;
		}
		data[right] = data[left];
	}
	//将标志位填到空位
	data[left] = temp;
	return left;
}
//先将标志位填好,然后左右递归调用
void quickSort(int data[], int left, int right) {
	if (left < right) {
		int middle = splitArray(data, left, right);
		quickSort(data, left, middle - 1);
		quickSort(data, middle + 1, right);
	}
}
int main() {
	int n;
	cout << "Please input the number of numberSet: ";
	cin >> n;
	int array[n];
	cout << "Please input the number: ";
	for (int i = 0; i < n; i++) {
		cin >> array[i];
	}
	quickSort(array, 0, n - 1);
	cout << "the result is: ";
	for (int i = 0; i < n; i++) {
		cout << array[i] << " ";
	}
	system("pause");
	return 0;

}

②用户界面
首先输入序列中数的个数,然后输入无序序列,回车之后返回有序序列
在这里插入图片描述
3.循环赛日程表
①代码

#include<iostream>
using namespace std;
#define NUM 100

void queue(int data[NUM][NUM], int left, int right, int num) {
	int middle = (left + right) / 2;
	//将左上角送到右下角
	for (int i = 0; i < num; i++) {
		for (int j = left; j <= middle; j++) {
			data[i + num][j + num] = data[i][j];
		}
	}
	//将左下角送到右上角
	for (int i = 0; i < num; i++) {
		for (int j = middle + 1; j <= right; j++) {
			data[i + num][j - num] = data[i][j];
		}
	}
}

void queueRace(int data[NUM][NUM], int left, int right, int num) {
	int middle = (left + right) / 2;
	//当没有到临界条件(块足够小)时,递归调用
	if (num > 1) {
		queueRace(data, left, middle, num / 2);
		queueRace(data, middle + 1, right, num / 2);
	}
	//合并块
	queue(data, left, right, num);
}

int main() {
	int n;
	cout << "Please input the number of queues: ";
	cin >> n;
	cout << "The result of race is: " << endl;
	int data[NUM][NUM] = { 0 };
	for (int i = 0; i < n; i++) {
		data[0][i] = i + 1;
	}
	for (int i = 1; i < n; i++) {
		for (int j = 0; j < n; j++) {
			data[i][j] = 0;
		}
	}
	queueRace(data, 0, n - 1, n / 2);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (j == n - 1)cout << data[i][j] << endl;
			else cout << data[i][j] << " ";
		}
	}
	system("pause");
	return 0;
}

②用户界面
首先输入需要比赛的队伍数(2的倍数),回车之后显示比赛日程表
在这里插入图片描述

  • 14
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值