提出的问题
分而治之的策略
重要的分而治之算法
快速排序
问题
要在一个长为x,宽为y的长方形中画出均匀且大小相等的正方形
那么正方形的边长为多少
(1)可以看出正方形的边长需要是x和y的最大公约数
如何求最大公约数?
找查约数法:
分别找出两个数的所有约数,再找出两个数的所有公约数,最大的那个就是最大公约数(最好别用,太烦人,容易出错)
更相减损法:
任意两个数,判定是否为偶数,是就用2约简,不是就用较大的数减较小的数,所得的差和较小的数比较,再用大的减小的,直到所得的减数和差相等,再用约掉的每个2相乘(如果约掉3个2,就是2^3)z再与所得的相等的数的乘积就是最大公约数【内部原理需要再想想。。。】
辗转相除法:
以小的数除大数,所得的是整数,那这个数就是最大公约数,不然就用余数来除刚才的除数,直到得到整数,这时作为除数的就是最大公约数【思想:处理余数】
算法实现(递归和循环):
#include <bits/stdc++.h>
using namespace std;
int Division(int a,int b)
{
if(b == 0)
{
return a;
}
else
{
return Division(b,a%b);
}
}
int Division_while(int c,int d)
{
while(d!=0)
{
int r = d;
d = c%d;
c = r;
}
return c;
}
int main()
{
int ac ,bc;
scanf("%d %d",&ac,&bc);
if(ac >bc)
{
cout<<"Division:\n"<<Division(ac,bc)<<endl;
cout<<"Division_while\n"<<Division_while(ac,bc)<<endl;
}
else
{
cout<<"Division:\n"<<Division(bc,ac)<<endl;
cout<<"Division_while\n"<<Division_while(bc,ac)<<endl;
}
return 0;
}
(2)如果长不是宽的整数倍,那么假如x = 2*y +m;那么可以画两个边长为y的正方形,还剩下一部分面积,然后再看看可以在剩下的这片区域中画几个最大的正方形(边长等于宽),不断缩小剩余的面积,直到没有剩余为止。【其实类似上面的辗转相除法,都是出来余下的部分,而且在不断缩小问题的规模】
不过问题是,为什么剩余部分的最大正方形就是整个长方形区域的最大正方形呢?
课本上说欧几里得算法已经证明完了
那就看看欧几里得算法
欧几里得算法好像就是辗转相除法(lll¬ω¬),这个算法的实现好像不算是问题(lll¬ω¬)
分而治之的原理
由上面的可以看出,分而治之其实是缩小问题规模再解决
快速排序的实现
先分而治之再归纳证明
分而治之是指如果有一个大规模的数组需要排序,那么可以分成多个小数组排序再组合成大数组,而归纳证明是指我们可以将只有两个元素的数组通过比较进行排序,也可以使用比较对有三个元素的数组进行排序,那么以此类推,我们可以对一个大规模的数组进行排序,通过分而治之可以转变为对两个或三个元素的
问题
如何创建未知大小的数组?
在C中如果创建数组而没有指定大小会报错
int e[];
||=== Build file: "no target" in "no project" (compiler: unknown) ===|
E:\C_code\kuaisupaixu.cpp|11|error: storage size of 'e' isn't known|
要实现元素动态添加有什么方法?
使用STL,vector
这个效率怎么样,消耗资源多么
使用链表
如果需要数组的话,可以再转为数组
使用链表的话,可以很容易的将多个片段连接起来,但是使用连接时需要找到这一段链表的最后一个元素将他的指针指向要连接的元素,仅仅找片段中的最后一个元素就会消耗不少时间及资源
而且这种排序操作几乎打乱了所有指针的指向可能会出现问题,导致指针指向错误
如果是大规模的数组使用快速排序,由于链表的创建,销毁,指针的重新分配以及链表不可随机访问只能一个个访问的原因,也可能会抵消掉快速排序的效率
还是使用数组
(1) 一开始使用malloc,如果元素增加使用realloc,这个方法使用的是堆内存,而堆内存一般受限于虚拟内存,所以一般堆内存比较大,有比较多的空间,这种方法可以实现认为上的动态增加,的确通过再申请空间让人以为空间在增加,好像有更多的空间可以用,实际上也是,
不过问题一是在递归时,保存的映像中使用此操作是所有映像改变还是只影响当前状态
而且如果会有很多元素需要添加那么需要很多次realloc那么会不会消耗很多的资源,让数组在内存中移来移去
(2) 直接创建一个足够大的数组,使用一个位置指针用来代表这个数组用了多少空间,这样不用使用新的方法,还是使用数组,虽然使用了几个大数组,但是不需要再对数组进行什么改变,只需要在数组的不同位置变换元素数值即可
如何在C语言中实现传递数组?
方法有两种:值传递和地址传递(额 一看就差不多了)
值传递
说明和定义函数时,要在数组参数的尾部加上一对方括号([]),调用函数时只需将数组的地址(即数组名)传递给函数
在值传递方式中,数组将被复制一份,复制所得的数组将被存放在栈中
值传递方式的开销是非常大的,
因为首先复制原来数组就会占用额外的内存,
还会有代码去执行复制的操作,
这种操作又会需要比较多的时间,
资源,额外指令,时间都会有消耗,所以效率会比较低
地址传递
地址传递只需要传递个地址就行了,也就是个指针,
#在C/C++不能直接返回一个数组。这是由于在C/C++中,数组不是一种类型,因此不能被直接返回。
#定义了一个数组名之后,他就是常量了,不能再给数组赋值
Python实现
def quicksort(array):
if len(array) < 2:
return arra