分治法实现快速排序与两路合并排序

分治法实现快速排序与两路合并排序
分治法实现快速排序与两路合并排序

实验报告

(2015 / 2016 学年第二学期)

课程名称

实验名称分治法实现快速排序与两路合并排序

实验时间年月日指导单位计算机学院计算机科学与技术系

指导教师

学生姓名班级学号

学院(系) 专业

实验报告

三、实验原理及内容

实验原理:

分治法:即分而治之。将问题分解为规模较小,相互独立,类型相同的问题进行求解。对于无序数组的有序排序也就是按某种方式将序列分成两个或多个子序列,分别进行排序,再将已排序的子序列合并成一个有序序列。

实验内容:

两路合并排序算法的基本思想是:将待排序元素序列一分为二,得到两个长度基本相等的子序列,其过程类似于对半搜索;然后将子序列分别排序,如果子序列较长,还可以继续细分,知道子序列长度不超过1为止。

以上的实现由下列代码执行:

void SortableList::MergeSort()

{

MergeSort(0,n-1);

}

void SortableList::MergeSort(int left,int right)

{

if (left

{

int mid=(left+right)/2;

MergeSort(left,mid);

MergeSort(mid+1,right);

Merge(left,mid,right);

}

}

函数MergeSort是类SortableList上的公有成员函数。

mid=(left+right)/2;将函数划分为两个长度基本相等的子序列,用递归来执行两个子序列的内部排序。而Merge函数是将有序的子序列合并,通过合并过程将自问题的解组合成元问题的解。通过比较两个序列中的最小者,输出其中的较小者,重复此过程,直到一个序列为空,如果还有元素为输出则输出即可。

其中对于Merge函数代码如下:

void SortableList::Merge(int left,int mid,int right)//将两个长度之和为n的有序子序列合并一个有序序列

{

int *temp=new int[right-left+1];

int i=left,j=mid+1,k=0;

while((i<=mid)&&(j<=right))

if (l[i]<=l[j]) temp[k++]=l[i++];

else temp[k++]=l[j++];

while (i<=mid) temp[k++]=l[i++];

while (j<=right) temp[k++]=l[j++];

for (i=0,k=left;k<=right;) l[k++]=temp[i++];

}

快速排序算法的基本思想是:

在待排序序列 K[left:right]上选择一个基准元素(通常是最左边的元素),通过一趟分划操作将序列分成左右两个子序列,左子序列中所有元素都小于等于该基准元素,有子序列中所有元素都大于等于该基准元素。

划分操作如下:

int SortableList::Partition(int left,int right)

{

int i=left,j=right+1;

do{

do i++; while (l[i]

do j--; while (l[j]>l[left]);

if (i

}while (i

Swap(left,j);

return j;

}

则当前基准元素所在的位置位于左、右子序列的中间,即是其排序完成后的最终位置。通过递归调用,对左子序列和右子序列再分别进行快速排序算法的调用。

由于每一趟分划结束后,左子序列中的元素均不大于基准元素,右子序列中的元素均不小于基准元素。而每次分划后,对分划得到的左、右子序列的快速排序又均是就地进行,所以一旦左、右两个子序列都已分别排好序后,无需再执行任何计算,整个序列就是所要求的有序序列了。因此类中应定义成员函数 QuickSort来完成递归快速排序算法的调用和成员函数。

快速排序操作如下:

void SortableList::QuickSort()

{

QuickSort(0,n-1);

}

void SortableList::QuickSort(int left,int right)

{

if (left

int j=Partition(left,right);

QuickSort(left,j-1);

QuickSort(j+1,right);

}

}

比较合并排序和快速排序的异同。

合并排序——将序列一分为二即可。

快速排序——需调用 Partition函数将一个序列划分为子序列。

子问题解合并得到原问题解的过程:合并排序——需要调用 Merge函数来实现。(Merge 函数时间复杂度为O(n))..快速排序——一旦左、右两个子序列都已分别排序,整个序列便自然成为有序序列。

程序中的其他函数:

输入输出函数:

void SortableList::Input(){

for(int i=0;i

cin>>l[i];

n++;

}

}

void SortableList::Output(){

for(int i=0;i

cout<

}

}

主函数:

void main()

{

int n;

int i;

cout <<"***************************************"<

cout <<" 1 两路合并排序"<<" "<<"2 快速排序"<< endl<

while(1)

{

cout <<"************请选择排序方式*************"<

cin>>i;

if(i!=1&&i!=2)

{ cout<<"fault"<

break;

}

cout <<"*********** 请输入比较个数 ************"<

cin >> n;

SortableList l(n);

cout<<"************ 请输入"<

l.Input();

if(i=1)

l.MergeSort();

else

l.QuickSort();

cout<<"************ 排序后序列是: ***********"<

l.Output();

cout<

}

}

实验结果:

实验用例(1)72 26 57 88 42 80 72 48 60

(2)0 0 0 0 0

完整实验代码:

#include

class SortableList

{

public:

SortableList(int mSize)//构造函数

{

maxSize=mSize;

l=new int[maxSize];

n=0;

}

~SortableList()//析构函数

{

delete []l;

}

void MergeSort();

void QuickSort();

void Input();

void Output();

private:

int *l;

int maxSize;

int n;

void MergeSort(int left,int right);

void Merge(int left,int mid,int right); void Swap(int i,int j);

void QuickSort(int left,int right);

int Partition(int left,int right);

};

void SortableList::Swap(int i,int j) {

int c=l[i];

l[i]=l[j];

l[j]=c;

}

int SortableList::Partition(int left,int right) {

int i=left,j=right+1;

do{

do i++; while (l[i]

do j--; while (l[j]>l[left]);

if (i

}while (i

Swap(left,j);

return j;

}

void SortableList::QuickSort()

{

QuickSort(0,n-1);

}

void SortableList::QuickSort(int left,int right) {

if (left

int j=Partition(left,right);

QuickSort(left,j-1);

QuickSort(j+1,right);}

}

void SortableList::MergeSort()

{

MergeSort(0,n-1);

}

void SortableList::MergeSort(int left,int right) {

if (left

{

int mid=(left+right)/2;

MergeSort(left,mid);

MergeSort(mid+1,right);

Merge(left,mid,right);

}

}

void SortableList::Merge(int left,int mid,int right)//将两个长度之和为n的有序子序列合并一个有序序列

{

int *temp=new int[right-left+1];

int i=left,j=mid+1,k=0;

while((i<=mid)&&(j<=right))

if (l[i]<=l[j]) temp[k++]=l[i++];

else temp[k++]=l[j++];

while (i<=mid) temp[k++]=l[i++];

while (j<=right) temp[k++]=l[j++];

for (i=0,k=left;k<=right;) l[k++]=temp[i++];}

void SortableList::Input(){

for(int i=0;i

cin>>l[i];

n++;

}

}

void SortableList::Output(){

for(int i=0;i

cout<

}

}

void main()

{

int n;

int i;

cout <<"***************************************"<

cout <<" 1 两路合并排序"<<" "<<"2 快速排序"<< endl<

while(1)

{

cout <<"************请选择排序方式*************"<

cin>>i;

if(i!=1&&i!=2)

{ cout<<"fault"<

break;

}

cout <<"*********** 请输入比较个数 ************"<

cin >> n;

SortableList l(n);

cout<<"************ 请输入"<

l.Input();

if(i=1)

l.MergeSort();

else

l.QuickSort();

cout<<"************ 排序后序列是: ***********"<

l.Output();

cout<

}

}

实验报告

最接近点对问题实验报告

最接近点对问题 一.实验目的: 1.理解算法设计的基本步骤及各步的主要内容、基本要求; 2.加深对分治设计方法基本思想的理解,并利用其解决现实生活中的问题; 3.通过本次实验初步掌握将算法转化为计算机上机程序的方法。 二.实验内容: 1.编写实现算法:给定n对点,在这n对点中找到距离最短的点对。 2.将输出数据存放到另一个文本文件中,包括结果和具体的运行时间。 3.对实验结果进行分析。 三.实验操作: 1.最接近点对查找的思想: 首先,将所有的点对按照x坐标排序,找到x坐标的中位数,将所有的点对分成三部分,横坐标小于x(S1)、等于x(S2)和大于x(S3)的点对,在求取每部分中的最短距离,利用分治法,一步步地分解为子问题,找到最短距离d。由于距离最近的两个点可能在不同的区域中,需要进一步判断。 选择S1中的一个点,由于与它相比较的点的距离不可能超过d,故其配对范围为d*2d的矩形,将这个矩形划分为6份2/d*3/d的小矩形,其对角线的长度为5/6d,小于d,故S1中的任意一个点只需和S2中的6个点比较即可,最终确定最短的距离。 2.取中位数: 为了减少算法的时间开销,需要将所有的点对进行分组,以中位数为基准,考虑到快速排序的不稳定性,本次排序使用了合并排序。 代码实现: template void Merge(Type c[],Type d[],int l,int m,int r){ int i = l,j = m + 1,k = l; while((i<=m)&&(j<=r)){ if(c[i]<=c[j]) d[k++] = c[i++]; else d[k++] = c[j++]; } if(i>m) { for(int q=j; q<=r; q++) d[k++] = c[q]; } else{ for(int q=i; q<=m; q++) d[k++] = c[q]; } } template void MergeSort(Type a[],Type b[],int left,int right){ if(left

0007算法笔记——【分治法】最接近点对问题

问题场景:在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。在涉及这些几何对象的问题中,常需要了解其邻域中其他几何对象的信息。例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来看待,则具有最大碰撞危险的2架飞机,就是这个空间中最接近的一对点。这类问题是计算几何学中研究的基本问题之一。 问题描述:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。严格地说,最接近点对可能多于1对。为了简单起见,这里只限于找其中的一对。 1、一维最接近点对问题 算法思路: 这个问题很容易理解,似乎也不难解决。我们只要将每一点与其他n-1个点的距离算出,找出达到最小距离的两个点即可。然而,这样做效率太低,需要O(n^2)的计算时间。在问题的计算复杂性中我们可以看到,该问题的计算时间下界为Ω(nlogn)。这个下界引导我们去找问题的一个θ(nlogn)算法。采用分治法思想,考虑将所给的n个点的集合S 分成2个子集S1和S2,每个子集中约有n/2个点,然后在每个子集中递归地求其最接近的点对。在这里,一个关键的问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对,因为S1和S2的最接近点对未必就是S的最接近点对。如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解

决。但是,如果这2个点分别在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它构成最接近点对的候选者,仍需做n^2/4次计算和比较才能确定S的最接近点对。因此,依此思路,合并步骤耗时为O(n^2)。整个算法所需计算时间T(n)应满足:T(n)=2T(n/2)+O(n^2)。它的解为T(n)=O(n^2),即与合并步骤的耗时同阶,这不比用穷举的方法好。从解递归方程的套用公式法,我们看到问题出在合并步骤耗时太多。这启发我们把注意力放在合并步骤上。 设S中的n个点为x轴上的n个实数x1,x2,..,xn。最接近点对即为这n个实数中相差最小的2个实数。我们显然可以先将x1,x2,..,x n排好序,然后,用一次线性扫描就可以找出最接近点对。这种方法主要计算时间花在排序上,在排序算法已经证明,时间复杂度为O(nlogn)。然而这种方法无法直接推广到二维的情形。因此,对这种一维的简单情形,我们还是尝试用分治法来求解,并希望能推广到二维的情形。假设我们用x轴上某个点m将S划分为2个子集S1和S2,使得S1={x∈S|x≤m};S2={x∈S|x>m}。这样一来,对于所有p∈S1和q∈S2有p

2009.1算法设计与分析课程期末试卷-A卷(自测 )

华南农业大学期末考试试卷(A卷)2008学年第一学期考试科目:算法分析与设计 考试类型:(闭卷)考试时间:120 分钟 学号姓名年级专业 一、选择题(20分,每题2分) 1.下述表达不正确的是。 A.n2/2 + 2n的渐进表达式上界函数是O(2n) B.n2/2 + 2n的渐进表达式下界函数是Ω(2n) C.logn3的渐进表达式上界函数是O(logn) D.logn3的渐进表达式下界函数是Ω(n3) 2.当输入规模为n时,算法增长率最大的是。 A.5n B.20log 2n C.2n2 D.3nlog 3 n 3.T(n)表示当输入规模为n时的算法效率,以下算法效率最优的是。A.T(n)= T(n – 1)+1,T(1)=1 B.T(n)= 2n2 C.T(n)= T(n/2)+1,T(1)=1 D.T(n)= 3nlog 2 n 4.在棋盘覆盖问题中,对于2k×2k的特殊棋盘(有一个特殊方块),所需的L型骨 牌的个数是。 A.(4k– 1)/3 B.2k /3 C.4k D.2k 5.在寻找n个元素中第k小元素问题中,若使用快速排序算法思想,运用分治算

法对n个元素进行划分,应如何选择划分基准?下面答案解释最合理。 A.随机选择一个元素作为划分基准 B.取子序列的第一个元素作为划分基准 C.用中位数的中位数方法寻找划分基准 D.以上皆可行。但不同方法,算法复杂度上界可能不同 6.有9个村庄,其坐标位置如下表所示: 现在要盖一所邮局为这9个村庄服务,请问邮局应该盖在才能使到邮局到这9个村庄的总距离和最短。 A.(4.5,0)B.(4.5,4.5)C.(5,5)D.(5,0) 7.n个人拎着水桶在一个水龙头前面排队打水,水桶有大有小,水桶必须打满水, 水流恒定。如下说法不正确? A.让水桶大的人先打水,可以使得每个人排队时间之和最小 B.让水桶小的人先打水,可以使得每个人排队时间之和最小 C.让水桶小的人先打水,在某个确定的时间t内,可以让尽可能多的人打上水D.若要在尽可能短的时间内,n个人都打完水,按照什么顺序其实都一样 8.分治法的设计思想是将一个难以直接解决的大问题分割成规模较小的子问题, 分别解决子问题,最后将子问题的解组合起来形成原问题的解。这要求原问题和子问题。

最近点对分治法

假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。 如果不用分治法,问题非常容易解决。也就是蛮力法。 代码如下: #include #include typedef struct TYPE { double x, y; } Point; float dist(Point a,Point b) { return (float)sqrt((float)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } float nearest(Point* points, int n) { float temp,near1=10000; int i,j; if(n==1) { printf("不可能"); return 0; } else{ for(i=0; itemp)?temp:near1; } } return near1; } } int main()

{ int n, i; double d; printf("输入点的个数:"); scanf("%d", &n); Point a[10000]; while (n) { for (i = 0; i < n; i++) scanf("%lf%lf", &(a[i].x), &(a[i].y)); d = nearest(a,n); printf("%.2lf\n", d); scanf("%d", &n); } return 0; } 但是本题是用分治法,我也参考了网上很多资料,他们要求对纵坐标进行排序,可能是为了对求右边的问题的点扫描用for 循环,但我发现那算法就不对,但愿是我的还没有完全明白按纵坐标排序的原因, 我参考的资料: https://www.360docs.net/doc/2f13282169.html,/p-198711591.html?qq-pf-to=pcqq.c2c 代码如下: #include #include #include

算法分析实验报告--分治策略

《算法设计与分析》实验报告 分治策略 姓名:XXX 专业班级:XXX 学号:XXX 指导教师:XXX 完成日期:XXX

一、试验名称:分治策略 (1)写出源程序,并编译运行 (2)详细记录程序调试及运行结果 二、实验目的 (1)了解分治策略算法思想 (2)掌握快速排序、归并排序算法 (3)了解其他分治问题典型算法 三、实验内容 (1)编写一个简单的程序,实现归并排序。 (2)编写一段程序,实现快速排序。 (3)编写程序实现循环赛日程表。设有n=2k个运动员要进行网球循环赛。现 要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其它n-1个选手各赛一次(2)每个选手一天只能赛一场(3)循环赛进行n-1天 四、算法思想分析 (1)编写一个简单的程序,实现归并排序。 将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行 排序,最终将排好序的子集合合并成为所要求的排好序的集合。 (2)编写一段程序,实现快速排序。 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有 数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数 据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据 变成有序序列。 (3)编写程序实现循环日赛表。 按分治策略,将所有的选手分为两组,n个选手的比赛日程表就可以通

过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割, 直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让 这2个选手进行比赛就可以了。 五、算法源代码及用户程序 (1)编写一个简单的程序,实现归并排序。 #include #include #define MAX 10 using namespace std; void merge(int array[],int p,int q,int r) { int i,k; int begin1,end1,begin2,end2; int* temp = new int[r-p+1]; begin1 = p; end1 = q; begin2 = q+1; end2 = r; k = 0; while((begin1 <= end1)&&(begin2 <= end2)) { if(array[begin1] < array[begin2]) { temp[k] = array[begin1]; begin1++; } else { temp[k] = array[begin2]; begin2++; } k++; } while(begin1 <= end1) {

分治算法实验(用分治法实现快速排序算法)

算法分析与设计实验报告第四次附加实验

while (a[--j]>x); if (i>=j) { break; } Swap(a[i],a[j]); } a[p] = a[j]; //将基准元素放在合适的位置 a[j] = x; return j; } //通过RandomizedPartition函数来产生随机的划分 template vclass Type> int RandomizedPartition(Type a[], int p, int r) { int i = Random(p,r); Swap(a[i],a[p]); return Partition(a,p,r); } 较小个数排序序列的结果: 测试结果 较大个数排序序列的结果:

实验心得 快速排序在之前的数据结构中也是学过的,在几大排序算法中,快速排序和归并排序尤其是 重中之重,之前的快速排序都是给定确定的轴值,所以存在一些极端的情况使得时间复杂度 很高,排序的效果并不是很好,现在学习的一种利用随机化的快速排序算法,通过随机的确 定轴值,从而可以期望划分是较对称 的,减少了出现极端情况的次数,使得排序的效率挺高了很多, 化算法想呼应,而且关键的是对于随机生成函数,通过这一次的 学习终于弄明白是怎么回事了,不错。 与后面的随机实 验和自己的 实验得分助教签名 附录: 完整代码(分治法) //随机后标记元素后的快速排序 #i nclude #in elude #inelude #include using namespacestd; template < class Type> void S &x,Type &y); // 声明swap函数 inline int Random(int x, int y); // 声明内联函数 template < class Type> int Partition(Type a[], int p, int r); // 声明 Partition 函数template int RandomizedPartition(Type a[], int p, int r); // 声明 RandomizedPartition 函数 int a[1000000]; //定义全局变量用来存放要查找的数组 更大个数排序序列的结果:

分治法实现快速排序与两路合并排序

实验报告 (2015 / 2016 学年第二学期) 课程名称 实验名称分治法实现快速排序与两路合并排序 实验时间年月日指导单位计算机学院计算机科学与技术系 指导教师 学生姓名班级学号 学院(系) 专业 实验报告

三、实验原理及内容 实验原理: 分治法:即分而治之。将问题分解为规模较小,相互独立,类型相同的问题进行求解。对于无序数组的有序排序也就是按某种方式将序列分成两个或多个子序列,分别进行排序,再将已排序的子序列合并成一个有序序列。 实验内容: 两路合并排序算法的基本思想是:将待排序元素序列一分为二,得到两个长度基本相等的子序列,其过程类似于对半搜索;然后将子序列分别排序,如果子序列较长,还可以继续细分,知道子序列长度不超过1为止。 以上的实现由下列代码执行: void SortableList::MergeSort() { MergeSort(0,n-1); } void SortableList::MergeSort(int left,int right) { if (left

分治法实现快速排序

实验一 实验名称:利用分治法实现快速排序 实验时 2012 年12月成绩: 间: 一、实验目的 分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将各个子问题的解合并得到原问题的解。 本实验的目的是利用分治策略实现快速排序算法。 二、实验内容 快速排序算法是基于分治策略的排序算法。其基本思想是,对于输入的子数组a[p:r],按以下三个步骤进行排序。 (1)分解:以a[p]为基准元素将a[p:r]划分成3段a[p:q-1],a[q] 和a[q+1:r], 使a[p:q-1]中任何一个元素小于等于a[q],而a[q+1:r]中任何一个元素大于等于 a[q]。下标q在划分过程中确定。 (2)递归求解:通过递归调用快速排序算法分别对a[p:q-1]和a[q+1:r]进行排序。 (3)合并:由于对a[p:q-1]和a[q+1:r]的排序是就地进行的,所以在a[p:q-1] 和a[q+1:r]都已排好的序后,不需要执行任何计算,a[p:r]就已排好序。 基于这个思想,可实现的快速排序算法如下: void QuickSort(i nt a[],i nt p,i nt r) if(p

int q=Partition(a,p,r); QuickSort(a,p,q-1); QuickSort(a,q+1,r); } } 对含有n 个元素的数组a[0;n-1] 进行快速排序只要调用QuickSort(a,0,n-1) 即可。 上述算法中的函数Partition ,以确定的一个基准元素a[p] 对子数组a[p:r] 进行划分,它是快速排序算法的关键。 int Partition(int a[],int p,int r) { int i=p,j=r+1; int x=a[p]; while(true) { while(a[++i]x); if(i>=j) break; Swap(a[i],a[j]); } a[p]=a[j];

用分治算法解平面最接近点对问题

一. 用分治算法解平面最接近点对问题 1.题目 关于最接近点对问题: 给定平面上n个点,找出其中一对点,使得在n个点所构成的所有点对中,该点对的距离最小。 2.程序详细介绍(各模块的功能等) 本程序主要包括两个类:类Point和类Ppoint.其中类Point为处理一些的基本数据传递等.类Ppoint为该程序的主要实现模块,该类中有输入点对的函数shuru,对所输入的点对按X轴排序的函数sort,求各点对的距离的函数xiao等. 假设S中的点为平面上的点,它们都有2个坐标值x和y。为了将平面上点集S线性分割为大小大致相等的2个子集S1和S2,我们选取一垂直线l(方程:x=m)来作为分割直线。其中m为S中各点x坐标的中位数。由此将S分割为S1={p∈S|px≤m}和S2={p∈S|px>m}。从而使S1和S2分别位于直线l的左侧和右侧,且S=S1∪S2 。由于m是S中各点x坐标值的中位数,因此S1和S2中的点数大致相等。递归地在S1和S2上解最接近点对问题,我们分别得到S1和S2中的最小距离δ1和δ2.此即为该程序的大致算法. 3. 程序结构(流程图) 该程序的流程图如下所示

4. 调试与测试:调试方法,测试结果(包括输入数据和输出结果)的分析与讨论 运行该程序时,屏幕上会出现一个界面,首先该界面会提示输入要处理的点对个数,输入点对个数后从键盘输入数字0即可显示出处理后的各个结果,会出现如下结果:

5.程序代码(源程序) #include #include #include using namespace std; int i,j,k,d,m,n; double p2,q,s,r,t; class Point //创建一个点类// { public: double x; double y; double getx() { return x; } double gety() { return y; } friend class Ppoint; }; class Ppoint { int sum; double juli[10][10]; double min[11]; //min[10]用来存放每组中最短的距离// double mini[11]; //mini[10]用来存放每组中距离最短的点对中的第一个点// double minj[11]; //minj[10]用来存放每组中距离最短的点对中的第二个点// Point p[100]; Point p1; public: void shuru() { cout<<"请输入要处理的点的个数"<>sum; for(i=0;i

算法分析实验报告--分治策略

分治策略 姓名:XXX 专业班级:XXX 学号:XXX 指导教师:XXX 完成日期:XXX

一、试验名称:分治策略 (1)写出源程序,并编译运行 (2)详细记录程序调试及运行结果 二、实验目的 (1)了解分治策略算法思想 (2)掌握快速排序、归并排序算法 (3)了解其他分治问题典型算法 三、实验内容 (1)编写一个简单的程序,实现归并排序。 (2)编写一段程序,实现快速排序。 (3)编写程序实现循环赛日程表。设有n=2k个运动员要进行网球循环赛。现 要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其它n-1个选手各赛一次(2)每个选手一天只能赛一场(3)循环赛进行n-1天 四、算法思想分析 (1)编写一个简单的程序,实现归并排序。 将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行 排序,最终将排好序的子集合合并成为所要求的排好序的集合。 (2)编写一段程序,实现快速排序。 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有 数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数 据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据 变成有序序列。 (3)编写程序实现循环日赛表。 按分治策略,将所有的选手分为两组,n个选手的比赛日程表就可以通 过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割, 直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让

这2个选手进行比赛就可以了。 五、算法源代码及用户程序 (1)编写一个简单的程序,实现归并排序。 #include #include<> #define MAX 10 using namespace std; void merge(int array[],int p,int q,int r) { int i,k; int begin1,end1,begin2,end2; int* temp = new int[r-p+1]; begin1 = p; end1 = q; begin2 = q+1; end2 = r; k = 0; while((begin1 <= end1)&&(begin2 <= end2)) { if(array[begin1] < array[begin2]) { temp[k] = array[begin1]; begin1++; } else { temp[k] = array[begin2]; begin2++; } k++; } while(begin1 <= end1) { temp[k++] = array[begin1++]; }

分治算法实验

中南大学 《算法设计与分析》实验报告 姓名: 专业班级: 学号: 指导教师: 完成日期:2010.1

一.实验名称 分治算法实验 二.实验目的 1. 了解分治策略算法思想 2. 掌握快速排序、归并排序算法 3. 了解其他分治问题典型算法 三.实验内容 1. 编写一个简单的程序,实现归并排序。 2. 编写一段程序,实现快速排序。 3. 编写程序实现循环赛日程表。设有n=2k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其它n-1个选手各赛一次(2)每个选手一天只能赛一场(3)循环赛进行n-1天 四.算法思想分析 1. 归并排序 归并排序算法思想: 分而治之(divide - conquer),即每个递归过程涉及三个步骤:第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括n/2 个元素。第二, 治理: 对每个子序列分别调用归并排序MergeSort,进行递归操作。第三, 合并: 合并两个排好序的子序列,生成排序结果。 归并操作的工作原理如下: (1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 (2)设定两个指针,最初位置分别为两个已经排序序列的起始位置 (3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 (4)重复步骤3直到某一指针达到序列尾 (5)将另一序列剩下的所有元素直接复制到合并序列尾 比较操作的次数介于(nlogn) / 2和nlogn ? n + 1。赋值操作的次数是(2nlogn)。归并算法的空间复杂度为:Θ (n)

2. 快速排序 快速排序法的基本精神是在数列中找出适当的轴心,然后将数列一分为二,分别对左边与右边数列进行排序,而影响快速排序法效率的正是轴心的选择。 (1)分解:将输入的序列L[p..r]划分成两个非空子序列L[p..q]和L[q+1..r],使L[p..q]中任一元素的值不大于L[q+1..r]中任一元素的值。 (2)递归求解:通过递归调用快速排序算法分别对L[p..q]和L[q+1..r]进行排序。 (3)合并:由于对分解出的两个子序列的排序是就地进行的,所以在L[p..q]和L[q+1..r]都排好序后不需要执行任何计算L[p..r]就已排好序。 3. 循环赛日程表 按分治策略,将所有的选手分为两组,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就可以简单的处理了。 五.算法源代码及用户屏幕 1.归并排序 (备注:语言C++;编译器:MS VS2008;共2个文件) head.h文件 #include #include using namespace std; void mergeSort(int *a,int left,int right); void merge(int *a,int left,int i,int right); main.cpp文件 #include "head.h" void main() { int test[]={0,12,45,3,6,29,4,16,77}; cout<<"before:"; for(int i=0;i<=8;i++) { cout<

最接近点对问题

一、最接近点对问题(一维) 1、最接近点对问题(一维) 最接近点对问题:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。此时S中的n个点退化为x轴上的n个实数x1,x2,..,x n。最接近点对即为这n 个实数中相差最小的2个实数。 2、分析 将所给的平面上n个点的集合S分成2个子集S1和S2,每个子集中约有n/2个点,·然后在每个子集中递归地求其最接近的点对。S1和S2的最接近点对未必就是S的最接近点对,如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。但是,如果这2个点分别在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它构成最接近点对的候选者,仍需做n2/4次计算和比较才能确定S的最接近点对。 因此,依此思路,合并步骤耗时为O(n2)。 整个算法所需计算时间T(n)应满足: T(n)=2T(n/2)+O(n2) 它的解为T (n)=O(n2) 3、伪代码 随机Random float Random() { float result=rand()%10000; return result*0.01; } 返回最大、最小 float Max OR Min(float s[],int p,int q)//返回s[]中的最大值 { float s_max(s_min)=s[p]; for(int i=p+1;i<=q;i++) if(s_maxs[i]) s_min=s[i]; return s_max(s_min) } 主要函数 Cpair Cpair1(float s[],int n) { Cpair out_p_d={99999,0,0}; if(n<2) return out_p_d; float m1=Max(s,0,n-1),m2=Min(s,0,n-1);

分治法实现快速排序

实验一 实验名称:利用分治法实现快速排序实验时间: 2012年12月成绩:一、实验目的 分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将各个子问题的解合并得到原问题的解。 本实验的目的是利用分治策略实现快速排序算法。 二、实验内容 快速排序算法是基于分治策略的排序算法。其基本思想是,对于输入的子数组a[p:r],按以下三个步骤进行排序。 (1)分解:以a[p]为基准元素将a[p:r]划分成3段a[p:q-1],a[q]和a[q+1:r],使a[p:q-1]中任何一个元素小于等于a[q],而a[q+1:r]中任何一个元素大于等于a[q]。下标q在划分过程中确定。 (2)递归求解:通过递归调用快速排序算法分别对a[p:q-1]和a[q+1:r]进行排序。 (3)合并:由于对a[p:q-1]和a[q+1:r]的排序是就地进行的,所以在a[p:q-1]和a[q+1:r]都已排好的序后,不需要执行任何计算,a[p:r]就已排好序。基于这个思想,可实现的快速排序算法如下:void QuickSort(int a[],int p,int r)

{ if(px); if(i>=j) break;

分治法实验报告

算法实验报告一分治法实验 一、实验目的及要求 利用分治方法设计大整数乘法的递归算法,掌握分治法的基本思想和算法设计的基本步 骤。 要求:设计十进制的大整数乘法,必须利用分治的思想编写算法,利用c语言(或者c++ 语言)实现算法,给出程序的正确运行结果。(必须完成) 设计二进制的大整数乘法,要求利用分治的思想编写递归算法,并可以实现多位数的乘 法(利用数组实现),给出程序的正确运行结果。(任选) 二、算法描述 1、 输入两个相同位数的大整数u,v 输出uv的值 判断大整数的位数i; w=u/10^(i/2); y=v/10^(i/2); x=u-w*10^(i/2); z= v-y*10^(i/2); 然后将w,x,y,z代入公式求得最后结果 uv=wy10^i+((w+x)(y+z)-wy-xz)10^(i/2)+xz 三、调试过程及运行结果 在实验中我遇到的问题: 原来以为这两个大整数的位数不同,结果题目要求是相同位数的大整数在写10的多少 次方时,写的是10^(i/2),10^(i),结果不对,我就将它改成了for循环语句 四、实验总结 在本次实验中,我知道了分治算法,以及分治算法的基本思想。我还掌握了编写大整数 乘法的算法与步骤,以及如何修改在编写程序时遇到的问题。 五、附录(源程序代码清单) 1、#include<iostream.h> int weishu(int x) { int i; while(x!=0) { x=x/10; i++; } return i; } void main() { int u,v; cout<<输入两个位数相同的大整数:<<endl; cin>>u; cin>>v;

2020智慧树知到《算法分析与设计》章节测试完整答案

2020智慧树知到《算法分析与设计》章节 测试完整答案 智慧树知到《算法分析与设计》章节测试答案 第一章 1、给定一个实例,如果一个算法能得到正确解答,称这个算法解答了该问题。 答案: 错 2、一个问题的同一实例可以有不同的表示形式 答案: 对 3、同一数学模型使用不同的数据结构会有不同的算法,有效性有很大差别。 答案: 对 4、问题的两个要素是输入和实例。 答案: 错 5、算法与程序的区别是() A:输入 B:输出 C:确定性 D:有穷性 答案: 有穷性 6、解决问题的基本步骤是()。(1)算法设计(2)算法实现(3)数学

建模(4)算法分析(5)正确性证明 A:(3)(1)(4)(5)(2) B:(3)(4)(1)(5)(2) C:(3)(1)(5)(4)(2) D:(1)(2)(3)(4)(5) 答案: (3)(1)(5)(4)(2) 7、下面说法关于算法与问题的说法错误的是()。 A:如果一个算法能应用于问题的任意实例,并保证得到正确解答,称这个算法解答了该问题。 B:算法是一种计算方法,对问题的每个实例计算都能得到正确答案。 C:同一问题可能有几种不同的算法,解题思路和解题速度也会显著不同。 D:证明算法不正确,需要证明对任意实例算法都不能正确处理。 答案: 证明算法不正确,需要证明对任意实例算法都不能正确处理。 8、下面关于程序和算法的说法正确的是()。 A:算法的每一步骤必须要有确切的含义,必须是清楚的、无二义的。 B:程序是算法用某种程序设计语言的具体实现。 C:程序总是在有穷步的运算后终止。 D:算法是一个过程,计算机每次求解是针对问题的一个实例求

用蛮力法和分治法解决最近对问题

算法分析与复杂型设计作业 学院计算机与控制工程学院 专业计算机软件与理论 班级 Y130701 学生姓名郑晓璐 流水号 20130789 2014年4月

问题: 设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。 蛮力算法描述: int ClosestPoints(int n, int x[ ], int y[ ]){ minDist=Double.POSITIVE_INFINITY;; for (i=1; i< n; i++) for (j=i+1; j<=n; j++) { d=(x[i]-x[j])* (x[i]-x[j])+(y[i]-y[j])* (y[i]-y[j]); if (d< minDist) { minDist=d; index1=i; index2=j; } } return minDist; } 程序: import java.util.*; public class ClosestPair1{ public static void main(String[] args) { /** *输入需要比较的点的对数存在变量n中 */ Scanner in=new Scanner(System.in); System.out.println("How many pairs of points to compare?(有多少对点需要比较?)"); int n=in.nextInt(); int[] x=new int[n]; int[] y=new int[n]; /** *输入这些点的横坐标和纵坐标分别存储在x[n]和y[n] */ System.out.println("Please enter these points,X-coordinate(请输入这些点,横坐标):"); for(int i=0;i< n;i++) { x[i]=in.nextInt(); }

二分搜索算法和快速排序算法及分治策略

实验课程:算法分析与设计 实验名称:实验二C/C++环境及递归算法(综合性/设计性) 实验目标: 1、熟悉二分搜索算法和快速排序算法; 2、初步掌握分治算法; 实验任务: 掌握分治策略的概念和基本思想。 实验题: 1、设a[0:n-1]是一个已排好序的数组。请改写二分搜索算法,使得当搜索元素x不在数组中时,返回小于x的最大元素的位置i和大于x的最小元素位置j。当搜索元素在数组中时,I 和j相同,均为x在数组中的位置。设有n个不同的整数排好序后存放于t[0:n-1]中,若存在一个下标i,0≤i<n,使得t[i]=i,设计一个有效的算法找到这个下标。要求算法在最坏的情况下的计算时间为O(logn)。 2、在快速排序中,记录的比较和交换是从两端向中间进行的,关键字较大的记录一次就能交换到后面单元,关键字较小的记录一次就能交换到前面单元,记录每次移动的距离较大,因而总的比较和移动次数较少。 实验设备及环境: PC;C/C++的编程环境Visual C++。 实验主要步骤: (1)明确实验目标和具体任务; (2)理解实验所涉及的分治算法; (3)编写程序并实现分治算法; (4)设计实验数据并运行程序、记录运行的结果; 实验数据及运行结果、实验结果分析及结论: 1、#include using namespace std; int main() { int const length=100; int n,x; int a[length]; cout<<"依次输入数组的长度,数组内容,要查找的数"<>n; //输入数组的长度 for(int i=0;i>a[i]; cin>>x;

算法分析复习题(含答案)

一、选择题 1、衡量一个算法好坏的标准是( C )。 (A)运行速度快(B)占用空间少(C)时间复杂度低(D)代码短 2、记号O的定义正确的是(A)。 (A)O(g(n)) = { f(n) | 存在正常数c和n0使得对所有n≥n0有:0≤ f(n) ≤ cg(n) };(B)O(g(n)) = { f(n) | 存在正常数c和n0使得对所有n≥n0有:0≤ cg(n) ≤ f(n) };(C)O(g(n)) = { f(n) | 对于任何正常数c>0,存在正数和n0 >0使得对所有n≥n0 有:0 ≤f(n)0,存在正数和n0 >0使得对所有n≥n0 有:0 ≤cg(n) < f(n) }; 3、二分搜索算法是利用( A )实现的算法。 (A)分治策略(B)动态规划法(C)贪心法(D)回溯法 4、使用分治法求解不需要满足的条件是(A )。 (A)子问题必须是一样的(B)子问题不能够重复 (C)子问题的解可以合并(D)原问题和子问题使用相同的方法解 5、合并排序算法是利用( A )实现的算法。 (A)分治策略(B)动态规划法(C)贪心法(D)回溯法 6、实现大整数的乘法是利用(C )的算法。 (A)贪心法(B)动态规划法(C)分治策略(D)回溯法 7、以下不可以使用分治法求解的是( D )。 (A)棋盘覆盖问题(B)选择问题(C)归并排序(D) 0/1背包问题 8、实现循环赛日程表利用的算法是( A )。 (A)分治策略(B)动态规划法(C)贪心法(D)回溯法 9、实现棋盘覆盖算法利用的算法是( A )。 (A)分治法(B)动态规划法(C)贪心法(D)回溯法 10、矩阵连乘问题的算法可由( B)设计实现。 (A)分支界限算法(B)动态规划算法(C)贪心算法(D)回溯算法 11、实现大整数的乘法是利用的算法( C )。 (A)贪心法(B)动态规划法(C)分治策略(D)回溯法 12、最长公共子序列算法利用的算法是( B )。 (A)分支界限法(B)动态规划法(C )贪心法(D)回溯法 13、下列算法中通常以自底向上的方式求解最优解的是( B )。 (A)备忘录法(B)动态规划法(C)贪心法(D)回溯法 14、下列是动态规划算法基本要素的是( D )。 (A)定义最优解(B)构造最优解(C)算出最优解(D)子问题重叠性质15、下列不是动态规划算法基本步骤的是( A )。 (A)找出最优解的解空间(B)构造最优解(C)算出最优解(D)定义最优解 16、能采用贪心算法求最优解的问题,一般具有的重要性质为:( A ) (A)最优子结构性质与贪心选择性质(B)重叠子问题性质与贪心选择性质 (C)最优子结构性质与重叠子问题性质(D)预排序与递归调用 17、下面问题(B )不能使用贪心法解决。 (A)单源最短路径问题(B)N皇后问题 (C)最小花费生成树问题(D)背包问题 18、以下不可以使用分治法求解的是(D )。 (A)棋盘覆盖问题(B)选择问题(C)归并排序(D)0/1背包问题

分治算法

《算法设计与分析》实验报告 实验1 分治算法 一、实验目的 1、掌握分治算法的设计思想与分析方法; 2、掌握归并排序、快速排序等高效排序算法。 二、实验环境 1、硬件环境 CPU:Intel(R) Celeron(R) CPU 1007U @ 1.5GHz 内存:4G 硬盘:500G 2、软件环境 操作系统:Windows7 编程环境:Visual C++ 6.0 编程语言:C++ 三、实验内容 1、编写程序,实现归并排序算法。 (1)归并排序算法 归并排序(Merge Sort)是利用“归并”技术来进行排序。归并是将若干个已排序的子序列合并成一个有序的序列,两路归并算法基本思路为设两个有序的子文件(相当于输入堆)放在同一向量中相邻的位置上:R[low..m],R[m+1..high]。R[low..high]中。 合并过程中,设置i,j和p三个指针,其初值分别指向这三个记录区的起始位置。合并时依次比较R[i]和R[j]的关键字,取关键字较小的记录复制到R1[p]中,然后将被复制记录的指针i或j加1,以及指向复制位置的指针P加1。重复这一过程直至两个输入的子文件有一个已经全部复制完毕,此时将另一个非空的子文件中剩余记录一次复制到R1中即可。

(2)归并排序算法分析 时间复杂度:O(nlog2n) 空间复杂度:O(n) (3)编程要求 ●待排序数组长度至少为16,数组中可以有相同元素; ●按递增排序。 (4)程序代码(含注释) #include #define MAX_OF_ARRAY 20 //打印数据 void PrintArray(int *arrays) { for(int i=0;i void Merge(T c[],T d[],int l,int m,int r) { //把c[l:m]和c[m:r]归并到d[l:r] int i=l,j=m+1,k=l; while((i<=m)&&(j<=r)) { if(c[i]<=c[j]) d[k++]=c[i++]; else d[k++]=c[j++];

相关文档
最新文档