tip:需要提前明白理解递归。

汉诺塔经典问题

汉诺塔问题源自印度一个古老的传说,印度教的“创造之神”梵天创造世界时做了 3 根金刚石柱,其中的一根柱子上按照从小到大的顺序摞着 64 个黄金圆盘。梵天命令一个叫婆罗门的门徒将所有的圆盘移动到另一个柱子上,移动过程中必须遵守以下规则:

  • 每次只能移动柱子最顶端的一个圆盘;
  • 每个柱子上,小圆盘永远要位于大圆盘之上;

通过分析移动思路,可以总结出一个规律:对于 n 个圆盘,分为a(起始柱),b(辅助柱),c三根柱子的汉诺塔问题,移动圆盘的过程是:

  1. 将起始柱a上的 n-1 个b通过c移动到b上;
  2. 将起始柱a上遗留的 第n个圆盘移动到c上;
  3. 将辅助柱b上的所有圆盘通过a移动到目标柱c上。

下面进行代码复现:

def hannuo(n,a,b,c):if n>0:hannuo(n-1,a,b,c)print("moving from %s to %s "%(a,c))hannuo(n-1,b,a,c)hannuo(3,'A','B','C')

运行结果:

moving from  A  to  C
moving from  A  to  C
moving from  B  to  C
moving from  A  to  C
moving from  B  to  C
moving from  B  to  C
moving from  A  to  C

查找算法

查找:用一定的方法,查找与给定关键字相同的数据元素的过程。

列表查找

输入需要查找的列表和元素,输出下标。没有则返回none,或-1.------index()函数

顺序查找

从第一个元素开始搜索,直到找到元素,或者直达列表最后一个元素。

代码复现:

del line_search(li,val):for ind,v in enumerate(li):if v==val:return indelse:return None

简单来说就是遍历,直至找到该元素。

时间复杂度:O(n)

二分查找

前提是排序,通过与中间值比较大小得出相应区间,然后再次二分,与二分法找零点道理相似。

代码复现:

def binary_search(li,val):left=0right=len(li)-1while left<= right:  #确定选区有值mid = (left+right)//2if li(mid) == val:return midelif li(mid) > val:right=mid-1  #操作后会进入下一个循环else:left=mid+1else:return None

这里的循环虽然没有像之前举例一样,有明显的次数减半的操作,但是通过对算法的理解,我们能明白这是每次减半的过程,所以

时间复杂度:O(logn)

排序算法

将无序数列,组合成有序数列的过程叫做排序。

列表排序

输入列表,输出有序列表。----内置函数sort()

冒泡排序

过程:通过比大小不断地交换 前后的值,直至形成一个有序数列。每次循环结束,有序区增加一位,无序区减少一位

利用代码复现,从最坏情况中举个例子。

假设四个,且顺序为完全导致。

那么第一次:

[4, 3, 2, 1]
#第一次排序,从4开始
[3, 4, 2, 1]
[3, 2, 4, 1]
[3, 2, 1, 4]
#完成了对4的排序,开始第二次排序
[2, 3, 1, 4]
[2, 1, 3, 4]
#完成了对3的排序,开始第三次排序
[1, 2, 3, 4]
#此时,第三次排序本质是对2进行排序,但对2排完序即最后一个元素也相应的归位了

则冒泡排序需要外循环n-1次。内循环(假设我们有n个元素) ,那么代码复现:

def bubble_sort(li):for i in range(len(li)-1):for j in range(len(li)-i-1):if li[j]>li[j+1]:li[j],li[j+1]=li[j+1],li[j]print(li)

时间复杂度:O(n^2)

当然,冒泡排序也可以优化,如没有发生交换则证明有序可以停止进程。

def bubble_sort(li):for i in range(len(li)-1):exchange=Falsefor j in range(len(li)-i-1):if li[j]>li[j+1]:li[j],li[j+1]=li[j+1],li[j]exchange=Trueif not exchange:return

选择排序

第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置(或新序列),然后再从剩余的未排序元素中寻找到最小(大)元素(或新序列),然后放到已排序的序列的末尾。

def select_sort(li):li_new=[]for i in range(len(li)):min_val=min(li)li_new.append(min_val)li.remove(min_val)return li_new

虽然代码简单,但必须要注意的是,使用的函数min本身也在遍历列表。

时间复杂度:需要考虑寻找min的方法复杂度。

插入排序

假设有序区为第一个数(一张牌),此时不断地从无序区抽取新的数,放到有序区的正确位置(抽牌并插入正确位置),知道无序区没有数字(没牌了)完成排序。

def insert_sort(li):for i in range(1,len(li)):#默认第一个数为有序区tmp=li[i]j=i-1 #有序区的最后一个数,也是最大的一个数while j>=0 and tmp < li[j]:#此时抽到的牌比最大的牌小,若比有序区最大值大则不进行操作,只将小的值向前排序li[j+1]=li[j] #已知牌向后推移,给抽到的牌让位li[j]=tmp #在原来的位置用更小的赋值j-=1  #向前移,直到没有数比选定值大

时间复杂度:O(n^2)

快速排序

思路:1)选定值,将其快速排到正确位置。

2)正确位置的值使得无序数列被分为了两部分小的无序数列

3)递归,直至完成排序

代码复现:

def partition(li,left,right):tmp=li[left]while left<right:while left<right and li[right] >=tmp:#从最右边寻找小于tmp的数right-=1 #right左移直至退出循环(找到小于tmp的值或者与left相等)li[left]=li[right]while left<right and li[left] <=tmp:left+=1li[right]=li[left]li[left]=tmpreturn leftdef quick_sort(li,left,right):if left<right:mid= partition(li,left,right)quick_sort(li,left,mid-1)quick_sort(li,mid+1,right)

利用partition函数完成对选定值的定位,利用quick_sort递归调用。

此时的时间复杂度,不能单单从几次循环来判断,要深刻的理解算法的过程。 推荐下面这个·链接,讲得非常清晰。

需要理解,快速排序效率提高的来源是什么。

(26条消息) 如何理解快速排序的时间复杂度是O(nlogn)_sun123704的博客-CSDN博客_快速排序时间复杂度为什么是nlogn

一般来说,时间复杂度:O(nlogn)

堆排序

树结构是一种非线性存储结构,存储的是具有“一对多”关系的数据元素的集合。

(A)                                                                        (B)

 1 树的示例

树的结点

结点:使用树结构存储的每一个数据元素都被称为“结点”。

父结点(双亲结点)、子结点和兄弟结点:对于图 1(A)中的结点 A、B、C、D 来说,A 是 B、C、D 结点的父结点(也称为“双亲结点”),而 B、C、D 都是 A 结点的子结点(也称“孩子结点”)。对于 B、C、D 来说,它们都有相同的父结点,所以它们互为兄弟结点

树根结点(简称“根结点”):每一个非空树都有且只有一个被称为根的结点。树根的判断依据为:如果一个结点没有父结点,那么这个结点就是整棵树的根结点。

叶子结点:如果结点没有任何子结点,那么此结点称为叶子结点(叶结点)。

结点的度

对于一个结点,拥有的子树数(结点有多少分支)称为结点的度(Degree)。 一棵树的度是树内各结点的度的最大值。

二叉树

满足以下两个条件的树就是二叉树:

  1. 本身是有序树;
  2. 树中包含的各个节点的度不能超过 2,即只能是 0、1 或者 2;

满二叉树

如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。

完全二叉树

如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。

二叉树的顺序存储结构

指的是利用列表储存二叉树。仅需从根节点开始,按照层次依次将树中节点存储到数组即可。

假设现在一棵非完全二叉树,拿一棵普通的二叉树举例,一棵普通二叉树有5种形态(空树、只有根结点、只有左子树、只有右子树、左右子树都有),从形态上来看可能是一棵“残缺不全”的二叉树,如果从根结点开始从1 挨个编号,然后在存进一维数组中,那么有些结点可能没有孩子,那么它原本的孩子在数组中的位置就会被后面上来的的结点占据,这样就无法通过下标寻找相应的规律。

只有完全二叉树才可以使用顺序表存储。

将父节点设为i,则左孩子结点为2i+1,右孩子为2i+2.

大根堆: 若根节点存在左右子节点,那么根节点的值大于或等于左右子节点的值。
小根堆: 若根节点存在左右子节点,那么根节点的值小于或等于左右子节点的值。

堆排序最重要的是两个部分:向下调整和创造堆。

具体过程不描述了,太繁琐。

代码复现:

def sift(li,low,high): #完成向下调整#li:列表 low:#堆的根结点位置(下标)#high:堆的最后一个元素位置(下标)i = low #i指向根结点j = 2*i+1 #j根节点对应的左孩子tmp= li[low] #将堆顶储存while j <= high: #不能溢出,j下标必须有数if j+1<= high and li[j+1] > li[j]:#右孩子大于左孩子j = j+1if li[j] > tmp: #将孩子与父亲比较,如果孩子大li[i] = li[j] #孩子上移i=jj=2*i+1else:   #父亲更大,停止交换breakelse:li[i]=tmp #将根结点的值储存回去def heap_sort(li):#构建堆n=len(li)for i in range((n-2)//2,-1,-1):#从最后一个叶子结点开始构造子树,完成大根堆sift(li,i,n-1)for i in range(n-1,-1,-1): #将找出来的最大数存到下面,不浪费新的内存空间li[0],li[i] = li[i],li[0] #这是最重要的一步!!!按序输出的根本sift(li,0,i-1)#此时high永远是最后一层,不需要考虑其他子树

时间复杂度:O(nlogn)--不要深究,理解为主。

归并排序

将两个有序列表通过归并合成新列表。

通过比较有序列表的相同位,将更大(小)的元素储存在新列表中。

def merge(li,low,mid,high):i=lowj=mid+1ltmp=[]while i<=mid and j<=high:if li[i]<li[j]:ltmp.append(li[i])i+=1else:ltmp.append(li[j])j+=1while i<=mid:ltmp.append(li[i])i+=1while j<=high:ltmp.append(li[j])j+=1li[low:high+1]=ltmp #切片的end不包含自己
def merge_sort(li,low,high):if low<high:mid =(low+high)//2merge_sort(li,low,mid)merge_sort(li,mid+1,high)merge(li,low,mid,high)#充分理解一个元素就是有序的,merge_sort本身就不需要任何操作      

注意:这里的思想最重要的是理解一个元素是有序,即每两个元素都能使用一次归并。

时间复杂度:有减半的过程,且每个元素都便利了,O(nlogn)

空间复杂度:O(n)——存在了新列表里。

总结(快排,堆排,归并)

时间复杂度:O(nlogn)

一般来说:快速排序<归并排序<堆排序

1)在极端条件下,快排时间长,效率低。

2)归并排序开辟了新的储存空间。

3)堆排序在几种效率高的排序中效率低。

这里的空间复杂度是因为递归,递归需要空间。

Python的几个基础算法相关推荐

  1. python中加减乘除_Python基础算法综合:加减乘除四则运算方法

    #!usr/bin/env python # -*- coding:utf-8 -*- #python的算法加减乘除用符号:+,-,*,/来表示 #以下全是python2.x写法,3.x以上请在pyt ...

  2. python 数组赋值_LeetCode基础算法题第182篇:一维数组的运行总和

    技术提高是一个循序渐进的过程,所以我讲的leetcode算法题从最简单的level开始写的,然后到中级难度,最后到hard难度全部完.目前我选择C语言,Python和Java作为实现语言,因为这三种语 ...

  3. python 二分查找_LeetCode基础算法题第120篇:二分查找算法

    技术提高是一个循序渐进的过程,所以我讲的leetcode算法题从最简单的level开始写的,然后> 到中级难度,最后到hard难度全部完.目前我选择C语言,Python和Java作为实现语言,因 ...

  4. Python基础入门知识实例【基础算法】

    基础知识很简单却非常重要,有兴趣的伙伴可以看我以前的两篇基础文章: Python基础知识汇总https://blog.csdn.net/weixin_41896770/article/details/ ...

  5. python实现sklearn的基本操作流程,sklearn预处理方法,sklearn基础算法的使用,以及sklearn模型的选择方法。

    python实现sklearn的基本操作流程,sklearn预处理方法,sklearn基础算法的使用,以及sklearn模型的选择方法. 一.数据的获取与分析 1.读取数据 2.分析数据 二.数据的预 ...

  6. python二分法查找程序_基础算法——查找(二分法)(python)

    基础算法--查找(二分法)(python).二分查找法(BinarySearchST)应用十分广泛,是必须要掌握的查找方法.适用对象是有序数组.具有最优的查找效率和空间需求,能够进行有序相关的操作.但 ...

  7. 两万多字诠释python最经典基础算法之100题【内含思路、程序和答案】【python初学者必备】

    前言: 本文为最最基础的python基础算法题目.思路和答案,适合python初学者使用,可以当作python入门算法工具书,虽然不具有高深的算法,但是都是企业级算法用的频率最多的,这也是学好高级算法 ...

  8. python编程的50种基础算法_Python算法新手入门大全

    干货:GitHub标星2.6万!Python算法新手入门大全 Python已经成为最受欢迎的程序设计语言之一.自从2004年以后,python的使用率呈线性增长.2011年1月,它被TIOBE编程语言 ...

  9. Python --深入浅出Apriori关联分析算法(二) Apriori关联规则实战

    上一篇我们讲了关联分析的几个概念,支持度,置信度,提升度.以及如何利用Apriori算法高效地根据物品的支持度找出所有物品的频繁项集. Python --深入浅出Apriori关联分析算法(一) 这次 ...

最新文章

  1. 我要再接再力 学更多
  2. qt带小数点的数字串显示,Qt-自定义小数点和千位分隔符
  3. GPU Shader 编程基础
  4. 破解栅栏密码python脚本
  5. 反射例子(配置文件)
  6. 【Python基础知识-pycharm版】第十一节-文件操作(IO技术)
  7. [Xpand] Error 1 Invalid option '6' for /langversion; must be ISO-1, ISO-2, 3, 4, 5 or Default
  8. cocos2D中实现滑动菜单CCScrollView+CCMenu效果,(注意不是cocos2D-x)!!
  9. C++调用V8与JS交互
  10. 12.Memcached 与 Redis 区别
  11. html 分享页面到微博qq空间
  12. php eclipse aptana,eclipse 下如何安装 Aptana插件
  13. 电子计算机发展经历几个阶段,计算机的发展经历几个阶段?每个阶段的电子原件及特征主要概述...
  14. python输入生日判断星座_用python条件语句判断星座
  15. js中php遍历数组,vue.js如何遍历数组
  16. 【python数据类型】
  17. 计算机word除法公式,word怎么用函数计算除法
  18. 中科院大牛博士是如何进行文献检索和阅读
  19. Chained Predictions Using Convolutional Neural Networks
  20. Linux常用命令——nice命令

热门文章

  1. go语言 第三方包安装方法_安装第三方软件到电视的方法,看直播应该下载什么软件?...
  2. 家用是买轿车还是suv_SUV的完整形式是什么?
  3. 《LoadRunner 12七天速成宝典》—第2章2.2节解决乱码
  4. Vue国际区号组件开发(目前已经发布到npm)
  5. 台式计算机配置清单8000,8000元能配置怎样的台式机
  6. 【数据结构与算法】BF算法(详解)
  7. 自动控制原理 第二讲 传递函数
  8. linux的多进程等待,等待进程结束wait()和waitpid()函数
  9. 整理下 android 保活 防被杀 守护进程
  10. 使用PTGui软件将全景图变成鱼眼图