基本排序算法:
1. 选择排序(seletionSort):
搜索整个列表,找到最小项的位置,如果该位置不是列表的第一个位置,算法就交换这两个位置的项。然后,算法回到第二个位置,并重复这个过程。
时间复杂度为 O ( n 2 ) O(n^2) O(n2)
《数据结构:Python语言描述》:
def swap(lyst, i, j):
'''Exchanges the items at positions i and j'''
temp = lyst[i]
lyst[i] = lyst[j]
lyst[j] =temp
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
if minIndex != i:
swap(Lyst, minIndex, i)
i += 1
return Lyst
我自己根据书上改的:
def selectionSort(Lyst):
i = 0
while i < len(Lyst)-1:
j = i + 1
while j < len(Lyst):
if Lyst[j] < Lyst[i]:
Lyst[i],Lyst[j] = Lyst[j],Lyst[i]
j += 1
i += 1
return Lyst
for 循环方法:
def selectionSort(list):
length=len(list)
for i in range(length):
for j in range(i+1,length):
if list[j] < list[i]:
list[j],list[i]=list[i],list[j]
return list
Lyst = [2,1,4,7,3,8,4,9,1,3]
print(selectionSort(Lyst))
[1, 1, 2, 3, 3, 4, 4, 7, 8, 9]
2. 冒泡排序(bubbleSort):
从列表的开头处开始,比较一对数据项,知道移动到列表的末尾,这样每趟排序会把最大的数字扔到最后面。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名。
时间复杂度为 O ( n 2 ) O(n^2) O(n2);
《数据结构:Python语言描述》:
def bubbleSort(lyst):
n = len(lyst)
while n > 1:
i = 1
while i < n:
if lyst[i] < lyst[i - 1]:
swap(lyst, i , i-1)
i += 1
n -= 1
return lyst
for 循环方法:
def bubbleSort(lyst):
# 外层循环控制从头走到尾的次数
for j in range(len(lyst) - 1):
# 内层循环控制走一次的过程
for i in range(0, len(lyst) - j - 1):
# 如果前一个元素大于后一个元素,则交换两个元素(升序)
if lyst[i] > lyst[i + 1]:
lyst[i], lyst[i + 1] = lyst[i + 1], lyst[i]
return lyst
针对冒泡排序进行一个小的调整,将其最好情况下的性能提高到线性阶,但平均复杂的仍是 O ( n 2 ) O(n^2) O(n2):
def bubbleSortWithTweak(lyst):
n = len(lyst)
while n > 1:
i = 1
while i < n:
if lyst[i] < lyst[i - 1]:
swap(lyst, i , i-1)
swapped = True
i += 1
if not swapped: return
n -= 1
return lyst
用递归实现冒泡?
3. 插入排序(insertionSort):
“一趟一个“地将待排序记录插入到已经排好序的部分记录的适当位置中,使其成为一个新的有序序列,直到所有待排序记录全部插入完毕。在第i轮通过列表的时候(其中i的范围从1到n-1),第i个项应该插入到列表的前i个项之中的正确位置。在第i轮之后,前i个项应该是排序好的。
列表中排好序的项越多,插入排序的效果越好。
时间复杂度为 O ( n 2 ) O(n^2) O(n2);
《数据结构:Python语言描述》:
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]
j -= 1
else:
break
lyst[j + 1] = itemToInsert
i += 1
return lyst
def insertionSort(lyst):
n = len(lyst)
for i in range(1,n):
for j in range(i,0,-1):
if lyst[j] < lyst[j-1]:
lyst[j],lyst[j-1] = lyst[j-1],lyst[j]
else:
break
return lyst
更快的排序算法
采用分而治之(divide-and-conquer)的策略。将列表分解为更小的子列表,随后,这些子列表递归的排序。算法复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
1.1 快速排序(quickSort)
随意选择一个数字(可选中点)作为基准(pivot)分割列表,比基准数字大的放在右,比基准数字小的放在左。对于子列表,递归地重复应用该过程。直到子列表的长度最大为1。
《数据结构:Python语言描述》:
def swap(lyst, i, j):
'''Exchanges the items at positions i and j'''
temp = lyst[i]
lyst[i] = lyst[j]
lyst[j] =temp
def quickSort(lyst):
quickSortHelper(lyst, 0, len(lyst)-1)
def quickSortHelper(lyst, left, right):
if left < right:
print(lyst)
pivotLocation = partition(lyst, left, right)
print(lyst[pivotLocation])
quickSortHelper(lyst, left, pivotLocation - 1)
quickSortHelper(lyst, pivotLocation + 1, right)
def partition(lyst, left, right):
middle = (left + right) // 2
pivot = lyst[middle]
lyst[middle] = lyst[right]
lyst[right] = pivot
boundary = left
for index in range(left, right):
if lyst[index] < pivot:
swap(lyst, index, boundary)
boundary += 1
print(lyst)
swap(lyst, right, boundary)
return boundary
Lyst = [12,19,17,18,14,11,15,13,16]
quickSort(Lyst)
print(Lyst)
快速排序递归分析:
1.遍历所有元素,使比基准小的在基准左,比基准大的在基准右,故先将基准换到最右侧。
2.然后从左到右遍历,找到比基准小的元素,从第一个位置开始依次互换。
3.如12先跟自己互换,然后11和19互换,然后13和17互换,最后基准14和18互换。
4.递归对左边子列表重复操作:基准11换到末端即11和13互换,然后11和12互换。
5.左边已不可再分,开始分右边子列表。首先基准15换到末端即15和18互换,然后15
[12, 19, 17, 18, 14, 11, 15, 13, 16]
[12, 19, 17, 18, 16, 11, 15, 13, 14]
[12, 11, 17, 18, 16, 19, 15, 13, 14]
[12, 11, 13, 18, 16, 19, 15, 17, 14]
14
[12, 11, 13, 14, 16, 19, 15, 17, 18]
11
[11, 13, 12, 14, 16, 19, 15, 17, 18]
[11, 12, 13, 14, 16, 19, 15, 17, 18]
13
[11, 12, 13, 14, 16, 19, 15, 17, 18]
15
[11, 12, 13, 14, 15, 19, 18, 17, 16]
[11, 12, 13, 14, 15, 16, 19, 17, 18]
[11, 12, 13, 14, 15, 16, 17, 19, 18]
18
[11, 12, 13, 14, 15, 16, 17, 18, 19]
16
[11, 12, 13, 14, 15, 16, 17, 18, 19]
1.2 算法导论 快速排序:
# quickSort, quickSortHelper 同上
def partition(lyst, left, right):
x = lyst[right]
i = left- 1
for j in range(left, right):
if lyst[j] <= x:
i += 1
lyst[i], lyst[j] = lyst[j], lyst[i]
print(lyst)
lyst[i + 1], lyst[right] = lyst[right], lyst[i+1]
return i + 1
Lyst = [12,19,17,18,14,11,15,13,16]
quickSort(Lyst)
print(Lyst)
[12, 19, 17, 18, 14, 11, 15, 13, 16]
[12, 19, 17, 18, 14, 11, 15, 13, 16]
[12, 14, 17, 18, 19, 11, 15, 13, 16]
[12, 14, 11, 18, 19, 17, 15, 13, 16]
[12, 14, 11, 15, 19, 17, 18, 13, 16]
[12, 14, 11, 15, 13, 17, 18, 19, 16]
16
[12, 14, 11, 15, 13, 16, 18, 19, 17]
[12, 14, 11, 15, 13, 16, 18, 19, 17]
[12, 11, 14, 15, 13, 16, 18, 19, 17]
13
[12, 11, 13, 15, 14, 16, 18, 19, 17]
11
[11, 12, 13, 15, 14, 16, 18, 19, 17]
14
[11, 12, 13, 14, 15, 16, 18, 19, 17]
17
[11, 12, 13, 14, 15, 16, 17, 19, 18]
18
[11, 12, 13, 14, 15, 16, 17, 18, 19]
2.1 归并排序(mergeSort)
创建在归并操作上的一种有效的排序算法,效率为 O ( n l o g n ) O(n log n) O(nlogn)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。
merge 函数将两个排好序的子列表合并到一个大的排好序的子列表中,第1个子列表在low和middle之间,第2个子列表在middle+1到high之间。这个过程包含3个步骤:
1.将索引指针设置为每个子列表的第一项,分别是low和middle+1
2.从每个子列表的第一项开始,重复地比较各项。将较小的项从其子列表中复制到复制缓存中,并且继续处理子列表中的下一项。重复这个过程,直到两个子列表中的所有的项都已经复制过了。如果先到达了其中的一个子列表的末尾,通过从另一个子列表复制剩余的项,从而结束这个步骤。
3.将copyBuffer中的low和high之间的部分,复制回lyst中对应的位置。
《数据结构:Python语言描述》:
import sys
sys.path.append(r'C:\Users\Qiuyi\eclipse-workspace\DataStructure3.0\programs\Ch_4_Student_Files')
from arrays import Array
def mergeSort(lyst):
copyBuffer = Array(len(lyst))
mergeSortHelper(lyst, copyBuffer, 0, len(lyst)-1)
def mergeSortHelper(lyst, copyBuffer, low, high):
if low < high:
middle = (low + high) // 2
mergeSortHelper(lyst, copyBuffer, low, middle)
mergeSortHelper(lyst, copyBuffer, middle + 1, high)
merge(lyst, copyBuffer, low, middle, high)
def merge(lyst, copyBuffer, low, middle, high):
i1 = low
i2 = middle + 1
for i in range(low, high + 1):
# stop conditions
if i1 > middle:
copyBuffer[i] = lyst[i2]
i2 += 1
elif i2 > high:
copyBuffer[i] = lyst[i1]
i1 += 1
# sort conditions
elif lyst[i1] < lyst[i2]:
copyBuffer[i] = lyst[i1]
i1 += 1
else:
copyBuffer[i] = lyst[i2]
i2 += 1
for i in range(low, high + 1):
lyst[i] = copyBuffer[i]
Lyst = [12,19,17,18,14,11,15,13,16]
mergeSort(Lyst)
print(Lyst)
"""
File: arrays.py
An Array is a restricted list whose clients can use
only [], len, iter, and str.
To instantiate, use
<variable> = array(<capacity>, <optional fill value>)
The fill value is None by default.
"""
class Array(object):
"""Represents an array."""
def __init__(self, capacity, fillValue = None):
"""Capacity is the static size of the array.
fillValue is placed at each position."""
self._items = list()
for count in range(capacity):
self._items.append(fillValue)
def __len__(self):
"""-> The capacity of the array."""
return len(self._items)
def __str__(self):
"""-> The string representation of the array."""
return str(self._items)
def __iter__(self):
"""Supports iteration over a view of an array."""
return iter(self._items)
def __getitem__(self, index):
"""Subscript operator for access at index."""
return self._items[index]
def __setitem__(self, index, newItem):
"""Subscript operator for replacement at index."""
self._items[index] = newItem
2.2 简书归并排序算法:
def mergesort(seq):
"""归并排序"""
if len(seq) <= 1:
return seq
mid = len(seq) // 2 # 将列表分成更小的两个列表
# 分别对左右两个列表进行处理,分别返回两个排序好的列表
left = mergesort(seq[:mid])
right = mergesort(seq[mid:])
# 对排序好的两个列表合并,产生一个新的排序好的列表
return merge(left, right)
def merge(left, right):
"""合并两个已排序好的列表,产生一个新的已排序好的列表"""
result = [] # 新的已排序好的列表
i = 0 # 下标
j = 0
# 对两个列表中的元素 两两对比。
# 将最小的元素,放到result中,并对当前列表下标加1
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
seq = [12,19,17,18,14,11,15,13,16]
print('排序前:',seq)
result = mergesort(seq)
print('排序后:',result)
排序前: [12, 19, 17, 18, 14, 11, 15, 13, 16]
排序后: [11, 12, 13, 14, 15, 16, 17, 18, 19]
TypeError: slice indices must be integers or None or have an index method
将 mid = len(seq) / 2 改成 mid = len(seq) // 2
其他排序:
1. 希尔排序(shellSort):
“基本有序化”可以提升插入排序的效率,将记录序列分成若干子序列,每个子序列分别进行插入排序。需要注意的是,这种子序列是由间隔为某个增量的一组数据组成,即跳跃式选择数据组。
时间复杂度:约在 O ( n 1.25 ) 和 O ( n 1.6 ) O(n^{1.25})和O(n^{1.6}) O(n1.25)和O(n1.6)之间
def shellSort(list):
length=len(list)
dist=length/2
while dist>0:
for i in range(dist,length):
temp=list[i]
j=i
while j>=dist and temp<list[j-dist]:
list[j]=list[j-dist]
j-=dist
list[j]=temp
dist/=2
return list
2. 堆排序(headSort):
把待排序的数据元素构造成一个完全二叉树结构,则每次选择出一个最大的数据元素只需比较完全二叉树的高度次,即 l o g n logn logn次,则排序算法的最好最坏时间复杂度均为 O ( n l o g n ) O(n log n) O(nlogn)
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
1.创建最大堆:将堆所有数据重新排序,使其成为最大堆
2.最大堆调整:作用是保持最大堆的性质,是创建最大堆的核心子程序
3.堆排序:移除位在第一个数据的根节点,并做最大堆调整的递归运算
def headSort(list):
length_list = len(list)
first=int(length_list/2-1)
for start in range(first,-1,-1):
max_heapify(list,start,length_list-1)
for end in range(length_list-1,0,-1):
list[end],list[0]=list[0],list[end]
max_heapify(list,0,end-1)
return list
def max_heapify(ary,start,end):
root = start
while True:
child = root*2 + 1
if child > end:
break
if child + 1 <= end and ary[child]<ary[child+1]:
child = child + 1
if ary[root]<ary[child]:
ary[root],ary[child]=ary[child],ary[root]
root=child
else:
break
3. 计数排序
计数排序的基本思想是:对每一个输入的元素a[i],确定小于 a[i] 的元素个数。所以可以直接把 a[i] 放到它输出数组中的位置上。假设有5个数小于 a[i],所以 a[i] 应该放在数组的第6个位置上。
def count_sort(list):
max=min=0
for i in list:
if i < min:
min = i
if i > max:
max = i
count = [0] * (max - min +1)
for j in range(max-min+1):
count[j]=0
for index in list:
count[index-min]+=1
index=0
for a in range(max-min+1):
for c in range(count[a]):
list[index]=a+min
index+=1
return list
…