冒泡排序(Bubble Sort)
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
算法描述
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
重复步骤1~3,,直到没有任何一对数字需要比较
#coding:utf-8
def bubble_sort(alist):
# 获取列表的长度
n = len(alist)
for i in range(n-1):
# 开启大循环,每一次循环将会从无序序列中获取最大值
# 统计发生交换行为的次数,小循环结束如果counter为0则表明列表中的数据是有序的,直接退出大循环
counter = 0
print("$$$")
for j in range(n-1-i):
if alist[j] > alist[j+1]:
alist[j],alist[j+1] = alist[j+1],alist[j]
counter += 1
if counter == 0:
break
if __name__ == '__main__':
# alist = [12,34,56,78,90,9,87,65,43,21]
alist = [1,2,3,4,5,6,7,8]
bubble_sort(alist)
print(alist)
# O(n^2)
# O(n)
# 稳定的
简单选择排序(Selection Sort)
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
算法描述
n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:
初始状态:无序区为R[1…n],有序区为空;
第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1…i-1]和R(i…n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],
将它与无序区的第1个记录R交换,使R[1…i]和R[i+1…n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
n-1趟结束,数组有序化了。
#coding:utf-8
def select_sort(alist):
n = len(alist)
for i in range(n-1):
min_index = i
print("*")
for j in range(i+1,n):
print("$$$")
if alist[j] < alist[min_index]:
min_index = j
if min_index != i:
alist[i],alist[min_index] = alist[min_index],alist[i]
if __name__ == '__main__':
# alist = [12,34,56,78,90,9,87,65,43,21]
alist = [1,2,3,4,5,6,7,8]
select_sort(alist)
print(alist)
# O(n^2)
# O(n^2)
# 稳定
插入排序
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
算法描述
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
从第一个元素开始,该元素可以认为已经被排序;
取出下一个元素,在已经排序的元素序列中从后向前扫描;
如果该元素(已排序)大于新元素,将该元素移到下一位置;
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
将新元素插入到该位置后;
重复步骤2~5。
#coding:utf-8
def insert_sort(alist):
n = len(alist)
# 将无序列表在逻辑上进行分组,从索引为1的位置开始认为是无序的,索引为0认为是有序列表
for i in range(1,n):
print("$")
# 从无序列表中获取一个数据,不断地将其与左侧有序列表中的数据做对比交换
for j in range(i, 0, -1):
print("#")
if alist[j] < alist[j-1]:
alist[j],alist[j-1] = alist[j-1],alist[j]
else:
break
if __name__ == '__main__':
# alist = [12,34,56,78,90,9,87,65,43,21]
alist = [8,7,6,5,4,3,2,1]
# alist = [1,2,3,4,5,6,7,8]
insert_sort(alist)
print(alist)
# O(n^2)
# O(n)
# 稳定
希尔排序
1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
算法描述
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列个数k,对序列进行k 趟排序;
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
#coding:utf-8
def shell_sort(alist):
n = len(alist)
gap = n // 2
while gap > 0:
for i in range(gap,n):
while i - gap >= 0:
if alist[i] < alist[i-gap]:
alist[i],alist[i-gap] = alist[i-gap],alist[i]
i -= gap
else:
break
gap //= 2
if __name__ == '__main__':
alist = [12,34,56,78,90,9,87,65,43,21]
# alist = [8,7,6,5,4,3,2,1]
# alist = [1,2,3,4,5,6,7,8]
shell_sort(alist)
print(alist)
# O(n^2)
# 不稳定
快速排序
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
算法描述
首先设定一个分界值,通过该分界值将数组分成左右两部分。
将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了
#coding:utf-8
def quick_sort(alist,start,end):
left = start
right = end
if left >= right:
return
mid = alist[left]
while left < right:
while alist[right] > mid and left < right:
right -= 1
alist[left] = alist[right]
while alist[left] < mid and left < right:
left += 1
alist[right] = alist[left]
alist[left] = mid
quick_sort(alist, start, left-1)
quick_sort(alist, left+1, end)
if __name__ == '__main__':
alist = [12,34,56,78,90,9,87,65,43,21]
# alist = [8,7,6,5,4,3,2,1]
# alist = [1,2,3,4,5,6,7,8]
quick_sort(alist, 0, len(alist) - 1)
print(alist)
# O(n^2)
# O(nlogn)
# 不稳定