从头复习一遍算法,顺便整理一下笔记。
# 选择排序
# 时间复杂度 O(n^2)
# 每一趟在n-i+1个记录中选择关键字最小的记录作为序列中的第i个记录。
import random
def select_sort(arr):
if arr == [] or len(arr) < 2:
return arr
for i in range(len(arr)):
minimumindex = i
for j in range(i + 1, len(arr)):
if arr[minimumindex] > arr[j]:
minimumindex = j
arr[minimumindex], arr[i] = arr[i], arr[minimumindex]
return arr
# 冒泡排序
# 时间复杂度 O(n^2)
# 大的东西沉底,汽泡上升。
def bubble_sort(arr):
if arr == [] or len(arr) < 2:
return arr
for i in range(len(arr)):
for j in range(i + 1, len(arr)):
if arr[i] > arr[j]:
arr[i], arr[j] = arr[j], arr[i]
return arr
# 插入排序
# 时间复杂度 O(n^2)
# 从0位置开始依次保证0~0\0~1\0~2上面有序.在i位置往前看,保证有序就停下来
# 因为思想是前面的数已经有序了,所以只要保证当前位置和前一位有序,就代表前面所有的数都有序了,就可以停下来
def insert_sort(arr):
if arr == [] or len(arr) < 2:
return arr
for i in range(len(arr)):
j = i - 0
while True:
if j < 0 or arr[j] < arr[i]:
break
else:
arr[i], arr[j] = arr[j], arr[i]
i = j
j = j - 1
return arr
# 归并排序
# 时间复杂度O(n*log(n))
# 用二分法往下递归,从最底层向上依次保持每一层的有序性
def merge(larr, rarr):
p1 = 0
p2 = 0
helplist = []
while p1 < len(larr) and p2 < len(rarr):
if larr[p1] < rarr[p2]:
helplist.append(larr[p1])
p1 += 1
else:
helplist.append(rarr[p2])
p2 += 1
if p1 != len(larr):
for i in range(p1, len(larr)):
helplist.append(larr[i])
else:
for i in range(p2, len(rarr)):
helplist.append(rarr[i])
return helplist
def merge_sort(arr, l, r):
if arr == [] or len(arr) < 2:
return arr
if l >= r:
helplist = []
helplist.append(arr[l])
return helplist
m = int((l + r) / 2)
left = merge_sort(arr, l, m)
right = merge_sort(arr, m + 1, r)
helplist = merge(left, right)
return helplist
# 归并排序引生(非常重要,所以放到了这里)
# 求小和问题(求一组数据中每个数左边有多少个数比当前数小,求出比当前数小的总和)
# 因为是从底层回溯的,所以不需要看已经merge过的数,只需要看右边有多少个比当前的大
def small_sum_merge(larr, rarr):
p1 = 0
p2 = 0
helplist = []
minsum = 0
while p1 < len(larr) and p2 < len(rarr):
if larr[p1] < rarr[p2]:
helplist.append(larr[p1])
minsum += larr[p1] * (len(rarr) - p2)
p1 += 1
else:
helplist.append(rarr[p2])
p2 += 1
if p1 != len(larr):
for i in range(p1, len(larr)):
helplist.append(larr[i])
else:
for i in range(p2, len(rarr)):
helplist.append(rarr[i])
return helplist, minsum
def small_sum(arr, l, r):
if arr == [] or len(arr) < 2:
return arr
if l >= r:
helplist = []
helplist.append(arr[l])
return helplist, 0
m = int((l + r) / 2)
left, lsum = small_sum(arr, l, m)
right, rsum = small_sum(arr, m + 1, r)
helplist, minsum = small_sum_merge(left, right)
print(minsum)
minsum = minsum + lsum + rsum
return helplist, minsum
# 快速排序
# 快排1:用数组的最后一位数作荷兰国旗问题,然后再把这个数和大于区域内的第一位作交换;然后在大于和小于区域重复这个过程
# 快排2:随机从数组中取一个数作为划分标准num
def partition(arr, l, r):
num = arr[random.randint(l, r)]
i = l
p1 = l - 1
p2 = r + 1
while i <= r and i < p2:
if arr[i] < num:
arr[i], arr[p1 + 1] = arr[p1 + 1], arr[i]
p1 += 1
i += 1
elif arr[i] == num:
i += 1
else:
arr[i], arr[p2 - 1] = arr[p2 - 1], arr[i]
p2 -= 1
return arr, p1, p2
def quick_sort(arr, l, r):
if arr == [] or len(arr) < 2:
return arr
if l >= r:
return
arr, less, more = partition(arr, l, r)
quick_sort(arr, l, less)
quick_sort(arr, more, r)
return arr
# 堆排序
# 说到了堆,不如直接手写一个简单的小根堆吧
# 堆结构
# 完全二叉树,从左往右依次变满的就是完全二叉树
# 手写一个小根堆
class HeapNode(object):
# 定义堆的节点结构,就是在二叉树节点的基础上加上一个父节点的信息
def __init__(self, value):
self.value = value
self.left = None
self.right = None
self.father = None
def __repr__(self):
return str(self.value)
class Small_root_pile(object):
def __init__(self):
self.root = None
def insert(self, node):
# inset的思想很简单,就是在保证是完全二叉树的基础上保证父节点用于比自己小
# 所以就是在基本的完全二叉树的基础上在添加节点的地方加上一个heapinsert的过程
node = HeapNode(node)
queue = [self.root]
if self.root == None:
self.root = node
self.root.father = self.root
return
else:
while True:
if queue == []:
break
else:
cur = queue.pop(0)
# 先进先出,如果先进去的也就是上层的节点有空的子节点就优先补上;如果不为空,就把自己的子节点加进去
if cur.left == None:
# 如果左边为空就加到左边
cur.left = node
cur.left.father = cur
self.heapinsert(cur.left)
return
else:
queue.append(cur.left)
if cur.right == None:
cur.right = node
cur.right.father = cur
self.heapinsert(cur.right)
return
else:
queue.append(cur.right)
def heapinsert(self, node):
# 不断的看父节点是不是比自己小
while True:
cur = node.father
if node.value < cur.value:
cur.value, node.value = node.value, cur.value
node = cur
else:
break
def pop(self):
# 弹出就是把头节点和最后一个节点交换然后再heapify
if self.root == None:
return
queue = [self.root]
while True:
cur = queue.pop(0)
if cur.left != None:
queue.append(cur.left)
if cur.right != None:
queue.append(cur.right)
if queue == []:
popvalue = self.root.value
self.root.value = cur.value
if cur.father.right != None:
cur.father.right = None
elif cur.father.left != None:
cur.father.left = None
else:
self.root = None
return popvalue
self.heapify(self.root)
return popvalue
def heapify(self, head):
# 不断的看子节点有没有比自己小的
while True:
if head.left != None and head.right == None:
if head.left.value < head.value:
head.value, head.left.value = head.left.value, head.value
head = head.left
else:
return
elif head.left != None and head.right != None:
if head.left.value < head.right.value:
if head.left.value < head.value:
head.value, head.left.value = head.left.value, head.value
head = head.left
else:
return
else:
if head.right.value < head.value:
head.value, head.right.value = head.right.value, head.value
head = head.right
else:
return
else:
return
def heap_sort(arr):
heap = Small_root_pile()
for i in arr:
heap.insert(i)
helplist = []
while heap.root != None:
helplist.append(heap.pop())
return helplist
# 桶排序(基数排序)
# 实际上就是从个位每一位进行排序
def bucket_sort(arr):
digit = 0
themax=max(arr)
while themax != 0:
digit += 1
themax=int(themax/10)
getDigitnum=lambda x,d:int(x/(10**(d-1))%10)
for d in range(1,digit+1):
bucket=[]
for i in range(10):
bucket.append([])
for i in range(len(arr)):
digitnum=getDigitnum(arr[i],d)
bucket[digitnum].append(arr[i])
arr=[]
for i in bucket:
for j in i:
arr.append(j)
return arr
'''
总结:
一、什么是稳定性:
同样值的个体之间,如果不要为排序而改变相对位置,这个排序就是稳定的,否则就是不稳定的.
2.稳定排序:
①冒泡排序: O(N^2) O(1)
1-2、2-3,依次比较交换确定最后一位的值
②插入排序: O(N^2) O(1)
依次确定0-0、0-1上面的排序,如果存在大小关系就交换
③归并排序: O(N*logN) O(N)
二分法递归再归并,在左右两个指针相同时先放入左边指针则稳定
④基数排序:
从个位数开始排序,直到最高位排完
3.不稳定排序:
①选择排序: O(N^2) O(1)
在列表中遍历把最小值放到前面去
②快速排序: O(N*logN) O(logN)
将数组先快排一次不断在左右两侧递归快排,当i指向的数<num时与小于范围外的第一个数交换,i和小于范围都+1。
当>num时,于大于范围外的第一个数做交换,大于范围+1
当==num时,i+1
③堆排序: O(N*logN) O(1)
先将数组变成大根堆,再把第一个和最后一个数做交换确定最大值,再将剩下的数组变成大根堆,重复以上
'''