常用的查找
什么是查找?
在一些数据元素中,通过一定的方法找出与给定关键字相同的数据元素的过程
列表查找(线性表查找)
从列表中查找指定的元素
输入:列表,待查找的元素
输出:元素下标(未找到时返回None或-1)
顺序查找(linear_search)
def linear_search(li, val):
for ind, v in enumerate(li):
if v == val:
return ind
else:
return None
二分查找(binary_search)
def binary_search(li, val):
left, right = 0, len(li)-1
while left <= right: # 候选区有值
mid = (left + right) // 2
if li[mid] == val:
return mid
elif li[mid] > val: # 查找的值在mid左侧
right = mid - 1
else: # 查找的值在mid右侧
left = mid + 1
else:
return None
------------------------------------------------------------华丽的分割线-----------------------------------------------------------
简单的排序算法
什么是排序?
将一组"无序"的记录序列调整为"有序"的记录序列.
常见的排序算法
- LowB 三人组
1,冒泡排序
2.选择排序
3,插入排序 - NB三人组
1,快速排序
2.堆排序
3.归并排序 - 其他排序
1.希尔排序
2.计数排序
3.基数排序
Low B三人组
1.冒泡排序
# 升序排序
def bubble_sort_up(li):
for i in range(len(li) - 1): # 第i趟
flag = False # 如果一趟循环里没有交换 证明列表已经有序
for j in range(len(li) - i - 1): # 键头
if li[j] > li[j + 1]:
li[j], li[j + 1] = li[j + 1], li[j]
flag = True
if not flag:
return
# 降序排序
def bubble_sort_down(li):
for i in range(len(li) - 1): # 第i趟
flag = False
for j in range(len(li) - i - 1):
if li[j] < li[j + 1]:
li[j], li[j + 1] = li[j + 1], li[j]
flag = True
if not flag:
return
2.选择排序
# 选择排序
def select_sort_simple(li): # 简单 不推荐
li_new = []
for i in range(len(li)):
min_val = min(li)
li_new.append(min_val)
li_new.remove(min_val)
return li_new
def select_sort(li):
for i in range(len(li) - 1): # 第i趟
min_loc = i # 假设 无序区第i个位置是最小
for j in range(i + 1, len(li)):
if li[j] < li[min_loc]:
min_loc = j
li[i], li[min_loc] = li[min_loc], li[i]
3.插入排序
把拆入排序想象成打扑克牌时抓牌的过程,从小到大进行插入
# 插入排序
def insert_sort(li):
for i in range(1, len(li)): # 摸到的牌
temp = li[i]
j = i - 1 # 手里的牌的下标
while j >= 0 and li[j] > temp:
li[j + 1] = li[j]
j -= 1
li[j + 1] = temp
NB三人组
1.快速排序
# 快速排序
def partition(li, left, right):
temp = li[left]
while left < right:
while left < right and li[right] >= temp: # 从右边找比temp小的数
right -= 1 # 右游标向左移动
li[left] = li[right]
while left < right and li[left] <= temp: # 从左边找比temp小的数
left += 1 # 左游标向右移动
li[right] = li[left]
li[left] = temp # 把temp归位
return left
def quick_sort(li, left, right):
if left < right: # 至少有两个元素
mid = partition(li, left, right)
quick_sort(li, left, mid - 1)
quick_sort(li, mid + 1, right)
2.堆排序
# 堆排序
def sift(li, low, high):
"""
:param li: 列表
:param low: 根节点位置
:param high:堆的最后一个元素位置
:return:
"""
i = low # i指向最开始的根节点
j = 2 * i + 1 # 左孩子位置
temp = li[low] # 把堆顶存起来
while j <= high: # j的位置有数
if j + 1 < high and li[j] < li[j + 1]: # 右孩子存在并且比较大
j = j + 1 # 指向右孩子
if li[j] > temp:
li[i] = li[j]
i = j # 向下移动指针
j = 2 * i + 1
else: # temp更大,放在i的位置
li[i] = temp
break
else:
li[i] = temp # 把temp放到叶子节点上
def heap_sort(li):
n = len(li)
for i in range((n - 2) // 2, -1, -1):
# 将i指向最后一个位置
sift(li, i, n - 1)
# 建堆完成了
for i in range(n - 1, -1, -1):
li[0], li[i] = li[i], li[0]
sift(li, 0, i - 1) # i-1是新的high
3.归并排序
# 归并排序
# mid两边有序时使用
def merge(li, low, mid, high):
i = low
j = mid + 1
ltemp = []
while i <= mid and j <= high: # 两边都有数
if li[i] > li[j]:
ltemp.append(li[j])
j += 1
else: # li[j] > li[i]
ltemp.append(li[i])
i += 1
while i <= mid:
ltemp.append(li[i])
i += 1
while j <= high:
ltemp.append(li[j])
j += 1
li[low:high + 1] = ltemp
def merge_sort(li, low, high):
if low < high: # 至少两个数
mid = (low + high) // 2
# 左边排序
merge_sort(li, low, mid)
# 右边排序
merge_sort(li, mid + 1, high)
merge(li, low, mid, high)
其它排序
1.希尔排序
# 希尔排序
def insert_sort_gap(li, gap):
for i in range(gap, len(li)):
temp = li[i]
j = i - gap
while j >= 0 and li[j] > temp:
li[j + gap] = li[i]
j -= gap
li[j + gap] = temp
def shell_sort(li):
d = len(li) // 2
while d >= 1:
insert_sort_gap(li, d)
d // 2
2.计数排序
# 计数排序
def count_sort(li, max_count=100):
count = [0 for _ in range(max_count + 1)]
for val in li:
count[val] += 1
li.clear()
for index, value in enumerate(count):
for i in range(value):
li.append(index)
3.桶排序
# 桶排序
def bucket_sort(li, n=100, max_num=10000):
"""
:param li:
:param n: 分成多少给桶
:param max_num: 范围
:return:
"""
bucket = [[] for _ in range(n)] # 创建n给桶
for var in li:
i = min(var // (max_num // n), n - 1) # i表示 var放到几号桶里
bucket[i].append(var) # 把var加到桶里
# 保持桶内顺序
for j in range(bucket[i] - 1, 0, -1):
if bucket[i][j] < bucket[i][j - 1]:
bucket[i][j], bucket[i][j - 1] = bucket[i][j - 1], bucket[i][j]
else:
break
sorted_li = []
for buc in bucket:
sorted_li.extend(buc)
return sorted_li
4.基数排序
# 基数排序
def radix_sort(li):
max_num = max(li)
it = 0
while 10 ** it <= max_num:
buckets = [[] for _ in range(10)]
for var in li:
digit = (var // 10 ** it) % 10
buckets[digit].append(var)
# 分桶完成
li.clear()
for buc in buckets:
li.extend(buc) # 把数重新写回li
it += 1
总结
1.LowB三人组
- 三种算法的时间复杂度都是O(n2)
- 在数据规模较小时,直接插入排序,简单选择排序差不多。
当数据较大时,冒泡排序算法的时间代价最高。性能为O(n^2)的算法基
本上是相邻元素进行比较,基本上都是稳定的。
2.NB三人组
- .三种算法的时间复杂度都是O(nlogn)
- 一般情况下就运行时间来说: 快速排序 < 归并排序 < 堆排序
- 三种算法的缺点:
- 快速排序: 极端情况下排序效率较低
- 归并排序: 需要额外的内存开销
- 堆排序: 在快的排序算法来说相对较慢
-----------------------------------------------------------------------------------------------------------------------------------
稳定:冒泡排序、插入排序、归并排序和基数排序
不稳定:选择排序、快速排序、希尔排序、堆排序