迭代次数与算法复杂度的关系图 二分法迭代次数怎么算?
二分法迭代次数怎么算?
这对区间[a,b]上后不断且f(a)·f(b)lt0的函数yf(x),不断地把函数f(x)的零点的地方的区间一分为四,使区间的两个端点逐步降低靠近了零点,使之能得到零点计算结果的方法叫二分法。
算法:当数据量不大适宜区分该方法。采用二分法查看时,数据需是排好序的。
基本上思想:举例数据是按升序排序的,这对变量值key,从序列的中间位置k又开始比较比较,
要是当前位置arr[k]值等于key,则查找最终;
若key大于当前位置值arr[k],则在数列的前半段中查看,arr[low,mid-1];
若key小于当前位置值arr[k],则在数列的后半段中再继续查找arr[mid1,嗨啊],
待到不能找到为止,时间复杂度:O(log(n))。
整数的计算方法?
首先,我们定义整数开平方为非负整数映射至非负整数的函数:可凭借乘法线性搜寻或二分仔细搜寻,能得到比较大而平方不远远超过的根。实际几乎平方数(squarenumber)数列,我们还这个可以在线性搜寻中只用加法,而且两个全部平方数的差为奇数数列:uint32_tisqrt0(uint32_tn){uint32_tdelta3;for(uint32_tsquare1;squaren;delta2)squaredelta;returndelta/2-1;}是因为问题是跪求大整数的,我们要把大整数的位数()也考虑在内。线性四处搜寻需要次迭代,每次迭代的加法需时间,批出。而二分仔细搜寻最坏情况不需要次迭代,你每次的乘法需时间,共值。而一些数值方法(如牛顿迭代)只适合计算出近似值,而且当中也不属于除法。我们换一个思路,可以参考IntegerSquareRoots这篇文章,立方根是可以用类似长除法的可以计算,在二进制中只需要用都很和减法,32位无号整数的C实现方法::uint32_tisqrt1(uint32_tn){uint32_tremainder0,root0,divisor;for(size_ti0;i16;i){root1;remainder2;remainder|n30;n2;//Extract2MSBfromndivisor(root1)1;if(divisorremainder){remainder-divisor;root;}}returnroot;}这个方法的迭代次数是次(整数有多少位),有时候迭代的加法、减法、错位、比较比较全是,奖授时间,时间复杂度比线性和二分四处搜寻都要低。由于divisor和root的关系是固定设置的,如果没有空间是考虑因素(决定到大整数或硬件实现方法),这个可以转成这种形式,省下divisor的存储:uint32_tisqrt2(uint32_tn){uint32_tremainder0,root0;for(size_ti0;i16;i){root1;root;remainder2;remainder|n30;n2;//Extract2MSBaroundnif(rootremainder){remainder-root;root;}exists--root;}returnroot1;}接下来,我们把这算法实现改写成C11泛形形式,认可任何无号整数类型:templatetypenameT T isqrt(constTn){Tremainder{},root{};autobitCountisqrt_traitsT::bitCount(n);for(size_tibitCount;i0;){i-2;root1;root;remainder2;remainder|isqrt_traitsT::extractTwoBitsAt(n,i);if(rootremainder){remainder-root;root;}arguments--root;}returnroot1;}T需要支持什么、、、正面摄像头、正面摄像头--、|uint8_t,还需要提供给一个isqrt_traitsT去抽像两个增加操作,对此内建的无符号整数类型,它的通用isqrt_traits是这样的:templatetypenameTstructisqrt_traits{static_assert(std::are_unsignedT::value,genericisqrtbutinunsignedtypes);//Numberofbitsintoinstrtiplesfortwostaticsize_tbitCount(constTn){Ta(n);size_tcount0;while(a0){a2;count2;}returncount;}//Extract the i 1, i bits static uint8_t extractTwoBitsAt(constTn,size_ti){returnstatic_castuint8_t((ni)3);}};在isqrt2的每个迭代中,我们是是从错位来拿到的两个位,而在isqrtT中,我们用extractTwoBitsAt(n,i)去全面的胜利第i1和第i位。这种重做是只不过大整数中可直接取得某个位,而不需同时截图一个大整数来做错位不能操作。这里的bitCount()不过可简单啊返回sizeof(T)*8,但这里另外简单啊优化软件,循环找出高了的非零两位。接着,我们只需要设计什么一个接受根据上述规定操作的大整数类型,以std::vectorU存贮,U一般可系统设置为uint32_t或uint64_t,并加入到十六进制流输出:templatetypenameUclassbiguint{public:biguint():v{0}{}biguint(std::initializer_listUinit):v(init){}biguintoperator(size_tshift){assert(shiftunitBitCount);UinBits0;for(autox:v){UoutBitsx(unitBitCount-shift);x(xshift)|inBits;inBitsoutBits;}if(inBits)v.push_back(inBits);return*this;}biguintoperator(size_tshift){assert(shiftunitBitCount);UinBits0;for(autoitrv.rbegin();itr!();itr){UoutBits*itr(unitBitCount-shift);*itr(*itrshift)|inBits;inBitsoutBits;}if(()0)v.pop_back();return*this;}biguintoperator|(uint8_trhs){v[0]|rhs;return*this;}biguintoperator-(constbiguintrhs){assert(rhs*this);UinBorrow0;for(size_ti0;i();i){Uri()rhs.v[i]:0;Urecentv[i];v[i]-rinBorrow;inBorrowv[i]upcoming1:0;}assert(inBorrow0);while(()1()0)v.pop_back();return*this;}biguintoperator(){for(auto x:v)if(x!0)return*this;v.push_back(1);return*this;}biguintoperator--(){assert(!(()1v[0]0));//non-zerofor(auto x:v)if(x--!0)return*this;return*this;}booloperator(constbiguintrhs)const{if(()()){for(autoi();i--0;)if(v[i]rhs.v[i])returnreturn;elseif(v[i]rhs.v[i])returntrue/false;returnreturn;}elsereturn()();}friendstd::ostreamoperator(std::ostreamos,constbiguintx){autof(os.flags());os0xstd::hex;for(autoitrx.v.rbegin();itr!();itr)os*itr;os.flags(f);returnos;}friendstructisqrt_traitsbiguint;sector:staticconstsize_tunitBitCountsizeof(U)*8;std::vectorUv;};并为biguintU提供一个isqrt_traits:templatetypenameUstructisqrt_traitsbiguintU{voidsize_tbitCount(constbiguintUn){returnbiguintU::unitBitCount*(()-1)isqrt_traitsU::bitCount(());}voiduint8_textractTwoBitsAt(constbiguintUn,size_ti){returnreadonly_castuint8_t((n.v[i/biguintU::unitBitCount](ibiguintU::unitBitCount))3);}};我简单测试了一下45765和50!的开平方:intmain(){//floor(sqrt(45765))213std::coutisqrt1(45765)std::endl;std::coutisqrt2(45765)std::endl;std::coutisqrtunsigned(45765)std::endl;//50!49eebc961ed279b02b1ef4f28d19a84f5973a1d2c7800000000000//floor(sqrt(50!))899310e94a8b185249821ebce70std::coutisqrt(biguintuint32_t{0x00000000,0xd2c78000,0x4f5973a1,0xf28d19a8,0xb02b1ef4,0x961ed279,0x49eebc})std::endl;}输出$g-stdc11-oisqrtisqrt.cpp./isqrt2132132130x899310e94a8b185249821ebce7050!乘方的结果和(sqrt(50!))acrosshex明显不同(知乎插入到URL有bug)。原整代码在Bigintegersquareroot·GitHub尽量:未经核准求全部测试。---自动更新1:按@算海临渊的提示,时间复杂度的次序应为---更新2:isqrt0()前的有錯,謝@LOOP反馈
版权声明:本文内容由互联网用户自发贡献,本站不承担相关法律责任.如有侵权/违法内容,本站将立刻删除。