算法设计与分析(第四节课——分治算法)

一、快速排序

利用递归和分治的思想,对数组:a[]={10,2,7,8,6,1,4,3,9,5}进行快速排序

  1. 快速排序的思想
    1. 取数组的第一个作为参考标准比较
    2. 将数组中的其它数与之比较,比它大的数和第它小的数,放到原数组的前半部分和后半部分
    3. 然后运用递归的思想对前后两部分进行快速排序
    4. 分治的标准:对应每次排序的数组第一个下标值
  2. 举例:a={4,3,5,8,1,2,6}
    1. 以4标准比较
    2. 分为两部分a1={3,1,2} a2={5,8,6}, a={3,1,2,4,5,8,6}
    4. 第二轮,开始递归:a1以3为标准,a2以5为标准,继续分割为a3,a4,a5,a6

代码:

#include 

int Partition(int a[],int s,int t)
{
	int i=s,j=t; 
	int tmp=a[s];//将第一个数临时存放作为比较值 
	while(i!=j)//当两个下标不相等时 
	{
		while(j>i&&a[j]>=tmp)//如果在数组a尾部的值比tmp大,就将它放在列表a前部 
		  j--;
		a[i]=a[j];   
		while(i<j&&a[i]<=tmp)// 如果数组a前部的值比tmp大,就将它放在列表a的尾部  
		  i++;
		a[j]=a[i]; 
	}    
	a[i]=tmp;//两下标不断靠拢直到i=j,再讲比较值插入中间a[i] 
	return i;	//返回数组中间下标,好进行下一轮的划分 
}


void QuickSort(int a[],int s,int t) //传入数组 ,及数组的起始下标 
{
	if(s<t) 
	{
		int i=Partition(a,s,t);//拆分为左右两部分,分别进行快速排序 
		QuickSort(a,s,i-1);    
		QuickSort(a,i+1,t); 
	}
 } 
 
 
 int main()
 {
 	int a[]={10,2,7,8,6,1,4,3,9,5};
	printf("排序之前的数组为");
	for(int i=0;i<=9;i++)
	printf("%d ",a[i]);
	printf("%\n");
	QuickSort(a,0,9);	
	printf("排序之后的数组为");
	for(int i=0;i<=9;i++)
	printf("%d ",a[i]);	
 }

二、归并排序

对数组:a[]={10,2,7,8,6,1,4,3,9,5}进行归并排序

解法1:递归法

  1. 归并排序的递归法思想
    1. 分割:将一个数组从中中间下标处不断分割,递归直到不可分割为止,以最大下标和最小下标的和的一半为标准,向下取整
    2. 排序、合并:对分割的部分排序,然后将其合并
    3. 递归:然后循环此过程,不断的排序合并
    4. 分治的标准:数组中间下标
  2. 举例:a={5,4,3,2}
    1. 分割
      1. {5,4,3,2}
      2. {5,4}.{3,2}
      3. {5},{4},{3},{2}
    2. 排序,合并(递归2次)
      1. {4,5},{3,2}
      2. {2,3,4,5}
#include
#include
void Merge(int a[],int low,int mid,int high)
{
    int *tmpa;	
	int i=low,j=mid+1,k=0; 
	tmpa=(int *)malloc((high-low+1)*sizeof(int));  //用指针定义一个临时空间 
	while(i<=mid&&j<=high)   //将合并要前半部分和后半部分进行比较,进行排序 
	if(a[i]<=a[j])     //进行比较,将较小的值放入tmpa数组中,直到有前部分和后部分中有一个全部放入到tmpa数组中,退出循环 
	{
		tmpa[k]=a[i]; i++; k++;       
	}
	else
	{
		tmpa[k]=a[j];j++;k++;
	}
	//然后将剩下没有装入数组中得部分,按顺序装入tmpa数组中 
	while(i<=mid)   
	{
		tmpa[k]=a[i];i++;k++;
	}
	while(j<=high)
	{
		tmpa[k]=a[j];j++;k++;
	}
	//重新排列好后将所有的数加入到a数组中,释放掉临时数组tmpa 
	for(k=0,i=low;i<=high;k++,i++)
	  a[i]=tmpa[k];
	free(tmpa);
}

void MergeSort(int a[],int low,int high) //排序主体 
{
	int mid;       //定义中间值 
	if(low<high)    //当前面的起始下标小于终止下标时 
	{
	   mid=(low+high)/2;  	 //取数值中间值,左右两边分割排序 
	   MergeSort(a,low,mid);    
	   MergeSort(a,mid+1,high);
	   Merge(a,low,mid,high);	//分割完之后,将其合并 
	}
}


int main()
{
	int a[]={10,2,7,8,6,1,4,3,9,5};
	printf("排序之前的数组为");
	for(int i=0;i<=9;i++)
	printf("%d ",a[i]);
	printf("%\n");
	MergeSort(a,0,9);	
	printf("排序之后的数组为");
	for(int i=0;i<=9;i++)
	printf("%d ",a[i]);
}

解法2:非递归法

  1. 归并排序非递归思想
    1. 每一次以2指数次方增长进行排序,将多余的数单独排序
    2. 举例 a={5,4,3,2,1}
      1. 以2划分:{4,5},{2,3}{1}
      2. 以4划分:{2,3,4,5},{1}
      3. 以8划分:{1,2,3,4,5}

代码

#include 
#include 
void Merge(int a[],int low,int mid,int high)
{
	int *tmpa;
	int i=low,j=mid+1,k=0;    
	tmpa=(int *)malloc((high-low+1)*sizeof(int)); //申请一个临时指针数组空间 
	while(i<=mid&&j<=high)    //将左右两组数进行比较,将它们放入数组tmpa中,直到有一个数组放完 
	  if(a[i]<=a[j])
	    {
		  tmpa[k]=a[i];i++;k++;
		  }
	   else
	   {
	   	  tmpa[k]=a[j];j++;k++;
	   }
	while(i<=mid) //将另一个没放完的数组放入数据 
	{
		tmpa[k]=a[i];i++;k++; 
	}
	while(j<=high)
	{
		tmpa[k]=a[j];j++;k++;
	}
	for(k=0,i=low;i<=high;k++,i++)//最后将数据转入a数组,释放临时指针 
	  a[i]=tmpa[k];
	free(tmpa);
}


void MergePass(int a[],int length,int n) 
{
   int i;
   for(i=0;i+2*length-1<n;i=i+2*length)	  //将其分割每一次以2*length长度分割,之后会分割的片段慢慢变大    
	 Merge(a,i,i+length-1,i+2*length-1);  //对其排序 
	 
    if(i+length-1<n)	//如果分割有部分则单独排序 
	  Merge(a,i,i+length-1,n-1);
}


void MergeSort(int a[],int n) //排序输入数组,及数组长度 
{
	int length;   // 
	for(length=1;length<n;length=2*length)  //那么lengh依次为 1   2   4    8
	     MergePass(a,length,n);   
 } 
 
 int main()
 {
 	int a[]={10,2,7,8,6,1,4,3,9,5};
	printf("排序之前的数组为");
	for(int i=0;i<=9;i++)
	printf("%d ",a[i]);
	printf("%\n");
	MergeSort(a,10);	
	printf("排序之后的数组为");
	for(int i=0;i<=9;i++)
	printf("%d ",a[i]);	
 }

你可能感兴趣的:(#,2.算法分析与设计)