分治

马上要期末考试了,来写点博客吃吃吧,哦不学学吧
分治法的三点:
1.原问题能够分解成为若干个规模小,相互独立,与原问题类型相同的子问题。
2.子问题足够小可以解决
3.能够将子问题的解组合成原问题的解。
算法分析:时间复杂度的递推公式为
T(n)=aT(n/b)+cn^k;
T(1)=c;
有待补充!
分治法求最大元最小元问题

void findmaxmin(int i,int j,int max,int min)
{
	
	if(i==j)
	max=min=a[i];
	if(i==j-1)
	{
		if(a[i]>a[j])
		{
			max=a[i];
			min=a[j];
		}
		else
		{
			max=a[j];
			min=a[i];
		}
	}
	int m=(i+j)/2;
	findmaxmin(i,m,max,min);
	findmaxmin(m+1,j,max1,min1);
	if(max<max1) max=max1;
	if(min<min1) min=min1;
	
}

最好最坏都运行3n/2-2次(推倒过程有待考量)。但是在运行时,由于使用递归的办法,空间消耗(效率也比较低下)会比较大,未必是有利的,所以说在数目很小的情况下,不建议使用递归算法,但是比较希望得到相对应得迭代算法。
二分搜索
需要注意的是对半搜索要求随机存取位于划分点m处的元素,所以一般使用顺序表,而不是链接储存。
二叉搜索树
性质1.具有n个内节点的对半二叉搜索树的左孩子有(n-1)/2的向下取整节点,右孩子有n/2向下取整个
节点。
根据定义可以证明此点的正确性。
性质2:n个节点的二叉判定树的高度至少是n/2向下取整。
证明:因为高度为h的二叉树至少有2^h-1个节点(??)
性质3:若n=2^h-1 则对半搜索二叉树一定是满二叉树。
性质4:若搜索树是满二叉树,则外节点一定在h+1层,否则要么在h层,要么在h+1层。
性质5:对半搜索算法在成功搜索的情况下,关键字之间的比较次数不超过logn(向下取整)+1即不会超过判定树的高度,显而易见(最坏的情况)
平均时间复杂度应该是logn(??)
排序
两路合并排序,两个数组每次输出最小值,时间复杂度是o(n)
运用递推的合并排序算法,结果是o(nlogn)
快速排序,在之前一篇算法基础博客中已经提到了
所以就不再赘述原理了
下面讨论快速排序的时间复杂度,快速排序的时间复杂度最优便是 O(nlogn)即每一个序列恰好可以排成两份,最坏时间复杂度就是有一方是空集的情况哈,这时候的时间复杂度就是O(n)了,所以快速排序不太稳定。
快速排序的代码如下:

int parition(int left int right)
{
	int i,j;
	int i=left;
	j=right;
	do
	{ 
	do i++; 
	while(a[i]<a[left])
	do j--;
	while(a[j]>a[left])
	if(i<j)
	swap(i,j);
	}while(i<j) 
	 swap(left,i);
	return j;
}
void quicksort(int left,int right)
{
	if(left<right)
	{
		int t=parition(left,right);
		quicksort(left,t-1);
		quicksort(t+1,right);
	}
}

改善快速排序性能的办法
1)改变主元法:三种选择主元的办法,选取中间值(left+right)/2作为主元。
2))选取left~right之间的随机数作为主元,这个会增加随机函数的时间复杂度
3))选取left right left+right的中间值的三者的平均值作为主元。
2)在数列划分足够小时,可以改变算法的办法,使用直接排序法可以进行直接的计算
3)递归算法的效率不是很高,所以我们可以一个堆栈对数组(这个具体实现过程,我会进一步搞定的)。
降低空间复杂度的办法,就是降低进栈的过程。
可以只进一部分栈,对另一部分进行操作,时间复杂度就是O(logn)
分治法求解第k小元素的问题:
步骤1:随机选择主元,若随机选的主元最终位置为j,j恰好等于k,那么我们就可以直接解决,如果不是就可以使用二分法继续往下搜索。
具体代码如下:

void sortlist(int left,int right)
{
do
{

//随机选择主元
int j=rand()%(right-left+1)+left;
swap(left,j);//交换主元的位置,将其置于0的位置;
int t=parition(left,rigth) ;//确定交换好的parition的位置,然后进行计算。
if(k==t+1)
flag=true;
if(k>t+1) 
right=t;
if(k<t+1)
left=t+1;
}while(flag==true);
}

这就是寻找第n个元素的算法,那么这个算法的最坏时间复杂度是O(n^2).最好是O(n)所以
还需要改进,改成线性时间的选择算法,
采用二次取中法,对算法进行计算
二次取中法的实现原则如下:首先将n个数据平均分成n组,将每一组选区一个中间值,再从选取的中间值中再选取中间值,
举个例子
序列:41 76 55 19 59 63 12 47 67 45 26 74 33 18 65 86 49 77 35 80 53 19 97 22 52 62 39 60 59 29 72 31 56 91 76
首先将这些数组按每七个一组划分成五组
1:41 76 55 19 59 63 12
2:47 67 45 26 74 33 18
3:65 86 49 77 35 80 53
4:19 97 22 52 62 39 60
5:59 29 72 31 56 91 76
第一步调用直接插入排序法找到中间值
1:55
2:45
3:65
4:60
5:59
并且把他们交换到最前端,同时将数组进行合并,得到画线后的七个中间值。
后求出中间值以59为主元进行分划操作,发现59位于下标为7的地方所以说,需要在左边进行深度搜索,再调用一遍函数,在此区间内进行搜索一直到搜到为止。
时间分析就是O(n)的算法。
代码:

int Select(int left,int right,int k)
{
	//首先如果数据很小就可以使用直接插入排序
	 if(n<=maxm)
	 {
	 	Insertsort(left,right);
		 return left+k-1;//直接就可以求得结果了 
	  } 
	  for(int i=1;i<=n/r;i++)
	  {
	  	Insertsort(left+(i-1)*r,left+i*r-1);
	  	swap(left+(i-1)*r,left+(i-1)*r+Ceil(r,2)-1);
	  }
	  int j=Select(Ceil(n/r,2),left,left+(n+r)-1);//u1s1不太明白 大概就是因为你把所有的都放在了最前面,所以选取的时候,从左边往后选择 
	  Swap(left,j);
	  j=parition(left,right);
	  if(k==j-left+1)
	  return j;
	  else if(k>j-left+1)
	  return Select(j+1,right,k);
	  else
	  return Select(left,j-1,k-(j-left+1));
	  
	 
	  
}

斯特拉森矩阵乘法
普通的矩阵乘法他的时间复杂度是O(n^3),所以我们需要降低一个时间复杂度。
分治法在矩阵乘法中的应用大概就在于分块进行计算。
斯特拉森矩阵乘法将时间复杂度降低为了O(n^2.81)虽然说也不太快,但是至少提供了一个更加有用的数据计算方法。
课后习题与总结,将会在后面给出。
终于写完了啊啊啊啊啊啊啊啊啊
我好累啊!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值