(1)时间频度:一个算法执行所消耗的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每一个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。
时间复杂度的基本计算规则:
(1)基本操作:只有常数项,认为其时间复杂度O(1)
(2)顺序结构:时间复杂度按加法进行计算
(3)循环结构:时间复杂度按照加法进行计算
(4)分支结构:时间复杂度取最大值
(5)判断一个算法的效率,旺旺只需要关注操作数量化的最高次项,其他次要项和常数项可以忽略。
(6)在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度。
一个程序的空间复杂度:运行完一个程序所需内存的大小。
程序执行时所需存储空间分为:
(1) 固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括:指令空间、数据空间(常量、简单变量)等所占的空间。
(2)可变空间,这部分空间主要包括动态分配的空间,以及递归栈所需的空间等。这部分空间的大小与算法有关。
(Sorting algorithm)是一种能将一串数据依照特定顺序进行排列的一种算法
排序算法的稳定性:稳定排序算法会让原本有相等键值的记录维持相对次序。
原理:
(1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
(2)对每一对相邻元素作同样的工作,从第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
(3)针对是所有元素重复以上的步骤,除最后一个
(3)储蓄每次对越来越少的元素重复上面的步骤直到没有任何一堆数字需要比较
#冒泡排序
#基础版
def bubble_sort(alist):
n = len(alist)
for j in range(n-1):
for i in range(n-1-j):
if alist[i] > alist[i+1]:
alist[i], alist[i+1] = alist[i+1], alist[i]
lista = [1,21,12,44,22,99,10,4,2,56]
print("原数组:", lista)
bubble_sort(lista)
print("排序后数组:", lista)
#进阶版
#检测一轮,查看是否进行交换,如果没有进行交换就说明列表为有序列表可以直接输出
def bubble_sort2(alist):
n = len(alist)
for j in range(n-1):
count = 0
for i in range(n-1-j):
if alist[i] > alist[i+1]:
alist[i], alist[i+1] = alist[i+1], alist[i]
count += 1
if count == 0:
break
通过一趟排序将要排序的数据分割为独立的两部分。假设要排序的列表是list,首先任取一个数据(通常选用列表的第一个数)作为基准数据,然后将所有比它小的数都放在它的左边,所有比它大的数放在右边。
步骤:
(1)设置两个变量low、high排序开始的时候:low =0,high = N-1
(2)以第一个列表元素作为基准数据,赋值给mid,即mid = A[0]
(3)从high开始向前搜索,即由后开始向前搜索(high- -),找到第一个小于mid的值A[high],将A[hight]和A[low]的值交换;
(4)从low开始向后搜索,即由前开始向后搜索(low++),找到第一一个大于mid的A[low],将A[hight]和A[low]的值交换;
def quick_sort(alist, start, end):
mid = alist[start]
low = start
high = end
#退出条件
if start >= end:
return
while low < high:
# 从右往左
while alist[high] >= mid and high > low:
high -= 1
alist[low] = alist[high]
# 从左往右
while alist[low] < mid and high > low:
low += 1
alist[high] = alist[low]
alist[low] = mid
quick_sort(alist, start, low-1)
if low+1 <= end:
quick_sort(alist, low+1, end)
原理:
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,序贩毒把已排序元素逐步向后挪位。
#插入排序
def insertion_sort(alist):
n = len(alist)
for j in range(1, n-1):
i = j
while i > 0:
if alist[i] < alist[i-1]:
alist[i], alist[i-1] = alist[i-1], alist[i]
else:
break
i -= 1
def insertion_sort2(alist):
n = len(alist)
for j in range(1, n):
for i in range(j, -1, -1):
if alist[i] < alist[i-1]:
alist[i], alist[i-1] = alist[i-1], alist[i]
else:
break
i -= 1
简单插入排序的改进版。
原理:
先将整个待排序的序列分割为若干个子序列进行直接插入排序
然后缩小增量为上个增量的一半:2,继续划分分组,此时,每个分组元素个数多了,但是,数组变的部分有序了,插入排序效率同样比高
def shell_sort(alist):
n = len(alist)
mid = n//2
while mid > 0:
for i in range(mid, n):
while i >= mid and alist[i - mid] > alist[i]:
alist[i], alist[i - mid] = alist[i - mid], alist[i]
mid //= 2
原理:
首先在为排序的序列中找到最大(小)元素,存放在排序列表的起始位置,然后在剩余未拍戏元素中继续寻找最大(小)元素,然后放到已排序序列的末尾。
#选择排序
def selection_sort(alist):
n = len(alist)
for j in range(n-1):
min_index = j
for i in range(j, n-1):
if alist[min_index] > alist[i+1]:
min_index = i+1
if min_index != j:
alist[j], alist[min_index] = alist[min_index], alist[j]
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
import random
def heapify(arr, n, i):
largest = i
l = 2 * i + 1 # left = 2*i + 1
r = 2 * i + 2 # right = 2*i + 2
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i] # 交换
heapify(arr, n, largest)
def heapSort(arr):
n = len(arr)
# Build a maxheap.
for i in range(n, -1, -1):
heapify(arr, n, i)
# 一个个交换元素
for i in range(n - 1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # 交换
heapify(arr, i, 0)
lst = []
for i in range(10):
lst.append(random.randint(1,300))
heapSort(lst)
print(lst)
思想:先递归分解数组,再合并数据。
将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
#归并算法
def merg_sort(alist):
#分解
n = len(alist)
mid = n//2
if n <= 1:
return alist
left_li = merg_sort(alist[0:mid])
right_li = merg_sort(alist[mid:])
#合并
result = []
left_pointer, right_pointer = 0, 0
while left_pointer < len(left_li) and right_pointer < len(right_li):
if left_li[left_pointer] < right_li[right_pointer]:
result.append(left_li[left_pointer])
left_pointer += 1
else:
result.append(right_li[right_pointer])
right_pointer += 1
result.extend(left_li[left_pointer:])
result += right_li[right_pointer:]
return result
原理:
def counting_sort(alist):
minVal = min(alist)
maxVal = max(alist)
temp = [0]*(maxVal-minVal+1)
offset = minVal
for number in alist:
temp[number-offset] += 1
i = 0
for index in range(len(temp)):
for k in range(temp[index]):
alist[i] = index + offset
i += 1
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。
原理:
import random
def bucket_sort(array,n):
# 1.创建n个空桶
new_list = [[] for _ in range(n)]
maxVal = max(array)
level = maxVal//n
for num in array:
print(num)
for k in range(0,n):
if level*k <= num < level * (k+1):
new_list[k].append(num)
if num >= level*n:
new_list[n-1].append(num)
print(new_list)
# 2.把arr[i] 插入到bucket[n*array[i]]
# 3.桶内排序
for i in range(n):
new_list[i].sort()
print(new_list)
# 4.产生新的排序后的列表
index = 0
for i in range(n):
for j in range(len(new_list[i])):
array[index] = new_list[i][j]
index += 1
new_list[i].clear()
lst = []
for i in range(10):
lst.append(random.randint(1,300))
bucket_sort(lst,5)
print(lst)
原理:
import random
def getindex(num,r):
if len(str(num)) < r:
return 0
return int(str(num)[-r])
def radixSort(alist):
radix = len(str(max(alist)))
#创建十个二维空数组
temp = [[] for i in range(10)]
for i in range(1, radix+1):
#放入
for num in alist:
temp[getindex(num, i)].append(num)
#取出
a = 0
for k in range(len(temp)):
if len(temp)!=0:
for j in range(len(temp[k])):
alist[a] = temp[k][j]
a += 1
temp[k].clear()
lst = []
for i in range(10):
lst.append(random.randint(1,300))
radixSort(lst)
print(lst)