生活资讯
基础算法 、基础算法知识
2023-04-04 17:00  浏览:58

数据结构有哪些基本算法

数据结构中最基本的算法有:查找、排序、快速排序,堆排序,归并排序,,二分搜索算法

等等。

1、用的最多也是最简单的数据结构是线性表。

2、有前途的又难数据结构是图 。

3、常用的80%算法是排序和查找。

排序常用的算法有:插入算法(直接插入算法、折半插入算法、希尔算法)、选择算法(简单选择算法、堆排序算法)、快速算法(冒泡排序、快速排序算法)

以下程序给出了各种算法的实现,其接口为void sort(int *arr***,int len),每个文件实现一个算法, 最后和main.c文件编译实现。

1、直接插入算法://direct_insert_sort.c

2、折半插入排序://binary_insert_sort.c

3、希尔排序://shell_sort.c

4、简单选择排序://simple_select_sort

一年级上册数学基础算法

小学一年级的数学学习是数学的基础入门,只有把这部分的内容学好了,才能让孩子在数学王国中快乐地遨游,我整理了一年级上册数学基础算法,希望能帮助到您。

小学一年级数学基础加减法规律和法则

加法

(1)两个数相加,保持得数不变:如果相加的这两个数有一个增大了,则另一个数就要减小,且一个数增大了多少,另一个数就要减少多少。

(2)两个数相加,其中的一个数不变,如果另一个数变化则得数也会发生变化,且加数变化了多少,结果就变化多少。

(3)两个数相加,交换它们的位置,得数不变。

减法

(1)一个数减去另一个数,保持减数不变:如果被减数增大,结果也增大且被减数增大多少,结果就增大多少;被减数减小,则结果也减小,且被减数减小多少,结果也减小多少。

(2)一个数减另一个数,保持被减数不变:如果减数增大,结果就减小,且减数增大了多少,结果就减小多少;如果减数减小,则结果增大,且减数减小了多少,结果就增大多少。

(3)一个数减另一个数,保持得数不变:被减数增大多少,减数就要增大多少;被减数减小多少,减数也要减小多少。

先教分解

加法,实际上就是:将两个集合和在一起,变成一个集合。

减法:将一个集合分开,分成两个。

孩子真正的理解加减法的意义,不是算会那道题,而是理解加减法之间的关系。

比如:6个苹果,可以分成2个和4个苹果,也可以反过来说是4个和2个苹果,同时,2个和4个苹果(或者4个苹果和2个苹果)合起来就是6个苹果。

也就是说:

1、从分解组合开始教孩子,一边分,一边用语言表述,一定要用嘴巴说出来,能说出来的孩子,表示她自己真的掌握了。

2、从5以内的开始。先从分解2开始。

3、每次分开后表述完,要记得在合起来。

打基础的方法

1、学数数

学计算之前先学数数,这谁都知道,但是利用多种数数形式来为计算打基础,却被相当多的父母所忽视。不少父母在孩子会唱读1~100之后就认为孩子已学会了数数,而可以教计算了,但实际上孩子并没有真正建立数的概念,也没有真正掌握计数的技巧。

数数的内容其实很多,除了要建立数的一对一的概念以外,还要包括多种数数的技能,主要形式有:

①N加1,即按递增1的顺序正着数,这是学N加1计算的基础;

②N减1,即按递减1的顺序倒着数,这是学N减1计算的基础;

③数单数,建立奇数概念;

④数双数,建立偶数概念;

⑤逢10数,建立进位概念;

⑥逢5数,将5作为一个基本单元,这是一个很重要的数数技能,因为在提高数数和计算技能方面,5的重要性仅次于10。

2、计算N加1,凡是能正着依次数数并理解其含义是依次递增1个的幼儿,都能轻而易举地学会计算N加1,包括10加1、20加1、99加1乃至100加1。

3、计算N减1,凡是能倒着数数并理解其含义是依次递减1个的幼儿都能学会计算N减1的题,包括11减1,21减1、100减1乃至101减1。

4、整10相加或相减,如10加10、20加10、……90加10,凡是会逢10数数并理解其含义是依次递增或递减10个的幼儿都能很容易地学会。

5、整5相加或相减,如0加5、5加5、10加5乃至95加5,凡是会逢5数数并理解其含义是递增或递减5个的幼儿,掌握起来并不难。

6、计算10加N,包括10加1、10加2……10加9,幼儿一旦理解10加几就等于十几,不仅能快速运算10加N,还能推广至20加N、30加N乃至90加N。

7、两个相同数相加,包括1加1、2加2……9加9,对于会数双数的幼儿,当发现两个相同的数相加后的结果都是双数时,便会很容易地学会运算这类题。教学实践发现,幼儿普遍对两个相同数相加的题有自发的关注与兴趣,因而幼儿对这组题的掌握往往要先于10以内非N加1的题。

8、计算两数之和等于10的题,包括1加9、2加8、3加7、4加6及5加5,这组题的熟练与否对于进行10以上的运算是至关重要的。

9、口算(20以内),当幼儿已掌握了上述技能之后,就可以做20以内的口算题了。父母应注意提醒幼儿学会运用已掌握的计算技能来推算其它题,如由2加2等于4而推知2加3等于5,由3加7等于10而推知3加6等于9,9加9等于18而推知9加8等于17,等等。

10、竖式笔算(100以内),口算100以内的数即使是对学龄儿童也是不容易的,可是列成竖式之后,凡具备上述技能的学龄前幼儿稍加指点即可完成运算,因为一道两位数相加的题列成竖式后实际上就变成了两道一位数相加的题。目前,5岁左右的幼儿都在幼儿园里学会了书写阿拉伯数字,因而这个年龄段的幼儿进行独立的竖式运算是完全可能的。

编故事的方法

我在教孩子10以内的加减法运算的时候,经常编一些小故事,让孩子参与其中,不知不觉孩子就学会了运算。而且,每次孩子都对这种小故事表现出非常浓厚的兴趣,学起加减运算来非常轻松。

比如,学习8的加减法,我编了一个这样的小故事,其中经常和孩子互动一下,互相提问,甚至让孩子把故事编下去:

小猴子要买8个苹果送给奶奶。它来到市场上,看见红苹果挺诱人的,绿苹果也挺好的,于是,这两种苹果它一样买了几个。(红苹果买5个,绿苹果买几个?)

小猴子拎着装了8个苹果的框高高兴兴地往奶奶家走去。路上同小猪撞了一下,结果撞掉一个苹果,它们都不知道。(这时还剩几个苹果了?)

小猪是小猴子的好朋友,见到小猴很高兴。小猪说口渴了,小猴子就给小猪一个苹果解渴。(这时还剩几个苹果?)

看到小猪吃苹果吃得津津有味的,小猴子也想吃,于是它也拿了一个苹果吃了起来。(这时还剩几个苹果?)

突然,背后响起一声狮子的吼声:“吼——”不好了,狮子看见小猴子了,快跑啊!小猴子拎着框使劲往前跑,框里的苹果噼里啪啦地往外掉。

好不容易跑到奶奶家了,狮子也没有追来,小猴子终于松了口气。小猴子把苹果送给奶奶,可是它往框里一看:“咦?怎么只剩下2个苹果了呢?”

奶奶听完小猴子讲的途中的遭遇后,哈哈笑了起来。奶奶对小猴子说:“你来了就是***的礼物了!”

就这样,故事讲完了。讲的过程中我还不时让孩子算算还有几个苹果,而后面的遇到狮子的事情也是孩子自己编出来的。整个过程非常轻松,既让孩子开拓了思维,又达到了学习的目的。

凑十法

凑十法是20以内进位加法的基本思路。运用凑十法能将20以内的进位加法转化为学生所熟悉的10加几的题目,从而化难为易。例如9+5,将5分成1和4,因为9凑十缺1,所以要分出1。所以9+5,就分解计算9+1=10、然后10+4=14,所以,孩子要牢记“9要1”、“8要2”、“7要3”、“6要4”、“5要5”凑十法简便易行,思考过程有“一看(看大数),二拆(拆小数),三凑十,四连加”

应该是用破十法:12可以分成10和2,用10-9=1,再用1+2=3,所以12-9=3

在教学中,我深有体会,低年级数学教学,使学生学好“两法”非常重要。“两法”即“凑十法”和“破十法”。凑十法是几和几合成十;破十法是从10里面拿出几还剩下几。

比如:教7+8=15有两种算法。一种是一个一个地加,算式:7+1+1+1+1+1+1+1+1=15,或8+1+1+1+1+1+1+1=15,这种方法对于接受能力差的学生不错,但这样加太繁,又浪费时间,多数同学都不适用。而凑十法就简便多了,方法是想8和几或7和几合成十(8和2、7和3),那么从7里面拿出2,7拿出2还剩下5元,或从8里面拿出3,8拿出3还剩下5,算式:8+2=10,10+5=15;或7+3=10,10+5=15。

教几加几等于十几,只要教会学生想几和几合成十,从几里面拿出几还剩下几,那么10加几就等于十几。

又如:教15-9=6有四种算法。一是用数数方法,一个一个地减,算式:15-1-1-1-1-1-1-1-1-1=6;二是用“平十”的方法先减5,再减4,算式:15-5=10,10-4=6;三是用“想加算减”的方法,想9加几等于15,15减9就等于几;四是用“破十法”,即把15分成10和5,10-9=1,1+5=6。几法比较,我觉得“破十法”最管用。***种数数法太繁,浪费时间;第二种“平十法”先减5,再减4,因为这个“平十”不固定,有时是5,有时是6,有时是4……中间这个几和几合成9或几加几等几也就不固定,对于接受能力差一点的学生不好学;第三种“想加算减”就更难了。

我认为“两法”既好教又易学。因为“凑十”只有五组:1+9、2+8、3+7、4+6、5+5,我把它当成5个生字词来教给学生记,而1+9、5+5都比较容易记,剩下3个也不难,课前经常反复练习,师:1和9,生:凑成十;师:2和8,生:凑成十;师:倒过来,生:8和2凑成十;师“3和7……这样久而久之就能熟能生巧,所以教十几减几时,只要让学生懂得十几可以分成10和几,10减几剩下几,几十几=几就可以了。好几个接受能力较差的同学学了“两法”后,作业基本独立完成。如:12-7,他们很快就能说出:“10-7=3,3+2=5”13-8呢?“10-8=2,2+3=5。”从这些差生转化来看,教好“两法”非常重要。

而“两法”既互相联系,又互相转化,学生只要掌握“凑十法”,“破十法”也就容易了,但愿教低年级数学的老师都能教好学生学好“两法”,“两法”对提高教学质量起着重要的作用。

儿歌法 一加九,十匹小马骝;

1+9 10匹小马骝

2+8 10只老母鸭

3+7 10只小公鸡

4+6 10个小皮球

5+5 10只大老虎

6+4 10只水彩笔

7+3 10根小竹竿

8+2 10只小白鹅

算法基础

谨以此文,感谢我在这个学校最喜欢的两个老师之一——肖my老师。本文基本为老师上课说讲授内容加上一部分自己的感悟拼凑而来,写作文本的目的是为自己的算法课程留下一点点东西,站在老师肩膀上形成粗糙的框架,方便以后的复习以及深入。文笔有限,其中包含的错误还请多多包容,不吝赐教。

to do list:

时间复杂度中递归树法;动规,分治新的感悟;

点覆盖:一组点的集合,使得图中所有边都至少与该集合中一个点相连。

支配集:一组点的集合,使得图中所有的点要么属于该集合,要么与该集合相连。

***团:在一个无向图中找出点数最多的完全图。

独立集:一组点的集合,集合中的顶点两两不相邻。(团转过来)

SAT问题:也称布尔可满足性问题。给一组变

其中Ci被称为句子。

点覆盖-独立集-***团

最小割:割是一组边集。如s-t割就是如果去掉这些边,将把原图划分为两个点集,其中一个点集包含s,一个点集包含t。(两个是指不相连,而不是代表不存在边相连,如反向边)

decision problem: 是否存在。

search problem:找到一个解。

(这个还能扩展,比如decision problem在多项式时间内解决,所以他是P问题吗)

渐进符号:

注意以上三种都是紧的,对应的两个小写的符号是不紧的,即如下图所示:

概念:算法的时间复杂度是一个函数,用于定性描述算法的运行时间。注意,这个一个代表算法输入字符串长度的函数。

[注]输入字符串长度是一个比较关键的理解,比如在背包问题中,其时间复杂度为O(nW),因为W不定,所以只能是一个伪多项式时间。

比较:c log2N n n * Log2N n^2 n^3 2^n 3^n n! n^n

大致:常数对数幂函数指数函数阶乘

对于指数是n相关的进行比较,优先比较指数,再比较底数。

记住一个特例:n (logn)n!n n

计算:

一般来说,计算采用主方法和递归树法,其中递归树技巧性比较强,主方法其实也是递归树推导归纳而来,且主方法能得到一个比较紧的结果。

主方法:

f(n) = af(n-b)+g(n) =O( a^(n/b) *g(n) )

P:decision problems有一个多项式算法。

NP(nondeterministic polynomial-time):decision problems能够在多项式时间内验证。

NPC:NP完全问题,首先这个问题是NP的,其次,其他所有问题都可以多项式时间内归约到它。

NPH:如果所有NP问题都可以多项式时间归约到某个问题,则称该问题为NP困难。

因为NP困难问题未必可以在多项式时间内验证一个解的正确性(即不一定是NP问题),因此即使NP完全问题有多项式时间的解(P=NP),NP困难问题依然可能没有多项式时间的解。因此NP困难问题“至少与NP完全问题一样难”。

一些NP问题能在多项式时间内解决,因为 P∈NP

NP难类型问题的证明:

先选好一个已知NP难的问题,然后将已知NP难问题多项式归约到要证明的问题上。先给出这个归约,然后再证明这个归约的正确性。

NPC类型问题的证明:

证明一个问题Y是NPC问题,先说明Y是NP的,然后找到一个NPC问题X,将这个问题X归约到问题Y上,即证明完成。

常见的NPC问题(重要,规约的时候有用!):

packing problems: set-packing,独立集

覆盖问题:集合覆盖问题,顶点覆盖问题

严格满足问题(constraint satisfaction problems):SAT,3SAT

序列问题:哈密尔顿回路,旅行商问题

划分问题:3D-matching, 3着色问题

数字问题:子集合问题(子集元素之和为t),背包问题

其他:分团问题(是否存在一个规模为k的团)

规约的概念与理解

规约:意味着对问题进行转换,例如将一个未知的问题转换成我们能够解决的问题,转换的过程可能涉及到对问题的输入输出的转换。

自归约:search problem =p decision problem

归约:A归约到B,也就是说,我们对A套一个函数f,在f函数的作用下形成一个新的问题,对这个问题运用B的黑盒解法,能够解决问题A。

(B =p A)一般说来,B问题如果可以归约到A问题,也就是说,一个解决A问题的算法可以被用做子函数(子程序)来解决B问题,也就是说,求解B问题不会比求解A问题更困难。因此,如果B问题是困难的,那么A问题也就是困难的,因为不存在求解A问题的高效算法。(最后一句不懂)

我简单说一下我理解的规约,以X规约到Y为准,大概分成两个方面:

注:在 三 的一些实例中细品。

概念:在对问题求解时,总是做出在当前看来是***的选择。

贪心的证明:先假设贪心算法得到的解不是***解,假设S1是贪心算法得到的解,而S2是所有***解中和S1具有最多相同元素的解,然后比较S1和S2,观察S1和S2中***个(最前面一个)不一样的元素,然后在贪心解S2中将不一样的元素换成S1中的那个元素得到另一个***解S3,这样S3和S1比S2和S1有更多相同元素,和假设S2是与S1有最多相同元素的***解矛盾,这样来推导S1是***解。

我的理解:假设这个不是***的,但是一定存在一个***的解在某一个位置之前和我当前解结构是一样的,那么在这个位置,选***解也可以选当前解,不影响最终答案。

[注]概念很简单,但是实际操作的时候,贪心的角度很重要,同样的贪心,方向对了,算法就是对的。

例子:

给你一系列活动,每个活动有一个起始时间和一个结束时间,要求在活动不冲突的情况下找到一种有最多活动的安排。

对于这个问题,我们有一下几种贪心的角度:

①将任务按照 开始时间 升序排列。

②将任务按照 结束时间 升序排列。

③将任务按照 任务时长 升序排列。

④对于每一个任务,都记录与其他任务冲突的数量,按照 冲突数量 的升序排列。

其中1,3,4都是不可以的。

任务结束时间的贪心证明(反证法):

假设贪心不是最***的,那我们在***解中找一个与当前解有最相似的解。

由图可以知道,贪心贪的就是最早结束,所以如果不是***,那么***的结束时间一定晚于贪心的结束时间。

由上图就可以证明。

***流通常与最小割相联系。

f 为任意一个流,cap为容量,对于任意的s-t割出来的点集(A,B),v( f ) = cap(A, B)。

当流增加到与割的容量相等时候,就不可能再有增长空间了,称为***流。

对于割的容量来说,不同的割法会有不同流量,有些割法永远不会有流达到,比如部分A = {s}, B = {V - s},这种把源点割出来的割法。

综上,通过这种感性的认识,如果能找到一个最小的割,那么这个割就一定是***能跑到的流(如果流能更高的话在这个割上就会超过容量,反证。)

上图为一条增广路,一条增广路即为一条s-t的路径,在路径上仍有流可以跑,其曾广的流就是该条路径上最小的剩余容量。(相当于每找一条增广路,就至少有一条边达到满流。)

直到在图中找不到增广路,此时已经达到了***流。

找ST集合:把满流的边去掉,从S出发走到能到的点,遍历的点就是S集合;剩下的点就属于T集合。注意,如果找到了在找S集合的时候找到了T点,说明还可以继续找增广路。

[补]有一个很有趣的延伸,如多源点多终点问题。问:如果我有两个源点s1,s2,两个终点t1,t2,我想求一组流,使得s1-t1,s2-t2的流达到***,是否可以加一个源点S,S与s1,s2相连,边流无限大;加一个终点T,T与t1,t2相连,边流无限大,然后这组ST的***流即可。——答案是No,无法保证是s1-t1,s2-t2,有可能交错。

例子讲的感觉不是特别好,对理解感觉起不到很大作用,希望以后有新的想法后进行补充。

规约是一个重要的概念和思想。

一个图的 ***独立集 与 最小点覆盖 是不相交的两个点集,它们的并就是整个点集。

个人理解:独立集和点覆盖都是从点的角度进行划分的,如果我们从边的角度来看,①一个最小的点覆盖即为我集合中的每一个点都尽可能与更多的边相连,②同时,一条边的两个端点中,只能有一个端点在最小点覆盖中[下注]

[注]我们假设有一条边两个端点(u,v)都在点覆盖之中,首先显然u,v都不是端点,因为假设u是端点的话只需要选择v即可;

给一个集合S和一堆S的子集S1,S2,...,Sm,问是否存在存在k个子集,使它们的并集为S。

构造:

集合为点,集合中的元素为边,有相同元素的边相连。(注意如果某一元素只在一个子集中出现,应该怎么处理呢!)

规约:在构造的图中找最小的点覆盖,选中的点能覆盖所有的边即为对应集合的并集能包含所有的元素。所以就完成了集合覆盖到点覆盖的规约。

构造:每个句子构造一个三角形,把对应变量但是相反取值的点相连。

规约:3SAT的有一个特点就是,每一个句子中至少有一个为真即可,每个句子都必须是真。将相同变量相反取值相连的目的就是,在***独立集中,比如选择x为真,则剩下所有句子中x-ba一定不会被选中,同时由独立集和构造出来三角形的性质可以知道,每一个句子,有且仅有一个会被选中(为真)。如上图,x1-ba为真,x2-ba和x3任选一个为真即可满足。

search problem =p decision version

比如:如果能在多项式时间内找到一个哈密尔顿圈,那么就能在多项式时间内找到一个哈密尔顿圈(删边)

在此再谈P和NP:

我们知道有些问题是可以从搜索问题规约到判断问题的,也就是所该问题如果能在多项式内判断,那么久能在多项式中搜索到,那么我们只需要说,这个判断问题能在多项式时间内求解,就叫做P问题,也就是上图红字的意思;那NP问题呢,必须要给出一个解的实例,判断的是这个实例是否满足求解问题,这个才是上图中的红字。比如,我如果能在多项式时间内判断哈密尔顿圈是否(Yes/No)存在,那这个就是ploy-time algorithm,如果我给出了一系列点,能过多项式时间内判断这些点能否构成哈密尔顿圈,那这个就是poly-time certifier。

构造:把一个点拆分成三个点。

构造:(下面两个图要连在一起看)

从行的角度看,一行代表一个变量;从列的角度来看,每三列代表一个句子。两边中一边是两个点,一边是一个点,所以有k个句子的话,每一行有3k+3个节点。从哈密尔顿圈的答案转到3SAT的答案看这个圈在每一行是从左到右还是从右到左。

子集和问题:给一个集合S,问是否能在集合中选取元素,使得总和为W。

构造:如下图,按照前六行和前三列进行分割,可以分成4部分,其中1,3,4部分是固定的,即在***部分,变量v列和 变量为v(包括变量及取反)的行对应的格子为0,其余为0;第三部分全为0;第四部分按照12依次写下来。第二部分,如果Ci句子中有变量v,则记为1,因为一个句子只有三个变量,可以简单通过第二部分每一列和为3进行判定。此时集合已经构造出来,W为111444,与上面的规约相似,可以通过3SAT的简单性质进行感性的认知。

近似的想法很简单,要解决一个问题,我们希望能够做到①求解结果是***的 ②在多项式时间内解决 ③对于任意的实例都能够通过该算法解决。现在对于部分问题,无法完全满足以上要求,所以就牺牲了①,但是我们希望结果不是盲目的,所以就引入了近似的概念。

近似算法。比如2-近似,认为W为近似解,W 为***解,在求最小值的情况下W=2W ;在求***值的情况下,W=1/2W*

给m个机器和n个任务,每个任务有一个ti的执行时间,我们认为完成最后一个任务所需的时间为负载时间,希望能够让这个负载时间最短。

***种:将任务依次放在机器上,当某个机器空闲时立即放入新任务。此时是2近似的。

证明:

引理1.最短时间安排是大于等于任务中时间最长的任务,L* = max tj

我们在考虑放入最后一个任务前,根据我们放置的规则,该机器是耗时最短,也就是说,该机器此时的用时是低于除掉最后一个任务后的平均时长,更低于所有任务的平均时长(引理2);再根据引理1,最后一个任务应该是小于***解的。

补充:

在这里,我还想讨论一下这个近似算法的中等于符号,先上结论:等号不一定能够找到一个实例,但是可以构造出一种结构,通过取极限求得,我们认为这样 也算是紧的。

构造实例:有m个机器,其中m(m-1)个任务的用时为1,1个任务的用时为m。肯定有一种任务集合,可以按照以下方式进行安排,此时的贪心解为19。

此时***的解为10,如下图:

通过推广可以知道此时的比为(2m-1)/m,当m取极限,能够达到2倍。

第二种:将任务从大到小排序,然后依次放在机器上,当某个机器空闲时立即放入新任务。此时是2近似的。

引理3:如果有大于m个任务,那么L*=2t(m-1)。证明:t(m+1)是目前最短的任务,且目前所有机器上都有任务了,所以该任务加入时***的情况不过是加入设备的原有任务刚好和t(m+1)相等,即等号。

(2近似)在n个点中,选取k个中心点,使得这些中心点能够以半径R的圆包含所有的点,让其中***的半径最小,如下图所示:

基础:距离需要满足的三个定理①(同一性)dist(x, x) = 0 ②(自反)dist(x, y) = dist(y, x) ③(三角不等式)dist(x, y) =dist(x, z)+dist(z, y)

r(C)为C集合中所有点的***覆盖半径。(需要求min r(C))

算法:在点集中任选一个作为中心点,然后重复以下步骤k-1次:选取距离已选点集中最远的点,加入点集。

证明:先假设r(C ) 1/2 * r(C)以选好的点画半径为1/2 * r(C)的圆,显然可知[注],这个圆里有且仅有一个r(C )中的点。那么根据在下图中,根据三角不等式可以得出:

[注]在每个点上r(c )一定会包含到c点,而r(C )1/2 * r(C),相当于大圆套小圆,所以c*一定在c的圆中。

(2近似)问题还是很好理解的,在点上加权值,要找一个点覆盖,使得权值最小。如下图左边就是一个带权的最小点覆盖。

算法: 任选一条边(i, j)加上代价,这个代价从零开始,且这个代价的***值低于i和j节点的权值。显然,这个边权值的***值取决于两个端点权值的最小值,我们认为当边权值与点权值相等时,对应的那个点是紧的。把所有紧的点找出来即为点覆盖。

流程:

证明:

引理:边权之和小于等于点覆盖的点权之和。这主要是由于涉及到一条边上两个点都被选(紧的)的情况,感性认知可以看上图,缩放证明如下:

w(S)是等于所选的节点的权值之和的,等于所选节点节点所对应的边权之和,可以把它放大到所有节点对应边权之和,这样因为一条边(u, v)在u上算过一次后还要在v上算一次,所以等于边权和的两倍。再由上面引理可得。

主要为了线性规划和整数规划。

(2近似)没啥好说的,只需要把方程构造出来就行了。

由于求解出来结果不一定是整数,所以我们认为某一点的值大于1/2,就选入点集。

证明:

因为xi+xj =1,且都是正数,那必至少一个点是大于1/2的(反证,两个都小于1/2则和小于1)。

给你n个物品和一个背包,每个物品有一个价值v和一个大小w,背包的容量是W,要求让背包装下尽可能大价值。

背包的时间复杂度:O(nW)

注意其中n表示物品的个数,无论是1个还是999个,他都是多项式的,这个很好理解。但是W就不一样了,这是一个数字。我理解的是这个数字会很奇特,比如1.00001,比如99999,这些有可能看起来不大但是实际在处理的时候很难处理的数字,统一的来说,如果我们把这些数字放在电脑上,都会以二进制的方式存储起来,有些数字用十进制表示很小,但是放在二进制上面就会很大,由W导致不能在多项式时间内解决(找不到一个范围/上界来框它)。

算法: 为了处理这个问题,我们改动了dp的状态转移方程,要让这个转移方程和W无关[注]。

此时还不是多项式的,然后我们再对value进行约。[注]

[注]这两步中,我们把w改成v,并对v进行近似处理。OPT的含义变成了,在面对是否选择第i个物品时,要想让价值达到当前值,最少的weight。理由是更改后的误差是可以忍受的:对v进行近似,结果只会出现***价值的上下误差,如果对w进行近似,则有可能出现该物品不能放入背包中,导致整个物品直接放弃的情况。

编程的基础算法有哪些?

1、二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^(i 1)个结点。

深度为k的二叉树至多有2^k 1个结点;对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0 = n2 + 1。二叉树算法常被用于实现二叉查找树和二叉堆。

2、递归算法(英语:recursion algorithm)在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。

递归算法能够解决的问题

数据的定义是按递归定义的。如Fibonacci函数。

问题解法按递归算法实现。如Hanoi问题。

数据的结构形式是按递归定义的。如二叉树、广义表等。

作为程序员提高编程能力的几个基础算法

一:快速排序算法

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序n个项目要Ο(nlogn)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(nlogn)算法更快,因为它的内部循环(innerloop)可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法(Divideandconquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

算法步骤:

1从数列中挑出一个元素,称为“基准”(pivot),

2重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

3递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的***部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

二:堆排序算法

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

堆排序的平均时间复杂度为Ο(nlogn) 。

创建一个堆H[0..n-1]

把堆首(***值)和堆尾互换

3.把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置

4.重复步骤2,直到堆的尺寸为1

三:归并排序

归并排序(Mergesort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(DivideandConquer)的一个非常典型的应用。

1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2.设定两个指针,最初位置分别为两个已经排序序列的起始位置

3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

4.重复步骤3直到某一指针达到序列尾

5.将另一序列剩下的所有元素直接复制到合并序列尾

四:二分查找算法

二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(logn) 。

五:BFPRT(线性查找算法)

BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分析,BFPRT可以保证在最坏情况下仍为线性时间复杂度。该算法的思想与快速排序思想相似,当然,为使得算法在最坏情况下,依然能达到o(n)的时间复杂度,五位算法作者做了精妙的处理。

1.将n个元素每5个一组,分成n/5(上界)组。

2.取出每一组的中位数,任意排序方法,比如插入排序。

3.递归的调用selection算法查找上一步中所有中位数的中位数,设为x,偶数个中位数的情况下设定为选取中间小的一个。

4.用x来分割数组,设小于等于x的个数为k,大于x的个数即为n-k。

5.若i==k,返回x;若ik,在小于x的元素中递归查找第i小的元素;若ik,在大于x的元素中递归查找第i-k小的元素。

终止条件:n=1时,返回的即是i小元素。

六:DFS(深度优先搜索)

深度优先搜索算法(Depth-First-Search),是搜索算法的一种。它沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。DFS属于盲目搜索。

深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如***路径问题等等。一般用堆数据结构来辅助实现DFS算法。

深度优先遍历图算法步骤:

1.访问顶点v;

2.依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;

3.若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

上述描述可能比较抽象,举个实例:

DFS在访问图中某一起始顶点v后,由v出发,访问它的任一邻接顶点w1;再从w1出发,访问与w1邻接但还没有访问过的顶点w2;然后再从w2出发,进行类似的访问,…如此进行下去,直至到达所有的邻接顶点都被访问过的顶点u为止。

接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止。

七:BFS(广度优先搜索)

广度优先搜索算法(Breadth-First-Search),是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。

BFS同样属于盲目搜索。一般用队列数据结构来辅助实现BFS算法。

1.首先将根节点放入队列中。

2.从队列中取出***个节点,并检验它是否为目标。

如果找到目标,则结束搜寻并回传结果。

否则将它所有尚未检验过的直接子节点加入队列中。

3.若队列为空,表示整张图都检查过了——亦即图中没有欲搜寻的目标。结束搜寻并回传“找不到目标”。

4.重复步骤2。

八:Dijkstra算法

戴克斯特拉算法(Dijkstra’salgorithm)是由荷兰计算机科学家艾兹赫尔·戴克斯特拉提出。迪科斯彻算法使用了广度优先搜索解决非负权有向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。

该算法的输入包含了一个有权重的有向图G,以及G中的一个来源顶点S。我们以V表示G中所有顶点的集合。每一个图中的边,都是两个顶点所形成的有序元素对。(u,v)表示从顶点u到v有路径相连。我们以E表示G中所有边的集合,而边的权重则由权重函数w:E→[0,∞]定义。因此,w(u,v)就是从顶点u到顶点v的非负权重(weight)。边的权重可以想像成两个顶点之间的距离。任两点间路径的权重,就是该路径上所有边的权重总和。已知有V中有顶点s及t,Dijkstra算法可以找到s到t的***权重路径(例如,最短路径)。这个算法也可以在一个图中,找到从一个顶点s到任何其他顶点的最短路径。对于不含负权的有向图,Dijkstra算法是目前已知的最快的单源最短路径算法。

1.初始时令S=,T=,T中顶点对应的距离值

若存在V0,Vi,d(V0,Vi)为V0,Vi弧上的权值

若不存在V0,Vi,d(V0,Vi)为∞

2.从T中选取一个其距离值为最小的顶点W且不在S中,加入S

3.对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值

重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止

九:动态规划算法

动态规划(Dynamicprogramming)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和***子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。

动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。

关于动态规划最经典的问题当属背包问题。

1.***子结构性质。如果问题的***解所包含的子问题的解也是***的,我们就称该问题具有***子结构性质(即满足***化原理)。***子结构性质为动态规划算法解决问题提供了重要线索。

2.子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

十:朴素贝叶斯分类算法

朴素贝叶斯分类算法是一种基于贝叶斯定理的简单概率分类算法。贝叶斯分类的基础是概率推理,就是在各种条件的存在不确定,仅知其出现概率的情况下,如何完成推理和决策任务。概率推理是与确定性推理相对应的。而朴素贝叶斯分类器是基于独立假设的,即假设样本每个特征与其他特征都不相关。

朴素贝叶斯分类器依靠精确的自然概率模型,在有监督学习的样本集中能获取得非常好的分类效果。在许多实际应用中,朴素贝叶斯模型参数估计使用***似然估计方法,换言朴素贝叶斯模型能工作并没有用到贝叶斯概率或者任何贝叶斯模型。

尽管是带着这些朴素思想和过于简单化的假设,但朴素贝叶斯分类器在很多复杂的现实情形中仍能够取得相当好的效果。

通过掌握以上算法,能够帮你迅速提高编程能力,成为一名优秀的程序员。

关于基础算法和基础算法知识的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

发表评论
0评