Python数据结构与算法算法分析

| 收藏本文 下载本文 作者:帅的想出书

小编在这里给大家带来Python数据结构与算法算法分析(共含5篇),希望大家喜欢!同时,但愿您也能像本文投稿人“帅的想出书”一样,积极向本站投稿分享好文章。

Python数据结构与算法算法分析

篇1:Python数据结构与算法算法分析

一个有趣的问题经常出现,那就是两个看似不同的程序,到底哪个更好呢?

要回答这个问题, 我们必须知道程序和代表程序的算法有很大的区别. 算法是一个通用的, 解决问题的一条条的指令. 提供一个解决任何具有指定输入的实例问题方法, 算法产生期望的结果. 一个程序, 另一方面, 是将算法用某一门编程语言代码实现. 有很多的程序实现的同一算法, 取决于程序员和编程语言的使用.

进一步的探究这种差异, 考察下面的函数代码. 这个函数解决一个简单的问题, 计算前n个自然数的和. 解决方案遍历这 n 个整数, 相加后赋值到累加器.

def sumOfN(n):

theSum = 0

for i in range(1,n+1):

theSum = theSum + i

return theSum

print(sumOfN(10))

接下来看下面的代码. 第一眼看上去感觉很奇怪, 但是深入理解之后你将发现这个函数和上面的函数完成同样的工作. T原因是这个函数不是那么明显,代码难看. 我们没有使用好的变量名导致可读性很差, 并且还声明了没有必要声明的变量.

def foo(tom):

fred = 0

for bill in range(1,tom+1):

barney = bill

fred = fred + barney

return fred

print(foo(10))

到底哪段代码更好呢.问题的答案取决于你的标准.如果你只关注可读性,函数sumOfN 肯定比 foo 好. 事实上, 你可能在你的编程启蒙课上见到过很多教你编写可读性好和易于理解的程序的例子. 然而在这里, 我们还对算法感兴趣.

作为替代空间的需求, 我们基于它们执行时间来分析和比较算法. 这种度量有时候被称为算法的“执行时间”或“运行时间”. 我们测量 sumOfN 函数执行时间的一种方法是做个基准分析. 在Python, 我们可以通过一个函数针对我们所使用的系统上标记程序的起始和结束时刻. 在 time 模块有一个被称为 time 的函数,将返回系统的当前时间. 通过两次调用这个函数, 起始和结束, 然后计算差值, 我们可以得到准确的执行时间.

Listing 1

import time

def sumOfN2(n):

start = time.time

theSum = 0

for i in range(1,n+1):

theSum = theSum + i

end = time.time()

return theSum,end-start

Listing 1 展示了sumOfN 函数在求和前后的时间开销. 测试结果如下:

>>>for i in range(5):

print(“Sum is %d required %10.7f seconds”%sumOfN(10000))

Sum is 50005000 required 0.0018950 seconds

Sum is 50005000 required 0.0018620 seconds

Sum is 50005000 required 0.0019171 seconds

Sum is 50005000 required 0.0019162 seconds

Sum is 50005000 required 0.0019360 seconds

我们发现时间相当的一致并且都平均花费 0.0019 秒执行程序. 那么假如我们将n增大到 100,000 会怎样呢?

>>>for i in range(5):

print(“Sum is %d required %10.7f seconds”%sumOfN(100000))

Sum is 5000050000 required 0.0199420 seconds

Sum is 5000050000 required 0.0180972 seconds

Sum is 5000050000 required 0.0194821 seconds

Sum is 5000050000 required 0.0178988 seconds

Sum is 5000050000 required 0.0188949 seconds

>>>

再次, 时间更长, 非常的一致,平均10倍的时间. 将 n 增大到 1,000,000 我们达到:

>>>for i in range(5):

print(“Sum is %d required %10.7f seconds”%sumOfN(1000000))

Sum is 500000500000 required 0.1948988 seconds

Sum is 500000500000 required 0.1850290 seconds

Sum is 500000500000 required 0.1809771 seconds

Sum is 500000500000 required 0.1729250 seconds

Sum is 500000500000 required 0.1646299 seconds

>>>

在这种情况下,平均执行时间又一次被证实是之前的10倍.

现在来看一下 Listing 2, 提出了一个不同的解决求和问题的方法. 这个函数, sumOfN3, 运用了一个等式:∑ni = (n+1)n/2来计算前 n 个自然数取代循环计算.

Listing 2

def sumOfN3(n):

return (n*(n+1))/2

print(sumOfN3(10))

如果我们针对 sumOfN3 做一些测试, 使用5种不同的n值(10,000, 100,000, 1,000,000, 10,000,000, and 100,000,000), 我们得到下面的结果:

Sum is 50005000 required 0.00000095 seconds

Sum is 5000050000 required 0.00000191 seconds

Sum is 500000500000 required 0.00000095 seconds

Sum is 50000005000000 required 0.00000095 seconds

Sum is 5000000050000000 required 0.00000119 seconds

对于这个输出,有两个方面需要注意. 第一, 上面程序的运行时间比前面的任意一个的运行时间都短. 第二, 无论n为多大执行时间都是一致的.

但是这个标准真正地告诉我们什么?直观地说, 我们可以看到,迭代的解决方案似乎是因为一些程序步骤被重复而做更多的工作. 这是它占用更多运行时间可能的原因. 当我们增加 n的时候循环方案执行时间也在增加. 然而,有一个问题. 如果我们跑相同的功能在不同的计算机或使用不同的编程语言,我们可能会得到不同的结果. 如果是老式计算机将可能在 sumOfN3上执行更多的时间.

我们需要一种更好的方式来描述这些算法的执行时间,

Python数据结构与算法算法分析

基准的方法计算实际的执行时间。它并不真的为我们提供了一个有用的测量,因为它是依赖于特定的机器,当前时间,编译,和编程语言。相反,我们要有一个特性,是独立于程序或计算机的使用。这一方法将独立地判断使用的算法是有用的,可以用来在实现算法比较。

一个易位构词实例

一个展示算法不同的数量级的例子是经典的字符串易位问题. 一个字符串和另一个字符串如果仅仅是字母的位置发生改变我们就称为易位. 例如, 'heart' 和 'earth' 就互为易位. 字符串'python'和 'typhon' 也是. 为简化问题的讨论,我们假设字符串中的字符为26个英文字母并且两个字符串的长度相同. 我们的目标是写一个boolean 类型的函数来判断两个给定的字符串是否互为易位.

方法1: 逐一检测

对于易位问题,我们的第一个解决方案是检测第一个字符串的每一个字母是否在第二个字符串中. 如果成功检测所有的字母, 那么两个字符串是易位的. 检查一个字母成功后将使用 Python的特殊值 None 取代. 然而, 因为在 Python 中string是不可变的, 第一步将字符串转换成 list. 看下面的代码:

def anagramSolution1(s1,s2):

alist = list(s2)

pos1 = 0

stillOK = True

while pos1 < len(s1) and stillOK:

pos2 = 0

found = False

while pos2 < len(alist) and not found:

if s1[pos1] == alist[pos2]:

found = True

else:

pos2 = pos2 + 1

if found:

alist[pos2] = None

else:

stillOK = False

pos1 = pos1 + 1

return stillOK

print(anagramSolution1('abcd','dcba'))

方法2: 排序比较

另一个解决方案基于的思想是:即使两个字符串 s1 和 s2 不同, t它们易位当且仅当它们包含完全相同的字母集合. 因此, 如果我们首先将两个字符串的字符按照字典排序, 如果两个字符串易位,那么我们将得到完全一样的两个字符串. 在 Python 我们可以使用list的内建方法 sort 来简单的实现排序.看下面的代码:

def anagramSolution2(s1,s2):

alist1 = list(s1)

alist2 = list(s2)

alist1.sort()

alist2.sort()

pos = 0

matches = True

while pos < len(s1) and matches:

if alist1[pos]==alist2[pos]:

pos = pos + 1

else:

matches = False

return matches

print(anagramSolution2('abcde','edcba'))

第一眼看上去,你可能认为程序的时间复杂度为O(n), 因为只有一个简单的比较n个字母的循环. 然而, 两次调用 Python sort 函数都没有考虑开销. 以后我们会介绍, 排序将花费的时间复杂度为 O(n2) 或 O(nlogn), 于是排序相比循环占主导地位.

方法3: 暴力

一个 brute force 计数方法是枚举出所有的可能性. 对于这个问题, 我们可以使用 s1 的字母简单地生成所有的可能字符串并看 s2 是否出现. 然而,这种方法有一个难点. 我们列举出s1的所有可能性,第一个字母有 n 种可能,第二个位置有n-1种可能, 第三个位置有n-2种可能,……. 总共的可能性为:n*(n-1)*(n-1)*3*2*1 = n!.已经证明 n!递增非常快,当n非常大的时候, n! 递增速度超过 2n .

方法4: 计算和比较

最后一个解决方案是基于这样的一个事实:任意两个易位的字符串都有相同的'a'的数目,相同的'b'的数目,相同的'c'的数目……. 为了判断两个字符串是否易位,我们首先计算每一个字母的次数. 因为只有26个可能的字母, 我们可以使用一个list来保存26个计数, 每一个保存可能的字母. 每次当我们看到一个特别的字母,我们就增加对应的计数. 最后, 如果两个list的对应计数完全相同, 两个字符串就是易位的. 看下面的代码:

def anagramSolution4(s1,s2):

c1 = [0]*26

c2 = [0]*26

for i in range(len(s1)):

pos = ord(s1[i])-ord('a')

c1[pos] = c1[pos] + 1

for i in range(len(s2)):

pos = ord(s2[i])-ord('a')

c2[pos] = c2[pos] + 1

j = 0

stillOK = True

while j<26 and stillOK:

if c1[j]==c2[j]:

j = j + 1

else:

stillOK = False

return stillOK

print(anagramSolution4('apple','pleap'))

依然, 这种解决方案包含大量的循环. 然而, 与第一种方案不同, 它们都没有被嵌入. 前两个循环方案都在n的基础上计算字母. 第三个方案的循环, 比较两个字符串中counts的数目, 只需要 26 步 因为一个字符串只有26种可能的字母. 累加在一起我们得到 T(n)=2n+26 步. 即是 O(n). 我们找到了这个问题的线性时间解法.

离开这个例子之前,我们需要说的是空间开销.虽然最后的解决方案能够在线性时间内运行,它能成功必须要通过使用额外的存储保持两个列表中的字符数。换句话说,该算法使用了空间换时间.

这是一种常见的情况. 在许多场合,你需要做出决定的时间和空间之间的权衡。在目前的情况下,额外空间量是不显著的。然而,如果下面的字母有数百万字,就必须更多的关注空间开销。作为一个计算机科学家,当在选定算法的时候,主要由你来决定如何利用计算机资源来解决一个特定的问题.

篇2:python插入排序算法实例分析

作者:pythoner 字体:[增加 减小] 类型:

这篇文章主要介绍了python插入排序算法,通过两个简单实例对比分析了Python插入排序算法的相关实现技巧,需要的朋友可以参考下

本文实例讲述了python插入排序算法,分享给大家供大家参考。具体如下:

def insertsort(array): for removed_index in range(1, len(array)): removed_value = array[removed_index] insert_index = removed_index while insert_index >0 and array[insert_index - 1] >removed_value: array[insert_index] = array[insert_index - 1] insert_index -= 1 array[insert_index] = removed_value

另外一个版本:

def insertsort(array): for lastsortedelement in range(len(array)-1): checked = lastsortedelement while array[checked] >array[lastsortedelement + 1] and checked >= 0: checked -= 1 #Insert the number into the correct position array[checked+1], array[checked+2 : lastsortedelement+2] = array[lastsortedelement+1], array[checked+1 : lastsortedelement+1] return array

希望本文所述对大家的Python程序设计有所帮助,

篇3:进路搜索的数据结构与算法及其仿真

进路搜索的数据结构与算法及其仿真

对铁路车站计算机联锁中的进路搜索,提出基于站场数据结构的'进路自动生成搜索算法.在确定对象节点数据结构的基础上,给出了进路搜索算法的步骤.同时将站场设计功能也包含在程序中,进而可以虚拟出各种不同的站场,根据实验选择不同的进路始点和终点,可达到良好的仿真效果.

作 者:占自才 徐雪松 ZHAN Zi-cai XU Xue-song  作者单位:华东交通大学,电气学院,江西,南昌,330013 刊 名:铁道运输与经济  PKU英文刊名:RAILWAY TRANSPORT AND ECONOMY 年,卷(期): 27(9) 分类号:O29 U284.36+2 关键词:进路搜索   数据结构   联锁设备,节点   仿真  

篇4:JavaScript数据结构与算法之栈详解

这篇文章主要介绍了JavaScript数据结构与算法之栈详解,本文讲解了对栈的操作、对栈的实现实例等内容,需要的朋友可以参考下

在上一篇博客介绍了下列表,列表是最简单的一种结构,但是如果要处理一些比较复杂的结构,列表显得太简陋了,所以我们需要某种和列表类似但是更复杂的数据结构---栈,栈是一种高效的数据结构,因为数据只能在栈顶添加或删除,所以这样操作很快,而且容易实现。

一:对栈的操作。

栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端陈为栈顶。比如餐馆里面洗盘子,只能先洗最上面的盘子,盘子洗完后,也只能螺到这一摞盘子的最上面。栈被称为 “后入先出”(LIFO)的数据结构。

由于栈具有后入先出的特点,所以任何不在栈顶的元素都无法访问,为了得到栈低的元素,必须先拿掉上面的元素。我们可以对栈的两种主要操作是将一个元素 压入栈 和 将一个元素 弹出栈。入栈我们可以使用方法push方法,出栈我们使用pop()方法。pop()方法虽然可以访问栈顶的元素,但是调用该方法后,栈顶元素也就从栈中被永久性的删除了。另一个我们很常用的方法是peek(),该方法只返回栈顶元素,而不删除它。

入栈和出栈的实列图如下:

push,pop()和peek()是栈的三个主要方法,但是栈还有其他方法和属性。如下:

clear():清除栈内的所有元素。

length(): 记录栈内元素的个数。

二:对栈的实现如下:

我们可以先实现栈类的方法开始;如下:

代码如下:

function Stack() {

this.dataStore = [];

this.top = 0;

}

如上:dataStore 是保存栈内的所有元素。变量top记录栈顶的位置,初始化为0. 表示栈顶对应数组的起始位置为0,如果有元素被压入栈。该变量值将随之变化。

我们还有如下几个方法:push(), pop(), peek(),clear(),length();

1. push()方法;当向栈内压入一个新元素时,需要将其保存在数组中变量top所对应的位置,然后top值加1,让其指向数组中下一个位置。如下代码:

代码如下:

function push(element) {

this.dataStore[this.top++] = element;

}

2. pop()方法与push()方法相反---它返回栈顶元素,同时将top值减1.如下代码:

代码如下:

function pop(){

return this.dataStore[--this.top];

}

3. peek()方法返回数组的第top-1个位置的元素,即栈顶元素;

代码如下:

function peek(){

return this.dataStore[this.top - 1];

}

4. length()方法 有时候我们要知道栈内有多少个元素,我们可以通过返回变量top值的方式返回栈内的元素个数,如下代码:

代码如下:

function length(){

return this.top;

}

5. clear(); 有时候我们要清空栈,我们将变量top值设为0;如下代码:

代码如下:

function clear() {

this.top = 0;

}

如下所有代码:

代码如下:

function Stack() {

this.dataStore = [];

this.top = 0;

}

Stack.prototype = {

// 向栈中压入一个新元素

push: function(element) {

this.dataStore[this.top++] = element;

},

// 访问栈顶元素,栈顶元素永久的被删除了

pop: function(){

return this.dataStore[--this.top];

},

// 返回数组中的 top-1 个位置的元素,即栈顶元素

peek: function(){

return this.dataStore[this.top - 1];

},

// 栈内存储了多少个元素

length: function(){

return this.top;

},

// 清空栈

clear: function(){

this.top = 0;

}

};

demo实例如下:

var stack = new Stack();

stack.push(“a”);

stack.push(“b”);

stack.push(“c”);

console.log(stack.length()); // 3

console.log(stack.peek());  // c

var popped = stack.pop();

console.log(popped); // c

console.log(stack.peek()); // b

stack.push(“d”);

console.log(stack.peek()); // d

stack.clear();

console.log(stack.length()); // 0

console.log(stack.peek()); // undefined

下面我们可以实现一个阶乘函数的递归定义;比如5!的阶乘 5!= 5 * 4 * 3 * 2 * 1;

如下代码:

代码如下:

function fact(n) {

var s = new Stack();

while(n >1) {

s.push(n--);

}

var product = 1;

while(s.length() >0) {

product *= s.pop();

}

return product;

}

console.log(fact(5));

上面的代码含义是:先数字5传入函数,使用while循环,每次自减1的之前,把自己使用栈的函数push()压入栈内,直到变量n 小于 1为止,

然后定义一个变量product;通过栈的length()的方法判断是否大于0 且每次执行 product* = s.pop(); pop()方法返回栈顶元素,且从栈中删掉该元素。所以每次执行一次,就删掉一个元素,直到s.length() <= 0 为止。所以 product = 5*4*3*2*1 .等操作。

篇5:算法设计与分析课程论文

算法设计与分析课程论文

“卓越工程师教育培养计划”(简称卓越计划)旨在培养一批创新能力强、适应经济社会发展需要的高质量工程技术人才。在南通大学计算机科学与技术学院制定的软件工程专业卓越工程师的培养计划中,算法设计与分析被设置为一门核心必修课程。通过该门课程的系统授课,重点培养学生的计算机问题求解能力,该能力是软件工程专业学生成长为卓越工程师必备的一项核心竞争力。一个典型的计算机问题的求解一般需要经历5个阶段:①问题的分析和建模;②算法设计方法和相应数据结构的选择;③算法的实现;④算法的正确性证明和复杂度分析;⑤算法实现的优化等。

经过多轮的教学实践发现,学生之间水平参差不齐是教学过程中面临的最大问题。随着高校招生规模的不断增大,不同学生之间在基础知识、智力水平、兴趣爱好、学习动机和学习方法上存在较大的差异性。相同的教学内容,对于一些基础较好的学生来说理解难度不大,但对于一些基础较弱的学生来说,则难以理解。因此,如何尊重学生个性差异、发展学生个性特长,在考虑学生整体发展的同时兼顾学生的个性特长发展,从而最终提高各个层次学生的综合素质是算法设计与分析课程的教学改革实践中需要重点关注的问题。

通过多次与学生的深入交流发现,学生在这门课程的学习过程中面临如下问题:

1)课程教学内容难度高。课程需要学生掌握常见的算法设计策略,如分治法、动态规划法和贪婪法等,对设计出的算法能进行正确性证明和复杂度分析。很多知识点抽象层次高,需要学生具备一定的数学分析能力,同时,通常算法内部逻辑比较复杂,因此需要学生具备较强的编程功底。笔者在讲授这些知识点时,均假设学生具备一定的数学分析能力和编程基础,但实际情况却不容乐观,很多学生在大一和大二的时候并未重视相关课程的学习,很多知识点都已经还给授课老师,在课堂上需要花费一定时间帮助学生回忆这些知识点。同时,部分学生因编程经验较为匾乏,难以顺利地将伪代码转化成可运行的程序代码。

2)学生问题求解能力弱。为辅助学生对知识点的理解,授课老师一般在实例选择时均采用一些经典实例,例如归并排序、最小生成树等。这些问题在一些预修课程(例如高级程序设计语言或数据结构)中均进行过讲解,因此理解起来难度不大。但是,学生在上机实践时,面对老师布置的新问题,却很难将学到的知识进行灵活运用,难以选择合理的算法设计策略,并借助熟悉的高级编程语言去解决。

3)学生自主学习意识薄弱。该门课程本身课时较少(仅有犯学时),其中8学时为上机实践,在剩余的24学时内,仅能讲授基本的算法设计与分析策略。学生即使了解常见的算法设计与分析方法,但现实生活中问题千变万化,更需要学生灵活使用学到的知识。因此,要提高学习效果和实践能力,需要学生在课外花费更多时间,阅读相关资料和进行大量编码。但是,授课过程中发现,真正能够完成自主学习的学生并不多。一方面,很多学生长期受应试教育的影响,习惯于填鸭式的教学模式,同时,学习时具有较强的功利性,很多学生普遍有应付考试和及格万岁的思想,有的`学生甚至为了应付老师的作业检查,大量抄袭作业,仅做一些表面上的修改来敷衍了事。另一方面,即使有少量同学对新知识比较好奇,愿意自己去积极探索,但在选择相关经典资料时经验不足、效率较低,因此,需要有经验的老师进行有效引导。

目前高校很多教室都配有多媒体设备,造成大部分专业课程均采用多媒体课件方式进行授课。多媒体课件虽然具有丰富的表现力、良好的交互性和较高的共享性,但与其他核心专业课程相比,算法设计与分析课程的理论程度更高,数学推导较多,因此笔者认为,采用板书为主的教学方式可能会效果更好。为验证该推测,对Leiserson教授和Demaine教授开设的麻省理工学院公开课的在线视频进行分析,发现他们在授课时,绝大部分教学内容均采用板书方式进行讲解,通过在黑板上一步一步地推导,在一些关键节点上与学生充分交互,使得学生可以更好地掌握算法设计与分析过程中的一些重要技巧。笔者在实际教学中通过精心设计板书,取得了较好的课堂效果。

综上所述,在学生水平参差不齐的情况下,针对算法课程教学中存在的问题,提出了一系列教学改革措施以提高不同层次学生的计算机问题求解能力。其中将教学问题与教学改革措施的对应关系,以及教学改革措施与不同层次学生的对应关系进行总结。而且具备良好的交叉学科基础和文化底蕴,能培养出满足市场需要的复合型人才。

如何使相关专业的教育教学满足将来ICT产业的发展是个相当复杂的问题,希望笔者提出的一些改进措施能对信息科学相关专业的工程教育具有参考意义,并对其他领域也有借鉴之处。

简介二分查找算法与相关的Python实现示例

Python实现的几个常用排序算法实例

论文:分析所得税费用算法新解

百度算法面试题

排序算法总结

了解百度算法 分析关键词与文章的相关性

年终奖个税算法

小学数学简便算法

算法实验体会与总结怎么写

Maslov渐近理论与辛几何算法

Python数据结构与算法算法分析(共5篇)

欢迎下载DOC格式的Python数据结构与算法算法分析,但愿能给您带来参考作用!
推荐度: 推荐 推荐 推荐 推荐 推荐
点击下载文档 文档为doc格式
点击下载本文文档