用递归法求汉诺塔问题Python,Python递归算法经典实例
每次对越来越少的元素重复上述步骤,直到没有要比较的数字对。
2.动画演示
3.Python代码实现
def bubbleSort(数组):
对于范围内的I(1,len(arr)):
对于范围(0,len(arr)-i)中的j:
if arr[j] arr[j 1]:
数组[j],数组[j 1]=数组[j 1],数组[j]
返回arr
选择排序法
选择是一种简单直观的排序算法。不管什么数据进去,都是O(n2)的时间复杂度。所以在使用的时候,数据量越小越好。唯一的好处可能就是不占用额外的内存空间。
1.算法步骤
首先,在未排序的序列中找到最小(最大)的元素,并将其存储在已排序序列的开头。
然后继续从剩余的未排序元素中寻找最小(最大)的元素,然后放在排序后的序列的末尾。
重复第二步,直到所有元素都排序完毕。
2.动画演示
3.Python代码实现
定义选择排序(arr):
对于范围内的I(len(arr)-1):
#记录最小数量的索引
minIndex=i
对于范围内的j(I ^ 1,len(arr)):
if arr[j] arr[minIndex]:
minIndex=j
当# i不是最小数时,用最小数交换I。
如果我!=minIndex:
arr[i],arr[minIndex]=arr[minIndex],arr[i]
返回arr
插入排序
虽然插入排序的代码实现没有冒泡排序和选择性排序那么简单粗暴,但是它的原理应该是最容易理解的,因为玩过扑克的人应该都能秒懂。插入是最简单、最直观的排序算法。它的工作原理是在排序后的序列中从后向前扫描未排序的数据,找到对应的位置并插入。
和冒泡排序一样,插入排序也有一个优化算法,叫做对半插入。
1.算法步骤
第一个待排序序列的第一个元素被视为有序序列,第二个元素到最后一个元素被视为未排序序列。
从头到尾扫描无序序列,将每个扫描的元素插入有序序列的适当位置。(如果要插入的元素等于有序序列中的一个元素,则将要插入的元素插入到等于的元素之后。)
2.动画演示
3.Python代码实现
定义插入排序(arr):
对于范围内的I(len(arr)):
preIndex=i-1
current=arr[i]
preIndex=0且arr[preIndex] current:
arr[preIndex 1]=arr[preIndex]
preIndex-=1
arr[preIndex 1]=当前
返回arr
谢尔分类
Hill排序,也称为降序增量排序算法,是插入排序的一个更高效的改进版本。然而,希尔排序算法是不稳定的。
希尔排序基于插入排序的以下两个属性:
在对几乎排序的数据进行操作时,插入排序是高效的,即可以达到线性排序的效率;
但是插入排序一般效率不高,因为插入排序一次只能移动一位数据;
Hill排序的基本思路是:首先,将待排序的整个记录序列分成若干子序列进行直接插入排序。当整个序列中的记录都是‘基本有序’时,直接插入所有记录并依次排序。
1.算法步骤
选择增量序列t1,t2,tk,其中ti tj,tk=1;
根据增量序列的个数k,对序列进行k次排序;
每次排序时,根据对应的增量ti,将待排序的列分成若干个长度为m的子序列,每个子表直接插入排序。当增量因子只有1时,整个序列被当作一个表,表的长度就是整个序列的长度。
2.Python代码实现
定义外壳排序(arr):
导入数学
差距=1
while(gap len(arr)/3):
差距=差距*3 1
而间隙0:
对于范围内的I(gap,len(arr)):
临时=数组[i]
j=i-gap
当j=0且arr[j] temp:
arr[j缺口]
间隙
arr[j gap]=温度
gap=math.floor(gap/3)
返回arr
合并分类
归并排序是一种基于归并操作的有效排序算法。这个算法是分而治之的典型应用。
作为分治思想的典型算法应用,归并排序通过两种方法实现:
自顶向下递归(所有递归方法都可以通过迭代重写,所以有第二种方法);
自底向上迭代;
在《数据结构与算法 JavaScript 描述》中,作者给出了一个自底向上的迭代方法。但是对于递归方法,作者认为:
然而,在JavaScript中这是不可能的,因为递归太深,语言无法处理。
但是这种方法在JavaScript中并不可行,因为这种算法的递归深度对它来说太深了。
说实话,这句话我不太懂。是不是说明JavaScript编译器内存太小,太深的递归容易导致内存溢出?希望有大神可以教教我。
与选择性排序一样,合并排序的性能不受输入数据的影响,但它比选择性排序好得多,因为它总是O(nlogn)的时间复杂度。代价是额外的存储空间。
1.算法步骤
申请一个大小为两个排序序列之和的空间,用来存放合并后的序列;
设置两个指针,其初始位置分别为两个排序序列的初始位置;
比较两个指针指向的元素,选择一个相对较小的元素放入归并空间,将指针移动到下一个位置;
重复步骤3,直到指针到达序列的末尾;
将另一个序列的所有剩余元素直接复制到合并序列的末尾。
2.动画演示
3.Python代码实现
定义合并排序(arr):
导入数学
if(len(arr)2):
返回arr
middle=math.floor(len(arr)/2)
left,right=arr[0:middle],arr[middle:]
返回merge(mergeSort(左),mergeSort(右))
定义合并(左、右):
结果=[]
而左和右:
如果left[0]=right[0]:
result . append(left . pop(0));
否则:
result . append(right . pop(0));
离开时:
result . append(left . pop(0));
右侧:
result . append(right . pop(0));
回送结果
快速排序
快速排序是智能豆豆研发的一种排序算法。平均来说,对N个项目进行排序需要 (nlogn)次比较。在最坏的情况下,需要进行 (N2)比较,但这种情况并不常见。事实上,快速排序通常比其他 (NLOGN)算法快得多,因为它的内循环可以在大多数架构中高效实现。
快速排序使用分治策略将一个列表分成两个子列表。
快速排序是分治思想在排序算法中的典型应用。本质上,快速排序应该看作是一种基于冒泡排序的递归分治法。
快速排序这个名字简单粗暴,因为只要一听到这个名字,你就会知道它存在的意义,那就是快速高效!是处理大数据最快的排序算法之一。虽然最坏情况的时间复杂度达到O(n2),但人是优秀的,在大多数情况下,比平均时间复杂度为O(n logn)的排序算法表现更好,但不知道为什么。还好我的强迫症又犯了。查了更多的资料,终于在《算法艺术与信息学竞赛》上找到了满意的答案:
快速排序最差的情况是O(n2),比如顺序数列的快速排序。但其共享的期望时间为O(nlogn),O(nlogn)标记中隐含的常数因子很小,远小于稳定复杂度等于O(nlogn)的归并排序。所以对于大部分弱序列的随机序列,快速排序总是比归并排序好。
1.算法步骤
从序列中挑出一个元素,称之为‘pivot’;
对数列重新排序,所有小于参考值的元素放在参考值的前面,所有大于参考值的元素放在参考值的后面(相同的数字可以在两边)。在这个分区退出后,基准位于系列的中间。这称为分区操作;
递归排序小于参考值的元素子序列和大于参考值的元素子序列;
在递归的最底层,序列的大小是零或一,也就是一直排序下去。虽然它一直在递归,但这种算法总是会退出,因为在每次迭代中,它至少会将一个元素放到最后一个位置。
2.动画演示
3.Python代码实现
def快速排序(arr,left=None,right=None):
如果不是isinstance,left=0(left,(int,float))否则向左
right=len(arr)-1 if not is instance(right,(int,float)) else right
如果向左向右:
partitionIndex=partition(arr,left,right)
快速排序(数组,左,分区索引-1)
快速排序(arr,partitionIndex 1,右)
返回arr
定义分区(左右排列):
枢轴=向左
索引=透视1
i=指数
而我=右:
if arr[i] arr[pivot]:
交换(arr,I,index)
指数=1
i=1
交换(数组,透视,索引-1)
回报指数-1
def swap(arr,I,j):
arr[i],arr[j]=arr[j],arr[i]
堆排序
堆排序是指利用堆的数据结构设计的一种排序算法。Heap是一种类似于完全二叉树的结构,同时满足heap的性质:即子节点的键值或索引总是小于(或大于)其父节点。堆排序可以说是利用堆的概念进行的一种选择性排序。有两种方法:
Top heap:每个节点的值大于等于其子节点的值,用于堆排序算法中的升序;
Top heap:每个节点的值小于等于其子节点的值,用于堆排序算法中的降序;
堆排序的平均时间复杂度为 (nlogn)。
1.算法步骤
创建一个堆h[0…n-1];
交换反应器头部(最大)和反应器尾部;
将堆的大小减少1,调用shift_down(0)以便将新数组顶部的数据调整到相应的位置;
重复步骤2,直到堆栈的大小为1。
2.动画演示
3.Python代码实现
def buildMaxHeap(arr):
导入数学
对于范围内的I(math . floor(len(arr)/2),-1,-1):
heapify(arr,I)
def heapify(arr,I):
左=2*i 1
右=2*i 2
最大=i
if left arrLen和arr[left]arr[large]:
最大=左侧
如果右arrLen和arr[右]arr[最大]:
最大=右侧
如果最大!=我:
交换(arr,I,最大)
heapify(arr,最大)
def swap(arr,I,j):
arr[i],arr[j]=arr[j],arr[i]
定义堆排序(arr):
全球arrLen
arrLen=len(arr)
buildMaxHeap(arr)
对于范围内的I(len(arr)-1,0,-1):
swap(arr,0,I)
arrLen -=1
heapify(arr,0)
返回arr
计数排序
计数排序的核心是将输入的数据值转换成键,存储在额外的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入数据必须是一定范围内的整数。
1.动画演示
2.Python代码实现
def countingSort(arr,maxValue):
bucketLen=maxValue 1
bucket=[0]*bucketLen
sortedIndex=0
arrLen=len(arr)
对于范围内的I(arr len):
如果不是bucket[arr[i]]:
bucket[arr[i]]=0
bucket[arr[i]]=1
对于范围内的j(bucket len):
while桶[j]0:
arr[sortedIndex]=j
sortedIndex=1
桶[j]-=1
返回arr
桶分类
桶排序是计数排序的升级版本。它利用了函数的映射关系,高效的关键在于这个映射函数的确定。为了提高桶排序的效率,我们需要做两件事:
当额外空间足够时,尝试增加桶的数量。
的映射函数可以将输入的N个数据均匀分布到K个桶中。
同时,为了对桶中的元素进行排序,选择一个性能比较排序算法是非常重要的。
1.最快是什么时候?
当输入数据可以均匀分布到每个桶时。
2.最慢的时间是什么时候?
当输入数据被分配到相同的桶时。
基数排序
基数排序是一种非比较整数排序算法。它的原理是把整数按照位数切割成不同的数字,然后按照每个数字进行比较。由于整数也可以用特定格式表示字符串(如姓名或日期)和浮点数,所以基数排序不仅可以用于整数。
1.基数排序vs计数排序vs桶排序
有两种方法对基数进行排序:
所有三种排序算法都利用了桶的概念,但是桶的用法有明显的不同:
基数:根据键值的每一位分配桶;
计数排序:每个桶只存储一个键值;
桶排序:每个桶存储一定范围的值;
2.LSD基数排序动态图的演示
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。