基础的排序算法
容易的算法效率比较低,但是容易理解。每一个python的排序函数都会使用一个swap的函数来交换列表中的两项的位置,函数的代码如下
def swap(lyst,i,j):
"""交换lyst中的i和j位置的item"""
temp=lyst[i]
lyst[i]=lyst[j]
lyst[j]=temp
pass
或者python中极具特色的:
def swapPython(lyst,i,j):
"""使用python的特色方法交换list中的i和j的item"""
lyst[i],lyst[j]=lyst[j],lyst[i]
选择排序
最简单的策略就是每一次找到最小的和它本应该的位置进行交换,在每一轮的时候只是交换两个位置;
流程应该是用一个循环来控制需要排序的位置的确定,然后用内嵌的循环是来找到后续的最小的数来,最后跳出来循环,进行交换
def selectionSort(lyst):
"""选择排序"""
i=0
while i<len(lyst)-1:#需要控制排序的位置
minIndex=i
j=i+1
while j<len(lyst):#内部循环的最小值
if lyst[j]<lyst[minIndex]:
minIndex=j
j+=1
pass
if minIndex!=i:
swap(lyst,i,minIndex)
i+=1
return lyst
该函数包含了一个嵌套的循环,对于大小为n的列表,外围的循环执行n-1次,在外部的第一次循环时,内部的循环的次数为n-1次,当外部的循环是第二次的时候,内部的循环的次数是n-2次,最后的一次外部的循环时,内部的循环的次数为1 次。因此该算法的复杂度是(n-1)+(n-2)……+1+0+n=1/2n^2+1/2n、
对于较大的n,可以忽略常数的系数,因此复杂度为O(n^2)。对于较大的数据集合,交换数据的开销可能会很大,因为交换两个数据的操作是在外围的循环里面的,所以在最坏的情况下和平均的情况下,选择排序的额外的开销是线性的。
冒泡算法
冒泡排序比较容易理解和编码。策略是从列表的开头处开始,并且比较一对的数据项,直到移动到数据列表的末尾。每当算法的位置不对时,算法就开始交换其位置。整个过程就是以冒泡的方式将最大的项拍到列表的末尾,然后算法从列表的开头到倒数的第二项重复这一过程。
冒牌排序的主算法主要是通过两个循环来进行的。第一个循环来确定的需要进行冒泡的项。第二个循环来进行冒泡的操作。代码如下:
def bubleSort(lyst):
"""冒泡排序法"""
i=0
while i<len(lyst):
j=0
while lyst[j]>lyst[j+1]:
swap(lyst,j,j+1)
j+=1
if (j==len(lyst)-1):
print(j)
break
i+=1
print(i,lyst)#输出循环的次数和每一次循环的结果
pass
return lyst
算法的复杂度分析,对于冒泡算法其复杂度也是O(n^2)。和选择排序一样。
可以对冒泡算法的程序做以下的修正,以使得算法的复杂度(最好的情况下)的性能提升到线性阶。如果在通过主循环的时候,list就是排序好的。这种情况可能发生在任何一个循环的轮次,但是在最好的情况下,第一轮就会发生,可以使用一个boolean的标志来标记交换动作的出现。并且当内部的循环没有这个标志的时候,就从函数返回。
代码如下
def bublesortTweak(lyst):
"""冒泡排序法的改进版"""
i=0
while i<len(lyst):
j=0
while lyst[j]>lyst[j+1]:
swap(lyst,j,j+1)
j+=1
flag=True
if (j==len(lyst)-1):
break
pass
if not flag:
return lyst
pass
i+=1
return lyst
这样的改进只是为了最好的情况,但是在平均的情况下,其复杂度仍然为O(n^2)
插入排序法
插入排序是试图以一种不同的方式来对列表进行修改
方法如下:
在第i轮的时候,第i个项应该插入到list的前i个项的正确的位置
在第i轮之后,第i个项应该是排好序的
这个过程类似手中的扑克牌的排列过程,也就是按照顺序放好了前面的i-1张牌,抓取了第i张,并且将其与手中的这些牌进行比较,直到将其放到合适的位置。
和其他的算法一样,插入排序同样具有两个循环,外围的循环是遍历从1到n-1的位置,对于这个循环中的每一个位置i都保存该项并且从位置n-1开始内部的循环,对于这个循环中的每一个位置j,都将移动到位置j+1,直到找到给保存的项(第i项)的插入位置
对于插入排序的理解就是用一个循环来控制项的选取,用内循环来控制所有满足条件的项的后移,然后给他后移空下来的位置上进行添加项
代码如下:
def insertSort(lyst):
"""这是插入排序的函数"""
i=1
while i<len(lyst):
itemToInsert=lyst[i]
j=i-1
while j>=0:
if itemToInsert<lyst[j]:
lyst[j+1]=lyst[j]#不必担心数据丢失的问题,每一次的插入就是将目前的i位置的项进行后移,而i项的数据已经在itemToInsert中保存了
j-=1
else:
break
lyst[j+1]=itemToInsert
i+=1
return lyst
分析嵌套的循环,外围的循环执行了n-1次,在最坏的时候,当所有的数据都是未排序的时候,插入排序的最坏的情况的复杂度是O(n^2)
列表中排好序的项越多,插入排序的效果越好。在最好的情况下,插入排序的复杂度就是线性阶的