大话数据结构这本书写的非常好的一个地方就是,会将这个算法的全部原由通俗易懂的向你介绍,不会仅仅将注意力放在算法上傻傻的分析,而是通过有趣的背景,阐述算法的来源和意义,以此让读者达到深刻理解的目的,而不是仅仅“背”住了算法。觉得不能理解可以去多看看图形和里面的代码实例。
插入类排序:简单插入排序,升级为-希尔排序
选择类排序:简单选择排序,升级为-堆排序
交换类排序:冒泡排序,升级为-快速排序
归并排序:很多复杂的排序可以进行分块解决。
桶排序:只有特定数据类型可以,可以在O(n)时间完成排序,需要消耗部分桶空间。
代码参考:https://blog.csdn.net/aiya_aiya_/article/details/79846380
'''冒泡排序
选择理由:稳定,与原位置偏离不远。
基本思想:正宗的冒泡排序,j其实从后往前走的,不过我们比较喜欢,
从下标0开始嘛,效果一样,但是要知道。默认有增加一个状态判断。
时间复杂度:最差:O(n2),最好:O(n)
空间复杂度:O(1)
'''
def BublleSort(li):
for i in range(len(li)):#定义几趟排序n-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]
'''简单选择排序
选择理由:稳定,很无序,与原位置偏离较远。
基本思想:后面找到最小的值后再来交换,比冒泡排序的优点是
不用交换那么多次。
时间复杂度:无论好差都是O(n2)
空间复杂度:O(1)
'''
def SelectSort(li):
for i in range(len(li)-1):#定义趟数n-1
minIndex = i
for j in range(i+1,len(li)):#定义每趟排序的比较次数
if li[minindex] > li[j]:
minindex = j
if minindex != i:
li[i],li[minindex] = li[minindex],li[i]
'''简单插入排序
选择理由:稳定,基本有序。
基本思想:从第一个元素开始,不断整理顺序。
时间复杂度:最差:O(n2),最好:O(n)
空间复杂度:O(1)
'''
def InsertSort(li):
for i in range(1, len(li)):#定义趟数n-1
tempi = li[i]; j = i
while j > 0 and tempi < li[j-1]:#for就显示不出来优势了
li[j] = li[j-1]#后面的值上移
j -= 1
ls[j] = tempi
#前面三种都是O(n2),经过后人的不断努力,研究,速度才得以提升。排序要加快的基本原则之一,是让后一次的排序进行时,尽量利用前一次排序后的结果,以加快排序的速度。
'''希尔排序-缩小增量排序
选择理由:不稳定,适合基本无序的序列。简单插入排序的升级!
基本思想:我们比较的元素可以再远一点,即所谓的增量,
等距的一些元素先排序,再逐渐过渡到整个数组。
(增量的选择很关键,有很多研究)
时间复杂度:最差最好:O(nlogn)
空间复杂度:O(1)
'''
def ShellSort(li):
def shellinsert(li, d):
n = len(li)
for i in range(d, n):
j = i - d
temp = li[i]
while (j >= 0 and li[j] > temp):
li[j+d] = li[j]
j -= d
if j != i-d:
li[j+d] = temp
n = len(li)
if n <= 1:
return li
d = n // 2
while d >= 1:
shellinsert(li, d)
d //= 2
return li
'''堆排序
选择理由:简单选择排序没有很好利用第一次比较的结果,因此改进为堆排序。不稳定。
基本思想:建堆:从最后一个非叶子节点开始调整到根节点;
排序:从根节点取出数放在最后面n-1次。
时间复杂度:最差最好都是:O(nlogn)这就很厉害了!
空间复杂度:O(1)
'''
def HeapSort(li):
def heapadjust(li, root, end):
temp = li[root]
son = 2*root+1
while son <= end:
if son < end and li[son] < li[son+1]:
son += 1
if temp > li[son]:
break
li[root] = li[son]
root = son
son = root*2+1
n = len(li)
if n <= 1:
return
root = n//2-1
while root >= 0:#建立堆
heapadjust(li, root, n-1)
root -= 1
i = n-1
while i > 0:#排序
li[i],li[0] = li[0],li[i]
heapadjust(li, 0, i-1)
i -= 1
return li
'''归并排序-分治递归的思想,代码为二路归并
选择理由:稳定,一般用于总体无序,但各子项相对有序。
基本思想:将列表分成几部分,两两合并。
时间复杂度:平均最差最好都是:O(nlogn)这就很厉害了!
空间复杂度:O(n)
'''
def MergeSort(li):
#合并左右子序列函数
def merge(li, left, mid, right):
temp = [] #中间数组
i = left#左段子序列起始
j = mid + 1#右段子序列起始
while i<= mid and j <= right:
if li[i] < li[j]:
temp.append(li[i])
i += 1
else:
temp.append(li[j])
j += 1
while i <= mid:
temp.append(li[i])
i += 1
while j <= right:
temp.append(li[j])
j += 1
# !注意这里,不能直接li=temp,他俩大小都不一定一样
for i in range(left, right+1):
li[i] = temp[i-left]
#递归调用归并排序
def msort(li, left, right):
if left >= right:
return
mid = (left+right)//2
mSort(li, left, mid)
mSort(li, mid+1, right)
merge(li, left, mid, right)
n = len(li)
if n <= 1:
return li
mSort(li, 0, n-1)
return li
'''桶排序:工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是比较排序,他不受到 O(n log n)下限的影响。
经典应用:
应用:给500万考生成绩排序,超级快。适用于元素集合不大的情况,分数集合最多是0-1000。
应用:在一个文件中有10G个整数,乱序排列,要求找出中位数。内存限制为2G。只写出思路即可
'''
def bucketSort(nums):
# 选择一个最大的数
max_num = max(nums)
# 创建一个元素全是0的列表, 当做桶
bucket = [0]*(max_num+1)
# 把所有元素放入桶中, 即把对应元素个数加一
for i in nums:
bucket[i] += 1
# 存储排序好的元素
sort_nums = []
# 取出桶中的元素
for j in range(len(bucket)):
if bucket[j] != 0:
for y in range(bucket[j]):
sort_nums.append(j)
return sort_nums
nums = [5,6,3,2,1,65,2,0,8,0]
print "脚本之家测试结果:"
print bucketSort(nums)
'''快速排序-20世纪十大算法之一
选择理由:不稳定,但是后序研究丰富,很多优化方案。进行优化后,该排序算法依旧很强!冒泡排序的改进!
改进虽然好,但是对于大数据是好事,但是如果数据本身就很小,就有点大炮打蚊子,
反而更费事了。
优化4:数据较小更换排序算法
基本思想:选一个数作为中间枢纽,进行列表的划分,递归。
时间复杂度:最差:O(n2)最好:O(nlogn)
空间复杂度:主要为递归造成的空间栈的使用,O(n)
'''
def QuickSort(li):
def partition(li, left, right):
key = left#优化1:三数取中或者九数,而不随便取一个
while left < right:
while left < right and li[right] > li[key]:
right -= 1
while left < right and li[left] < li[key]:
left += 1
li[left],li[right] = li[right],li[left]
#优化2:直接进行交换,最后再插入中间枢纽:。
li[key],li[left] = li[left],li[key]
return left
def quicksort(li, left, right):#递归调用
if left >= right:
return
mid = partition(li, left, right)
quicksort(li, left, mid-1)
#优化3:减少递归栈空间的使用,使用迭代
#while循环加上left = mid + 1
quicksort(li, mid+1, right)
#主函数
n = len(li)
if n <= 1:
return li
quicksort(li, 0, n-1)
return li