一、算法抽象

它们一般是在具体算法的基础上总结、提炼、分析出来的,再反过来用于指导解决其它问题。它们适用于某一类问题的解决,用辩

证法的观点看,抽象的算法和具体的算法就是抽象与具体、普遍性与特殊性、共性和个性的关系。马是白马的抽象,无论是白马还是红

马,都是马,我们用马的唯一本质属性——染色体来决定一种动物是否是马,这个本质属性就是马的抽象。

(1)分治法

分治法的基本思想是先分割原问题,将原问题分割成一个或多个简单的子问题,这些子问题的解经过一定组合得到原问题的解,而求

解这些子问题时,常常会再次分解,组合,即迭代上面的过程。再进一步总结可以得到分治法的步骤:分解、求解子问题、组合。而至

于怎么分解、组合,分治法没有抽象出规律。自己想怎么做就怎么做,比如归并排序和快速排序,都是用的分治法,但分解和组合过程

不一样。分治法适用于解决易分解为子问题的问题。

我们可以给出分治法的伪代码框架,针对某个具体的问题,需进行适当的修改,比如参数个数等,由于数学功底不是很牛B,我没有办

法证明该框架适用于所有的递归函数和所有基于分治法的算法,但我还没有发现不适用的情况。还有,如果子结节是直接在原问题对象上进

行的操作,那有时子结节就不需要返回值(返回None就行)给父结点了,父结点也不会用这些结点的返回值,因为所有结点操作的是同

一个共享资源,这点见快速排序;另外,对于像二分查找,对于任意一次查找的过程,它其实只是走的某个结点到根结点的路径而已,它

每次分解后只用到其中一个结点,这样它也就没有merge()可言了。

看了下面代码,是不是感觉跟MapReduce的思想有些相似,是的,MapReduce其实是就是基于分治法思想的。MapReduce中的Map

就对应下面的map()方法,而Reduce其实是merge()方法的一种特例而已,因为merge()是根据具体问题而定的,不一定就是迭代函数。

因为MapReduce是基于分治法的,所以适用场景与只能是分治法适用场景的一个子集。

def handler(obj):
end_ret = is_end(obj)
if end_ret[0]== True: #递归结束点
return end_ret[1]
else: #非结束点,递归调用
subnode_tuple = separate(obj) #该节点分割,分割为一个或多个子节点
subnode_rettuple = map(handler, subnode_tuple) #求解每个子节点的解,递归调用
node_ret = merge(subnode_rettuple,obj) #将子节点的解组合,组合时有时也会用到节点的某些数据
return node_ret

二、 具体算法

(1)冒泡排序

这是最简单的一种排序方法,每次遍历后找出最大的数,冒泡排序是稳定排序,时间复杂度为O(n^2)

OK,我们先看一下一次遍历怎么做,由简单到复杂,这样把问题分解一下,其实感觉并没有那么难了,这也是分治法的思想。

#一次排序
def bubble_sort(s):
i = 0
for index in range(i,len(s)):
if s[index] > s[i]:
s[i],s[index] = s[index],s[i]
return s

然后把代码修改一下,真正的冒泡排序出来如下

#冒泡排序
def func(s):
length = len(s)
for i in range(length):
for index in range(i,length):
if s[index] > s[i]:
s[i],s[index] = s[index],s[i]
return s

(2)快速排序

快速排序其实是用的分治法的思想,归并排序也是用的分治法,同样都是分治法,但策略不同。我们在“分治法”中提到分治法分为三

个步骤:分解、求解子问题、组合。快速排序和归并排序的不同体现在分解上,分解不同,后面的组合也常常不同。快速排序在分解时

会有一定的排序,也就是边分解边求解,它们是在原对象上直接进行的操作,操作完也不需要组合。归并的主要工作在组合上,分解过

程非常简单,归并的过程也完全可以在原对象(原序列)上进行。

快速排序一次分割会把序列中的某一个元素(任意选择一个即可)确定好位置,并把序列以该元素为界分为两部分,一部分大于等于

该元素,另一部分小于等于该元素,然后再递归分解这两部分(确定好位置的那个元素无需再排序,不用放在这两部分中),直到分割

的部分只有一个元素或为空。递归就是树的分解过程,子节点可以直接操作原问题对象(原序列),操作完之后,相当于原序列的某个

部分就是有序的了。这样子结节无需再返回值让父节点用了。下面是快速排序代码,第一个没用分治法框架,第二个用了。子结点和叶

节点其实不需用返回值,但为了更好的用分治法框架理解,还是让他们返回值好了。

#-*- coding=utf-8 -*-
def qsort(s,start_index,end_index):
if start_index>=end_index:
if start_index == end_index:
return [s[start_index]]
else:
return []
else:
i = separate(s,start_index,end_index)
#不用考虑索引为i的元素,它已经排好序了
left_ret = qsort(s,start_index,i-)
right_ret = qsort(s,i+,end_index)
node_ret = left_ret + [s[i]] + right_ret
return node_ret #分治,排好start_index的位置,并将序列分为两部分
def separate(s,start_index,end_index):
key = s[start_index]
empty_index = start_index #空位指针
track_index = end_index #跟踪指针
while empty_index != track_index:
if track_index > empty_index:
if s[track_index] < key:
s[empty_index] = s[track_index]
track_index,empty_index = empty_index,track_index
track_index +=
else:
track_index -=
else:
if s[track_index] > key:
s[empty_index] = s[track_index]
track_index,empty_index = empty_index,track_index
track_index -=
else:
track_index +=
s[empty_index] = key
return empty_index a = [,,,,,,,,,,,,,,,,,]
b = qsort(a,,len(a)-)
print a
print b

使用分治法框架,与不使用的代码相比,只是微小的重构而已。

# -*- coding=utf-8 -*-
def qsort(obj):
s = obj[0]
start_index = obj[1]
end_index = obj[2]
end_ret = is_end(obj)
if end_ret[0]== True:
return end_ret[1]
else:
i = separate(obj)
#不用考虑索引为i的元素,它的位置已经确定了
subnode1 = (s,start_index,i-1)
subnode2 = (s,i+1,end_index)
subnode_tuple = (subnode1,subnode2)
subnode_rettuple = map(qsort,subnode_tuple)
node_ret = merge(subnode_rettuple,obj[0][i])
return node_ret def is_end(obj):
s = obj[0]
start_index = obj[1]
end_index = obj[2]
if start_index>=end_index:
if start_index == end_index:
return (True,[s[start_index]])
else:
return (True,[])
else:
return (False,None) #分治,排好start_index的位置,并将序列分割成两部分
def separate(obj):
s = obj[0]
start_index = obj[1]
end_index = obj[2]
key = s[start_index]
empty_index = start_index #空位指针
track_index = end_index #跟踪指针
while empty_index != track_index:
if track_index > empty_index:
if s[track_index] < key:
s[empty_index] = s[track_index]
track_index,empty_index = empty_index,track_index
track_index +=1
else:
track_index -=1
else:
if s[track_index] > key:
s[empty_index] = s[track_index]
track_index,empty_index = empty_index,track_index
track_index -=1
else:
track_index +=1
s[empty_index] = key
return empty_index def merge(subnode_rettuple,obj):
return subnode_rettuple[0] + [obj] + subnode_rettuple[1] a = [12,3,9,10,87,25,8,9,47,11,1,100,85,47,59,81,60,33]
obj = (a,0,len(a)-1)
b = qsort(obj)
print a
print b

(3)二分查找

二分查找的条件是序列必须是有序的,下面假设是从小到大排序的序列,如果查找成功返回下标,如果失败,返回None。两种方法的代码均测试通过

方法一:使用递归

#使用递归,递归中只创建一个序列对象s,而没使用s的切片,这样做可以节省内存
def binary_search(s,start_index,end_index,key):
if start_index <= end_index:
mid_index = (start_index + end_index)/2
if key == s[mid_index]:
return mid_index
elif key > s[mid_index]:
return func(s,mid_index+1,end_index,key)
else:
return func(s,start_index,mid_index-1,key)
else:
return None

方法二:使用循环

#使用循环,其实就是把递归简单改一下就可以了
def binary_search(s,start_index,end_index,key):
while start_index <= end_index:
mid_index = (start_index + end_index)/2
if key == s[mid_index]:
return mid_index
elif key > s[mid_index]:
start_index = mid_index + 1
else:
end_index = mid_index - 1 return None

下面使用循环方法测试

>>> a = [2,8,20,77,190,490]
>>> binary_search(a,0,len(a)-1,1)
>>> binary_search(a,0,len(a)-1,300)
>>> binary_search(a,0,len(a)-1,490)
5
>>> binary_search(a,0,len(a)-1,77)
3
>>>

算法抽象及用Python实现具体算法的更多相关文章

  1. python数据结构与算法

    最近忙着准备各种笔试的东西,主要看什么数据结构啊,算法啦,balahbalah啊,以前一直就没看过这些,就挑了本简单的<啊哈算法>入门,不过里面的数据结构和算法都是用C语言写的,而自己对p ...

  2. python数据结构与算法之算法和算法分析

    1.问题.问题实例.算法的概念区分. 一个例子说明一下: 问题:判断一个正整数N是否为素数   #问题是需要解决的一个需求 问题实例:判断1314是否为素数? #问题实例是该问题的一个具体例子 算法: ...

  3. python数据结构与算法之问题求解

    懂得计算机的童鞋应该都知道,一条计算机程序由数据结构跟算法两大部分组成.所以,其实不管你使用哪种计算机语言编写程序,最终这两部分才是一个程序设计的核心.所以,一个不懂得数据结构与算法的程序员不是一个好 ...

  4. Python 数据结构和算法

    阅读目录 什么是算法 算法效率衡量 算法分析 常见时间复杂度 Python内置类型性能分析 数据结构 顺序表 链表 栈 队列 双端队列 排序与搜索 冒泡排序 选择排序 插入排序 希尔排序 快速排序 归 ...

  5. Apriori算法的原理与python 实现。

    前言:这是一个老故事, 但每次看总是能从中想到点什么.在一家超市里,有一个有趣的现象:尿布和啤酒赫然摆在一起出售.但是这个奇怪的举措却使尿布和啤酒的销量双双增加了.这不是一个笑话,而是发生在美国沃尔玛 ...

  6. 【转】你真的理解Python中MRO算法吗?

    你真的理解Python中MRO算法吗? MRO(Method Resolution Order):方法解析顺序. Python语言包含了很多优秀的特性,其中多重继承就是其中之一,但是多重继承会引发很多 ...

  7. Python数据结构与算法--List和Dictionaries

    Lists 当实现 list 的数据结构的时候Python 的设计者有很多的选择. 每一个选择都有可能影响着 list 操作执行的快慢. 当然他们也试图优化一些不常见的操作. 但是当权衡的时候,它们还 ...

  8. Python数据结构与算法--算法分析

    在计算机科学中,算法分析(Analysis of algorithm)是分析执行一个给定算法需要消耗的计算资源数量(例如计算时间,存储器使用等)的过程.算法的效率或复杂度在理论上表示为一个函数.其定义 ...

  9. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

随机推荐

  1. Nginx(五)-- 配置文件之Rewrite

    Rewrite支持URL重写 1.常用指令以及语法 1) if指令    if语法: if 空格 (condition) {}     条件:     1. “=” 来判断相等,用于字符的比较     ...

  2. [Linux] 如何修改 Linux 主机名

    该方法适用于安装了 Linux 系统的Raspberry Pi & Cubieboard. 在终端执行: sudo vi /etc/hosts 你看到的 hosts 文件应该是这样的: 127 ...

  3. 深入浅出MFC——MFC多线程程序设计(七)

    1. 从操作系统层面看线程——三个观念:模块(MDB).进程(PDB).线程(TDB) 2. “执行事实”发生在线程身上,而不在进程身上.也就是说,CPU调度单位是线程而非进程.调度器据以排序的,是每 ...

  4. iOS富文本组件的实现—DTCoreText源码解析 渲染篇

    本文转载至 http://blog.cnbang.net/tech/2729/ 上一篇介绍了DTCoreText怎样把HTML+CSS解析转换成NSAttributeString,本篇接着看看怎样把N ...

  5. Centos6下Python3的编译安装

    本文转载自 Centos6下Python3的编译安装 系统环境:CentOS 6.8-Minimal 安装Python依赖包: 1 [root@Python src]# yum install zli ...

  6. 在apache虚拟目录配置

    在apache虚拟目录配置中 <VirtualHost *:80>xxx xxx xxx</VirtualHost> 不能写成 <VirtualHost *>xxx ...

  7. 怎样在excel中快速输入当前日期和时间

    找到并启动我们的Microsoft Excel软件,如图   在excel中,我们先演示如何快速输入当前“日期”,先在一个“单元格”里面输入“Ctrl+:”(就是“Ctrl“键和“:”键的组合),效果 ...

  8. vsCode_1.27.2

    User Settings: 一,当前行高亮显示: "editor.renderLineHighlight": "line", 二,如何呈现空白字符(一般选no ...

  9. C#中XML的读取

    本文主要介绍在C#中有关XML的读取,写入操作. 1.XML的内容如下: <?xml version="1.0" encoding="utf-8" ?&g ...

  10. Linux下openoffice与SWFtools的安装

    第一部份:OpenOffice的安装 1.Openoffice的官网:http://www.openoffice.org/download/index.html 选择Linux 64-bit(x860 ...